2011-04-11 04:21:16 +00:00
< ? php
2017-11-16 18:24:59 +00:00
/**
2021-03-29 06:40:20 +00:00
* @ copyright Copyright ( C ) 2010 - 2021 , the Friendica project
2020-02-09 15:18:46 +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 />.
*
2017-11-16 18:24:59 +00:00
*/
2018-01-25 02:08:45 +00:00
2017-04-30 04:07:00 +00:00
use Friendica\App ;
2018-01-10 03:42:04 +00:00
use Friendica\Content\ContactSelector ;
2017-12-04 14:04:36 +00:00
use Friendica\Content\Feature ;
2018-12-26 06:06:24 +00:00
use Friendica\Core\Hook ;
2018-10-29 21:20:46 +00:00
use Friendica\Core\Logger ;
2018-08-11 20:40:44 +00:00
use Friendica\Core\Protocol ;
2018-10-31 14:35:50 +00:00
use Friendica\Core\Renderer ;
2019-05-26 20:15:38 +00:00
use Friendica\Core\Session ;
2020-09-03 14:03:36 +00:00
use Friendica\Core\Theme ;
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-08 04:33:36 +00:00
use Friendica\Model\Contact ;
2018-06-10 07:26:37 +00:00
use Friendica\Model\Item ;
2021-01-16 04:11:28 +00:00
use Friendica\Model\Post ;
2020-04-26 15:24:58 +00:00
use Friendica\Model\Tag ;
2020-05-26 05:18:50 +00:00
use Friendica\Model\Verb ;
2021-01-16 12:35:44 +00:00
use Friendica\Object\Post as PostObject ;
2018-01-25 02:08:45 +00:00
use Friendica\Object\Thread ;
2019-10-23 00:05:11 +00:00
use Friendica\Protocol\Activity ;
2019-10-24 22:10:20 +00:00
use Friendica\Util\Crypto ;
2018-01-27 02:38:34 +00:00
use Friendica\Util\DateTimeFormat ;
2021-06-29 20:26:58 +00:00
use Friendica\Util\Proxy ;
2018-11-08 15:14:37 +00:00
use Friendica\Util\Strings ;
2019-10-24 22:10:20 +00:00
use Friendica\Util\Temporal ;
2018-02-03 17:25:58 +00:00
use Friendica\Util\XML ;
2017-04-30 04:07:00 +00:00
2011-04-18 15:37:02 +00:00
/**
* Render actions localized
2019-01-07 15:24:06 +00:00
*
* @ param $item
* @ throws ImagickException
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2011-04-18 15:37:02 +00:00
*/
2018-06-19 19:06:17 +00:00
function localize_item ( & $item )
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2021-02-21 19:38:53 +00:00
/// @todo The following functionality needs to be cleaned up.
2020-04-04 20:00:40 +00:00
if ( ! empty ( $item [ 'verb' ])) {
$activity = DI :: activity ();
2020-04-05 17:25:36 +00:00
$xmlhead = " < " . " ?xml version='1.0' encoding='UTF-8' ? " . " > " ;
2020-04-04 20:00:40 +00:00
if ( stristr ( $item [ 'verb' ], Activity :: POKE )) {
2020-04-05 07:08:20 +00:00
$verb = urldecode ( substr ( $item [ 'verb' ], strpos ( $item [ 'verb' ], '#' ) + 1 ));
2020-04-04 20:00:40 +00:00
if ( ! $verb ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2020-04-04 20:00:40 +00:00
return ;
}
2020-04-05 07:08:20 +00:00
if ( $item [ 'object-type' ] == " " || $item [ 'object-type' ] !== Activity\ObjectType :: PERSON ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2020-04-04 20:00:40 +00:00
return ;
2012-09-10 08:36:30 +00:00
}
2020-04-05 07:08:20 +00:00
$obj = XML :: parseString ( $xmlhead . $item [ 'object' ]);
2012-09-10 08:36:30 +00:00
2020-04-04 20:00:40 +00:00
$Bname = $obj -> title ;
$Blink = $obj -> id ;
$Bphoto = " " ;
2018-08-29 13:00:01 +00:00
2020-04-04 20:00:40 +00:00
foreach ( $obj -> link as $l ) {
$atts = $l -> attributes ();
switch ( $atts [ 'rel' ]) {
case " alternate " : $Blink = $atts [ 'href' ];
case " photo " : $Bphoto = $atts [ 'href' ];
}
2012-09-10 08:36:30 +00:00
}
2021-02-17 18:59:19 +00:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
$A = '[url=' . Contact :: magicLinkByContact ( $author ) . ']' . $item [ 'author-name' ] . '[/url]' ;
if ( ! empty ( $Blink )) {
$B = '[url=' . Contact :: magicLink ( $Blink ) . ']' . $Bname . '[/url]' ;
} else {
$B = '' ;
}
if ( $Bphoto != " " && ! empty ( $Blink )) {
2020-04-04 20:00:40 +00:00
$Bphoto = '[url=' . Contact :: magicLink ( $Blink ) . '][img=80x80]' . $Bphoto . '[/img][/url]' ;
}
2015-10-04 19:17:28 +00:00
2020-04-04 20:00:40 +00:00
/*
* we can ' t have a translation string with three positions but no distinguishable text
* So here is the translate string .
*/
$txt = DI :: l10n () -> t ( '%1$s poked %2$s' );
2012-09-10 08:36:30 +00:00
2020-04-04 20:00:40 +00:00
// now translate the verb
2020-04-05 07:11:47 +00:00
$poked_t = trim ( sprintf ( $txt , '' , '' ));
2020-04-04 20:00:40 +00:00
$txt = str_replace ( $poked_t , DI :: l10n () -> t ( $verb ), $txt );
2012-09-10 08:36:30 +00:00
2020-04-04 20:00:40 +00:00
// then do the sprintf on the translation string
2012-09-10 08:36:30 +00:00
2020-04-05 07:11:47 +00:00
$item [ 'body' ] = sprintf ( $txt , $A , $B ) . " \n \n \n " . $Bphoto ;
2012-09-10 08:36:30 +00:00
2017-04-08 18:00:54 +00:00
}
2020-04-05 07:08:20 +00:00
if ( $activity -> match ( $item [ 'verb' ], Activity :: TAG )) {
2020-04-04 20:00:40 +00:00
$fields = [ 'author-id' , 'author-link' , 'author-name' , 'author-network' ,
'verb' , 'object-type' , 'resource-id' , 'body' , 'plink' ];
2021-01-16 04:11:28 +00:00
$obj = Post :: selectFirst ( $fields , [ 'uri' => $item [ 'parent-uri' ]]);
2020-04-04 20:00:40 +00:00
if ( ! DBA :: isResult ( $obj )) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2020-04-04 20:00:40 +00:00
return ;
}
2012-09-10 08:36:30 +00:00
2020-04-04 20:00:40 +00:00
$author_arr = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
$author = '[url=' . Contact :: magicLinkByContact ( $author_arr ) . ']' . $item [ 'author-name' ] . '[/url]' ;
$author_arr = [ 'uid' => 0 , 'id' => $obj [ 'author-id' ],
'network' => $obj [ 'author-network' ], 'url' => $obj [ 'author-link' ]];
$objauthor = '[url=' . Contact :: magicLinkByContact ( $author_arr ) . ']' . $obj [ 'author-name' ] . '[/url]' ;
switch ( $obj [ 'verb' ]) {
case Activity :: POST :
switch ( $obj [ 'object-type' ]) {
case Activity\ObjectType :: EVENT :
$post_type = DI :: l10n () -> t ( 'event' );
break ;
default :
$post_type = DI :: l10n () -> t ( 'status' );
}
break ;
default :
if ( $obj [ 'resource-id' ]) {
$post_type = DI :: l10n () -> t ( 'photo' );
$m = []; preg_match ( " / \ [url=([^]]*) \ ]/ " , $obj [ 'body' ], $m );
$rr [ 'plink' ] = $m [ 1 ];
} else {
$post_type = DI :: l10n () -> t ( 'status' );
}
// Let's break everthing ... ;-)
break ;
}
$plink = '[url=' . $obj [ 'plink' ] . ']' . $post_type . '[/url]' ;
2012-09-10 08:36:30 +00:00
2020-04-05 17:25:36 +00:00
$parsedobj = XML :: parseString ( $xmlhead . $item [ 'object' ]);
2012-09-10 08:36:30 +00:00
2020-04-04 20:00:40 +00:00
$tag = sprintf ( '#[url=%s]%s[/url]' , $parsedobj -> id , $parsedobj -> content );
$item [ 'body' ] = DI :: l10n () -> t ( '%1$s tagged %2$s\'s %3$s with %4$s' , $author , $objauthor , $plink , $tag );
2012-09-10 08:36:30 +00:00
}
}
2020-04-04 20:00:40 +00:00
2012-09-10 08:36:30 +00:00
$matches = null ;
2017-04-08 18:00:54 +00:00
if ( preg_match_all ( '/@\[url=(.*?)\]/is' , $item [ 'body' ], $matches , PREG_SET_ORDER )) {
2017-04-04 17:46:56 +00:00
foreach ( $matches as $mtch ) {
2018-02-27 09:29:11 +00:00
if ( ! strpos ( $mtch [ 1 ], 'zrl=' )) {
2018-06-02 08:05:06 +00:00
$item [ 'body' ] = str_replace ( $mtch [ 0 ], '@[url=' . Contact :: magicLink ( $mtch [ 1 ]) . ']' , $item [ 'body' ]);
2017-04-08 18:00:54 +00:00
}
2012-09-10 08:36:30 +00:00
}
}
// add sparkle links to appropriate permalinks
2018-10-21 20:23:08 +00:00
// Only create a redirection to a magic link when logged in
2019-09-28 18:09:11 +00:00
if ( ! empty ( $item [ 'plink' ]) && Session :: isAuthenticated ()) {
2021-02-17 18:59:19 +00:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
2019-02-22 02:29:22 +00:00
$item [ 'plink' ] = Contact :: magicLinkByContact ( $author , $item [ 'plink' ]);
2018-07-10 12:27:56 +00:00
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2011-04-18 15:37:02 +00:00
}
2012-08-07 07:53:53 +00:00
/**
* Count the total of comments on this item and its desendants
2017-04-08 18:00:54 +00:00
* @ TODO proper type - hint + doc - tag
2019-01-07 15:24:06 +00:00
* @ param $item
* @ return int
2012-08-07 07:53:53 +00:00
*/
function count_descendants ( $item ) {
2012-09-10 08:36:30 +00:00
$total = count ( $item [ 'children' ]);
2017-04-04 17:46:56 +00:00
if ( $total > 0 ) {
foreach ( $item [ 'children' ] as $child ) {
2018-02-27 09:29:11 +00:00
if ( ! visible_activity ( $child )) {
2012-09-10 08:36:30 +00:00
$total -- ;
2017-04-08 18:03:21 +00:00
}
2012-09-10 08:36:30 +00:00
$total += count_descendants ( $child );
}
}
return $total ;
2012-08-07 07:53:53 +00:00
}
2012-09-19 03:12:55 +00:00
function visible_activity ( $item ) {
2019-12-15 22:28:01 +00:00
$activity = DI :: activity ();
2019-10-23 00:05:11 +00:00
2019-11-18 06:39:56 +00:00
if ( empty ( $item [ 'verb' ]) || $activity -> isHidden ( $item [ 'verb' ])) {
2019-10-23 22:25:43 +00:00
return false ;
2015-05-31 23:23:04 +00:00
}
2012-09-19 03:12:55 +00:00
2018-05-14 20:25:39 +00:00
// @TODO below if() block can be rewritten to a single line: $isVisible = allConditionsHere;
2019-10-23 22:25:43 +00:00
if ( $activity -> match ( $item [ 'verb' ], Activity :: FOLLOW ) &&
2019-10-24 22:10:20 +00:00
$item [ 'object-type' ] === Activity\ObjectType :: NOTE &&
2019-10-23 22:25:43 +00:00
empty ( $item [ 'self' ]) &&
$item [ 'uid' ] == local_user ()) {
2018-05-13 14:58:40 +00:00
return false ;
2012-09-28 02:53:55 +00:00
}
2012-09-19 03:12:55 +00:00
return true ;
}
2018-08-10 04:27:52 +00:00
function conv_get_blocklist ()
{
if ( ! local_user ()) {
return [];
}
2020-07-19 01:21:15 +00:00
$str_blocked = str_replace ([ " \n " , " \r " ], " , " , DI :: pConfig () -> get ( local_user (), 'system' , 'blocked' ));
2018-08-10 04:27:52 +00:00
if ( empty ( $str_blocked )) {
return [];
}
$blocklist = [];
foreach ( explode ( ',' , $str_blocked ) as $entry ) {
2020-12-11 14:16:29 +00:00
$cid = Contact :: getIdForURL ( trim ( $entry ), 0 , false );
2018-08-10 04:27:52 +00:00
if ( ! empty ( $cid )) {
$blocklist [] = $cid ;
}
}
return $blocklist ;
}
2011-04-13 00:58:16 +00:00
/**
* " Render " a conversation or list of items for HTML display .
* There are two major forms of display :
* - Sequential or unthreaded ( " New Item View " or search results )
* - conversation view
* The $mode parameter decides between the various renderings and also
2012-09-10 07:19:08 +00:00
* figures out how to determine page owner and other contextual items
2011-04-13 00:58:16 +00:00
* that are based on unique features of the calling module .
2019-01-07 15:24:06 +00:00
* @ param App $a
* @ param array $items
* @ param $mode
* @ param $update
* @ param bool $preview
* @ param string $order
* @ param int $uid
* @ return string
* @ throws ImagickException
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2011-04-13 00:58:16 +00:00
*/
2020-02-14 04:40:00 +00:00
function conversation ( App $a , array $items , $mode , $update , $preview = false , $order = 'commented' , $uid = 0 )
2018-10-24 06:15:24 +00:00
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2020-09-03 14:03:36 +00:00
$page = DI :: page ();
$page -> registerFooterScript ( Theme :: getPathForFile ( 'asset/typeahead.js/dist/typeahead.bundle.js' ));
$page -> registerFooterScript ( Theme :: getPathForFile ( 'js/friendica-tagsinput/friendica-tagsinput.js' ));
$page -> registerStylesheet ( Theme :: getPathForFile ( 'js/friendica-tagsinput/friendica-tagsinput.css' ));
$page -> registerStylesheet ( Theme :: getPathForFile ( 'js/friendica-tagsinput/friendica-tagsinput-typeahead.css' ));
2018-08-10 04:27:52 +00:00
$ssl_state = ( local_user () ? true : false );
2012-09-10 07:19:08 +00:00
2012-10-09 15:41:33 +00:00
$live_update_div = '' ;
2012-09-10 07:19:08 +00:00
2018-08-10 04:27:52 +00:00
$blocklist = conv_get_blocklist ();
2013-04-29 04:02:53 +00:00
2012-09-10 08:36:30 +00:00
$previewing = (( $preview ) ? ' preview ' : '' );
2012-09-10 07:19:08 +00:00
2017-04-04 17:46:56 +00:00
if ( $mode === 'network' ) {
2018-05-26 18:07:27 +00:00
$items = conversation_add_children ( $items , false , $order , $uid );
2017-04-04 17:46:56 +00:00
if ( ! $update ) {
2017-04-08 17:05:50 +00:00
/*
* The special div is needed for liveUpdate to kick in for this page .
* We only launch liveUpdate if you aren ' t filtering in some incompatible
* way and also you aren ' t writing a comment ( discovered in javascript ) .
*/
2012-10-09 15:41:33 +00:00
$live_update_div = '<div id="live-network"></div>' . " \r \n "
2015-10-07 22:25:55 +00:00
. " <script> var profile_uid = " . $_SESSION [ 'uid' ]
2019-12-16 00:33:13 +00:00
. " ; var netargs = ' " . substr ( DI :: args () -> getCommand (), 8 )
2012-10-09 15:41:33 +00:00
. '?f='
2020-05-17 15:01:27 +00:00
. ( ! empty ( $_GET [ 'contactid' ]) ? '&contactid=' . rawurlencode ( $_GET [ 'contactid' ]) : '' )
. ( ! empty ( $_GET [ 'search' ]) ? '&search=' . rawurlencode ( $_GET [ 'search' ]) : '' )
. ( ! empty ( $_GET [ 'star' ]) ? '&star=' . rawurlencode ( $_GET [ 'star' ]) : '' )
. ( ! empty ( $_GET [ 'order' ]) ? '&order=' . rawurlencode ( $_GET [ 'order' ]) : '' )
. ( ! empty ( $_GET [ 'bmark' ]) ? '&bmark=' . rawurlencode ( $_GET [ 'bmark' ]) : '' )
. ( ! empty ( $_GET [ 'liked' ]) ? '&liked=' . rawurlencode ( $_GET [ 'liked' ]) : '' )
. ( ! empty ( $_GET [ 'conv' ]) ? '&conv=' . rawurlencode ( $_GET [ 'conv' ]) : '' )
. ( ! empty ( $_GET [ 'nets' ]) ? '&nets=' . rawurlencode ( $_GET [ 'nets' ]) : '' )
. ( ! empty ( $_GET [ 'cmin' ]) ? '&cmin=' . rawurlencode ( $_GET [ 'cmin' ]) : '' )
. ( ! empty ( $_GET [ 'cmax' ]) ? '&cmax=' . rawurlencode ( $_GET [ 'cmax' ]) : '' )
. ( ! empty ( $_GET [ 'file' ]) ? '&file=' . rawurlencode ( $_GET [ 'file' ]) : '' )
2012-10-09 15:41:33 +00:00
2020-02-14 04:40:00 +00:00
. " '; </script> \r \n " ;
2012-10-09 15:41:33 +00:00
}
2017-04-08 17:05:50 +00:00
} elseif ( $mode === 'profile' ) {
2018-08-20 04:26:05 +00:00
$items = conversation_add_children ( $items , false , $order , $uid );
2012-09-10 07:19:08 +00:00
2017-04-04 17:46:56 +00:00
if ( ! $update ) {
2018-01-01 20:27:33 +00:00
$tab = 'posts' ;
2018-11-30 14:06:22 +00:00
if ( ! empty ( $_GET [ 'tab' ])) {
2018-11-09 18:29:42 +00:00
$tab = Strings :: escapeTags ( trim ( $_GET [ 'tab' ]));
2018-01-01 20:27:33 +00:00
}
2017-04-04 17:46:56 +00:00
if ( $tab === 'posts' ) {
2017-04-08 17:05:50 +00:00
/*
* This is ugly , but we can ' t pass the profile_uid through the session to the ajax updater ,
* because browser prefetching might change it on us . We have to deliver it with the page .
*/
2012-10-09 15:41:33 +00:00
$live_update_div = '<div id="live-profile"></div>' . " \r \n "
2021-07-23 12:39:37 +00:00
. " <script> var profile_uid = " . $uid
2020-02-14 04:40:00 +00:00
. " ; var netargs = '?f='; </script> \r \n " ;
2012-10-09 15:41:33 +00:00
}
}
2017-04-08 17:05:50 +00:00
} elseif ( $mode === 'notes' ) {
2018-12-13 20:09:19 +00:00
$items = conversation_add_children ( $items , false , $order , local_user ());
2018-07-31 02:06:22 +00:00
2017-04-04 17:46:56 +00:00
if ( ! $update ) {
2012-10-09 15:41:33 +00:00
$live_update_div = '<div id="live-notes"></div>' . " \r \n "
2015-10-07 22:25:55 +00:00
. " <script> var profile_uid = " . local_user ()
2020-02-14 04:40:00 +00:00
. " ; var netargs = '/?f='; </script> \r \n " ;
2012-10-09 15:41:33 +00:00
}
2017-04-08 17:05:50 +00:00
} elseif ( $mode === 'display' ) {
2018-08-20 20:32:55 +00:00
$items = conversation_add_children ( $items , false , $order , $uid );
2018-07-31 02:06:22 +00:00
2017-04-04 17:46:56 +00:00
if ( ! $update ) {
2012-11-02 00:31:50 +00:00
$live_update_div = '<div id="live-display"></div>' . " \r \n "
2019-05-26 20:15:38 +00:00
. " <script> var profile_uid = " . Session :: get ( 'uid' , 0 ) . " ; "
2020-02-14 04:40:00 +00:00
. " </script> " ;
2012-11-02 00:31:50 +00:00
}
2017-04-08 17:05:50 +00:00
} elseif ( $mode === 'community' ) {
2018-05-26 20:03:30 +00:00
$items = conversation_add_children ( $items , true , $order , $uid );
2018-07-31 02:06:22 +00:00
2018-01-04 15:46:56 +00:00
if ( ! $update ) {
$live_update_div = '<div id="live-community"></div>' . " \r \n "
2019-12-16 00:33:13 +00:00
. " <script> var profile_uid = -1; var netargs = ' " . substr ( DI :: args () -> getCommand (), 10 )
2020-09-26 18:01:10 +00:00
. '?f='
. ( ! empty ( $_GET [ 'no_sharer' ]) ? '&no_sharer=' . rawurlencode ( $_GET [ 'no_sharer' ]) : '' )
. " '; </script> \r \n " ;
2018-01-04 15:46:56 +00:00
}
2018-08-25 13:48:00 +00:00
} elseif ( $mode === 'contacts' ) {
2018-11-25 18:50:41 +00:00
$items = conversation_add_children ( $items , false , $order , $uid );
2018-08-25 13:48:00 +00:00
if ( ! $update ) {
2020-10-06 18:47:23 +00:00
$live_update_div = '<div id="live-contact"></div>' . " \r \n "
. " <script> var profile_uid = -1; var netargs = ' " . substr ( DI :: args () -> getCommand (), 8 )
2020-02-14 04:40:00 +00:00
. " /?f='; </script> \r \n " ;
2018-08-25 13:48:00 +00:00
}
2017-04-08 17:05:50 +00:00
} elseif ( $mode === 'search' ) {
2012-10-09 15:41:33 +00:00
$live_update_div = '<div id="live-search"></div>' . " \r \n " ;
2012-09-10 08:36:30 +00:00
}
2012-09-10 07:19:08 +00:00
2021-07-23 12:39:37 +00:00
$page_dropping = (( local_user () && local_user () == $uid ) ? true : false );
2012-09-10 07:19:08 +00:00
2018-01-04 02:12:19 +00:00
if ( ! $update ) {
2019-12-16 00:30:34 +00:00
$_SESSION [ 'return_path' ] = DI :: args () -> getQueryString ();
2017-04-08 17:05:50 +00:00
}
2012-03-15 04:20:20 +00:00
2018-01-15 13:05:12 +00:00
$cb = [ 'items' => $items , 'mode' => $mode , 'update' => $update , 'preview' => $preview ];
2020-11-21 16:08:44 +00:00
Hook :: callAll ( 'conversation_start' , $cb );
2012-01-10 04:03:00 +00:00
2012-09-10 08:36:30 +00:00
$items = $cb [ 'items' ];
2011-04-11 06:01:38 +00:00
2018-01-15 13:05:12 +00:00
$conv_responses = [
2020-02-23 01:41:12 +00:00
'like' => [],
'dislike' => [],
'attendyes' => [],
'attendno' => [],
2020-02-26 20:53:46 +00:00
'attendmaybe' => [],
2021-02-21 19:38:53 +00:00
'announce' => [],
2018-01-15 13:05:12 +00:00
];
2011-05-20 08:15:02 +00:00
2020-02-20 03:20:26 +00:00
if ( DI :: pConfig () -> get ( local_user (), 'system' , 'hide_dislike' )) {
unset ( $conv_responses [ 'dislike' ]);
}
2012-09-10 08:36:30 +00:00
// array with html for each thread (parent+comments)
2018-01-15 13:05:12 +00:00
$threads = [];
2012-09-10 08:36:30 +00:00
$threadsid = - 1 ;
2011-07-05 04:52:21 +00:00
2018-10-31 14:44:06 +00:00
$page_template = Renderer :: getMarkupTemplate ( " conversation.tpl " );
2012-08-10 06:01:37 +00:00
2018-07-31 02:06:22 +00:00
if ( ! empty ( $items )) {
2018-08-25 13:48:00 +00:00
if ( in_array ( $mode , [ 'community' , 'contacts' ])) {
2018-01-31 23:22:41 +00:00
$writable = true ;
2017-12-20 10:16:25 +00:00
} else {
2019-07-01 18:00:55 +00:00
$writable = ( $items [ 0 ][ 'uid' ] == 0 ) && in_array ( $items [ 0 ][ 'network' ], Protocol :: FEDERATED );
2017-12-20 10:16:25 +00:00
}
2012-08-10 06:01:37 +00:00
2018-01-04 14:39:47 +00:00
if ( ! local_user ()) {
$writable = false ;
}
2020-10-13 04:23:17 +00:00
if ( in_array ( $mode , [ 'filed' , 'search' , 'contact-posts' ])) {
2011-04-11 06:01:38 +00:00
2017-04-08 18:00:54 +00:00
/*
* " New Item View " on network page or search page results
* - just loop through the items and format them minimally for display
*/
2011-04-11 04:21:16 +00:00
2012-09-10 08:36:30 +00:00
$tpl = 'search_item.tpl' ;
2017-04-04 17:46:56 +00:00
foreach ( $items as $item ) {
2014-01-05 15:22:42 +00:00
2018-02-27 09:29:11 +00:00
if ( ! visible_activity ( $item )) {
continue ;
}
2018-08-10 04:27:52 +00:00
if ( in_array ( $item [ 'author-id' ], $blocklist )) {
continue ;
2013-04-29 04:02:53 +00:00
}
2013-09-15 08:40:58 +00:00
2012-09-10 08:36:30 +00:00
$threadsid ++ ;
// prevent private email from leaking.
2018-08-11 20:40:44 +00:00
if ( $item [ 'network' ] === Protocol :: MAIL && local_user () != $item [ 'uid' ]) {
2017-04-08 17:05:50 +00:00
continue ;
}
2012-09-10 08:36:30 +00:00
2018-06-24 10:48:29 +00:00
$profile_name = $item [ 'author-name' ];
if ( ! empty ( $item [ 'author-link' ]) && empty ( $item [ 'author-name' ])) {
2012-09-10 08:36:30 +00:00
$profile_name = $item [ 'author-link' ];
2017-04-08 17:05:50 +00:00
}
2012-09-10 08:36:30 +00:00
2020-05-01 06:01:22 +00:00
$tags = Tag :: populateFromItem ( $item );
2013-01-13 16:13:01 +00:00
2018-07-02 05:41:55 +00:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
2019-02-22 02:29:22 +00:00
$profile_link = Contact :: magicLinkByContact ( $author );
2017-04-08 17:05:50 +00:00
2020-09-13 23:50:39 +00:00
$sparkle = '' ;
2018-06-01 06:46:34 +00:00
if ( strpos ( $profile_link , 'redir/' ) === 0 ) {
2012-09-10 08:36:30 +00:00
$sparkle = ' sparkle' ;
2017-04-08 17:05:50 +00:00
}
2012-09-10 08:36:30 +00:00
2018-01-15 13:05:12 +00:00
$locate = [ 'location' => $item [ 'location' ], 'coord' => $item [ 'coord' ], 'html' => '' ];
2020-11-21 16:08:44 +00:00
Hook :: callAll ( 'render_location' , $locate );
2020-09-13 23:33:57 +00:00
$location_html = $locate [ 'html' ] ? : Strings :: escapeHtml ( $locate [ 'location' ] ? : $locate [ 'coord' ] ? : '' );
2012-09-10 08:36:30 +00:00
localize_item ( $item );
2020-10-13 04:23:17 +00:00
if ( $mode === 'filed' ) {
2012-09-10 08:36:30 +00:00
$dropping = true ;
2017-04-08 17:05:50 +00:00
} else {
2012-09-10 08:36:30 +00:00
$dropping = false ;
2017-04-08 17:05:50 +00:00
}
2012-09-10 08:36:30 +00:00
2018-01-15 13:05:12 +00:00
$drop = [
2012-09-10 08:36:30 +00:00
'dropping' => $dropping ,
2012-09-26 02:10:46 +00:00
'pagedrop' => $page_dropping ,
2020-01-18 19:52:34 +00:00
'select' => DI :: l10n () -> t ( 'Select' ),
'delete' => DI :: l10n () -> t ( 'Delete' ),
2018-01-15 13:05:12 +00:00
];
2012-09-10 08:36:30 +00:00
2020-02-14 01:42:15 +00:00
$likebuttons = [
2020-10-11 08:49:47 +00:00
'like' => null ,
'dislike' => null ,
'share' => null ,
'announce' => null ,
2020-02-14 01:42:15 +00:00
];
2012-09-10 08:36:30 +00:00
2020-02-20 03:20:26 +00:00
if ( DI :: pConfig () -> get ( local_user (), 'system' , 'hide_dislike' )) {
unset ( $likebuttons [ 'dislike' ]);
}
2020-09-13 23:37:43 +00:00
$body_html = Item :: prepareBody ( $item , true , $preview );
2012-09-24 02:22:48 +00:00
2019-12-15 22:28:01 +00:00
list ( $categories , $folders ) = DI :: contentItem () -> determineCategoriesTerms ( $item );
2012-09-26 02:10:46 +00:00
2020-01-18 15:50:57 +00:00
if ( ! empty ( $item [ 'content-warning' ]) && DI :: pConfig () -> get ( local_user (), 'system' , 'disable_cw' , false )) {
2019-02-23 04:03:32 +00:00
$title = ucfirst ( $item [ 'content-warning' ]);
2018-04-05 02:50:39 +00:00
} else {
2019-02-23 04:03:32 +00:00
$title = $item [ 'title' ];
2018-04-05 02:50:39 +00:00
}
2018-01-15 13:05:12 +00:00
$tmp_item = [
2012-09-10 08:36:30 +00:00
'template' => $tpl ,
2018-07-10 12:27:56 +00:00
'id' => ( $preview ? 'P0' : $item [ 'id' ]),
'guid' => ( $preview ? 'Q0' : $item [ 'guid' ]),
2020-09-30 19:14:13 +00:00
'commented' => $item [ 'commented' ],
'received' => $item [ 'received' ],
'created_date' => $item [ 'created' ],
'uriid' => $item [ 'uri-id' ],
2018-06-18 20:36:34 +00:00
'network' => $item [ 'network' ],
2019-12-27 17:24:29 +00:00
'network_name' => ContactSelector :: networkToName ( $item [ 'author-network' ], $item [ 'author-link' ], $item [ 'network' ]),
2019-08-28 06:38:35 +00:00
'network_icon' => ContactSelector :: networkToIcon ( $item [ 'network' ], $item [ 'author-link' ]),
2020-01-18 19:52:34 +00:00
'linktitle' => DI :: l10n () -> t ( 'View %s\'s profile @ %s' , $profile_name , $item [ 'author-link' ]),
2012-09-10 08:36:30 +00:00
'profile_url' => $profile_link ,
2020-09-13 23:40:59 +00:00
'item_photo_menu_html' => item_photo_menu ( $item ),
2019-02-23 04:03:32 +00:00
'name' => $profile_name ,
2012-09-10 08:36:30 +00:00
'sparkle' => $sparkle ,
2020-09-13 23:50:39 +00:00
'lock' => false ,
2021-06-29 20:26:58 +00:00
'thumb' => DI :: baseUrl () -> remove ( Contact :: getAvatarUrlForUrl ( $item [ 'author-link' ], $item [ 'uid' ], Proxy :: SIZE_THUMB )),
2019-02-23 04:03:32 +00:00
'title' => $title ,
2020-09-13 23:37:43 +00:00
'body_html' => $body_html ,
2019-02-23 04:03:32 +00:00
'tags' => $tags [ 'tags' ],
'hashtags' => $tags [ 'hashtags' ],
'mentions' => $tags [ 'mentions' ],
'implicit_mentions' => $tags [ 'implicit_mentions' ],
2020-01-18 19:52:34 +00:00
'txt_cats' => DI :: l10n () -> t ( 'Categories:' ),
'txt_folders' => DI :: l10n () -> t ( 'Filed under:' ),
2012-09-24 00:16:37 +00:00
'has_cats' => (( count ( $categories )) ? 'true' : '' ),
'has_folders' => (( count ( $folders )) ? 'true' : '' ),
2012-09-19 15:38:32 +00:00
'categories' => $categories ,
'folders' => $folders ,
2020-09-13 23:37:43 +00:00
'text' => strip_tags ( $body_html ),
2018-01-27 02:38:34 +00:00
'localtime' => DateTimeFormat :: local ( $item [ 'created' ], 'r' ),
2020-11-21 16:08:44 +00:00
'ago' => (( $item [ 'app' ]) ? DI :: l10n () -> t ( '%s from %s' , Temporal :: getRelativeDate ( $item [ 'created' ]), $item [ 'app' ]) : Temporal :: getRelativeDate ( $item [ 'created' ])),
2020-09-13 23:33:57 +00:00
'location_html' => $location_html ,
2012-09-10 08:36:30 +00:00
'indent' => '' ,
2020-09-13 23:50:39 +00:00
'owner_name' => '' ,
'owner_url' => '' ,
2021-06-30 16:58:46 +00:00
'owner_photo' => DI :: baseUrl () -> remove ( Contact :: getAvatarUrlForUrl ( $item [ 'owner-link' ], $item [ 'uid' ], Proxy :: SIZE_THUMB )),
2018-11-07 12:19:39 +00:00
'plink' => Item :: getPlink ( $item ),
2012-09-10 08:36:30 +00:00
'edpost' => false ,
2020-09-13 23:50:39 +00:00
'isstarred' => 'unstarred' ,
'star' => false ,
2012-09-10 08:36:30 +00:00
'drop' => $drop ,
'vote' => $likebuttons ,
2020-09-13 23:44:11 +00:00
'like_html' => '' ,
'dislike_html' => '' ,
2020-09-13 23:43:42 +00:00
'comment_html' => '' ,
2020-01-18 19:52:34 +00:00
'conv' => (( $preview ) ? '' : [ 'href' => 'display/' . $item [ 'guid' ], 'title' => DI :: l10n () -> t ( 'View in context' )]),
2012-09-10 08:36:30 +00:00
'previewing' => $previewing ,
2020-01-18 19:52:34 +00:00
'wait' => DI :: l10n () -> t ( 'Please wait' ),
2012-09-10 08:36:30 +00:00
'thread_level' => 1 ,
2018-01-15 13:05:12 +00:00
];
2012-09-10 08:36:30 +00:00
2018-01-15 13:05:12 +00:00
$arr = [ 'item' => $item , 'output' => $tmp_item ];
2018-12-26 06:06:24 +00:00
Hook :: callAll ( 'display_item' , $arr );
2012-09-10 08:36:30 +00:00
2018-07-10 12:27:56 +00:00
$threads [ $threadsid ][ 'id' ] = $item [ 'id' ];
2018-06-18 20:36:34 +00:00
$threads [ $threadsid ][ 'network' ] = $item [ 'network' ];
2018-01-15 13:05:12 +00:00
$threads [ $threadsid ][ 'items' ] = [ $arr [ 'output' ]];
2012-09-10 08:36:30 +00:00
}
2017-04-08 17:05:50 +00:00
} else {
2012-09-10 08:36:30 +00:00
// Normal View
2018-10-31 14:44:06 +00:00
$page_template = Renderer :: getMarkupTemplate ( " threaded_conversation.tpl " );
2012-09-10 08:36:30 +00:00
2017-12-19 17:15:56 +00:00
$conv = new Thread ( $mode , $preview , $writable );
2012-09-10 08:36:30 +00:00
2017-04-08 17:05:50 +00:00
/*
* get all the topmost parents
* this shouldn ' t be needed , as we should have only them in our array
* But for now , this array respects the old style , just in case
*/
2017-04-04 17:46:56 +00:00
foreach ( $items as $item ) {
2018-08-10 04:27:52 +00:00
if ( in_array ( $item [ 'author-id' ], $blocklist )) {
continue ;
2013-04-29 04:02:53 +00:00
}
2013-09-15 08:40:58 +00:00
2012-09-10 08:36:30 +00:00
// Can we put this after the visibility check?
2015-06-03 18:57:30 +00:00
builtin_activity_puller ( $item , $conv_responses );
2012-09-10 08:36:30 +00:00
// Only add what is visible
2018-08-11 20:40:44 +00:00
if ( $item [ 'network' ] === Protocol :: MAIL && local_user () != $item [ 'uid' ]) {
2012-09-10 08:36:30 +00:00
continue ;
}
2017-04-08 17:05:50 +00:00
2018-02-27 09:29:11 +00:00
if ( ! visible_activity ( $item )) {
2012-09-10 08:36:30 +00:00
continue ;
}
2018-07-08 13:52:11 +00:00
/// @todo Check if this call is needed or not
2018-07-08 12:01:36 +00:00
$arr = [ 'item' => $item ];
2018-12-26 06:06:24 +00:00
Hook :: callAll ( 'display_item' , $arr );
2013-01-22 07:11:13 +00:00
2012-09-26 02:10:46 +00:00
$item [ 'pagedrop' ] = $page_dropping ;
2020-05-27 12:19:06 +00:00
if ( $item [ 'gravity' ] == GRAVITY_PARENT ) {
2021-01-16 12:35:44 +00:00
$item_object = new PostObject ( $item );
2017-12-08 04:33:36 +00:00
$conv -> addParent ( $item_object );
2012-09-10 08:36:30 +00:00
}
}
2017-11-19 19:15:25 +00:00
$threads = $conv -> getTemplateData ( $conv_responses );
2017-04-04 17:46:56 +00:00
if ( ! $threads ) {
2018-10-30 13:58:45 +00:00
Logger :: log ( '[ERROR] conversation : Failed to get template data.' , Logger :: DEBUG );
2018-01-15 13:05:12 +00:00
$threads = [];
2012-09-10 08:36:30 +00:00
}
}
}
2018-10-31 14:35:50 +00:00
$o = Renderer :: replaceMacros ( $page_template , [
2019-12-30 22:00:08 +00:00
'$baseurl' => DI :: baseUrl () -> get ( $ssl_state ),
2019-12-16 00:30:34 +00:00
'$return_path' => DI :: args () -> getQueryString (),
2012-10-09 15:41:33 +00:00
'$live_update' => $live_update_div ,
2020-01-18 19:52:34 +00:00
'$remove' => DI :: l10n () -> t ( 'remove' ),
2012-09-10 08:36:30 +00:00
'$mode' => $mode ,
2020-10-20 20:43:51 +00:00
'$update' => $update ,
2012-09-10 08:36:30 +00:00
'$threads' => $threads ,
2020-01-18 19:52:34 +00:00
'$dropping' => ( $page_dropping ? DI :: l10n () -> t ( 'Delete Selected Items' ) : False ),
2018-01-15 13:05:12 +00:00
]);
2012-09-10 08:36:30 +00:00
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2012-09-10 08:36:30 +00:00
return $o ;
2017-12-12 04:52:33 +00:00
}
2011-04-13 00:58:16 +00:00
2019-04-03 18:51:50 +00:00
/**
* Fetch all comments from a query . Additionally set the newest resharer as thread owner .
*
2020-01-26 19:14:36 +00:00
* @ param mixed $thread_items Database statement with thread posts
2019-11-08 06:52:44 +00:00
* @ param boolean $pinned Is the item pinned ?
2020-11-28 06:23:17 +00:00
* @ param array $activity Contact data of the resharer
2019-11-08 06:52:44 +00:00
*
2019-04-03 18:51:50 +00:00
* @ return array items with parents and comments
*/
2020-11-28 06:23:17 +00:00
function conversation_fetch_comments ( $thread_items , bool $pinned , array $activity ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2019-04-03 18:51:50 +00:00
$comments = [];
2021-01-16 22:37:27 +00:00
while ( $row = Post :: fetch ( $thread_items )) {
2020-11-28 06:23:17 +00:00
if ( ! empty ( $activity )) {
2020-11-03 19:24:47 +00:00
if (( $row [ 'gravity' ] == GRAVITY_PARENT )) {
2021-04-07 06:02:06 +00:00
$row [ 'post-reason' ] = Item :: PR_ANNOUNCEMENT ;
2020-11-28 06:23:17 +00:00
$row = array_merge ( $row , $activity );
2020-11-28 06:29:20 +00:00
$contact = Contact :: getById ( $activity [ 'causer-id' ], [ 'url' , 'name' , 'thumb' ]);
2020-11-03 19:24:47 +00:00
$row [ 'causer-link' ] = $contact [ 'url' ];
$row [ 'causer-avatar' ] = $contact [ 'thumb' ];
$row [ 'causer-name' ] = $contact [ 'name' ];
} elseif (( $row [ 'gravity' ] == GRAVITY_ACTIVITY ) && ( $row [ 'verb' ] == Activity :: ANNOUNCE ) &&
2020-11-28 06:23:17 +00:00
( $row [ 'author-id' ] == $activity [ 'causer-id' ])) {
2020-11-03 19:24:47 +00:00
continue ;
}
}
2021-04-07 06:02:06 +00:00
switch ( $row [ 'post-reason' ]) {
case Item :: PR_TO :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'to' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_CC :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'cc' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_BTO :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'bto' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_BCC :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'bcc' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_FOLLOWER :
2020-09-09 18:03:14 +00:00
$row [ 'direction' ] = [ 'direction' => 6 , 'title' => DI :: l10n () -> t ( 'You are following %s.' , $row [ 'author-name' ])];
2020-09-13 14:15:28 +00:00
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_TAG :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 4 , 'title' => DI :: l10n () -> t ( 'Tagged' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_ANNOUNCEMENT :
2020-09-30 17:30:26 +00:00
if ( ! empty ( $row [ 'causer-id' ]) && DI :: pConfig () -> get ( local_user (), 'system' , 'display_resharer' )) {
2020-11-10 19:43:12 +00:00
$row [ 'owner-id' ] = $row [ 'causer-id' ];
2020-09-22 05:36:01 +00:00
$row [ 'owner-link' ] = $row [ 'causer-link' ];
$row [ 'owner-avatar' ] = $row [ 'causer-avatar' ];
$row [ 'owner-name' ] = $row [ 'causer-name' ];
}
if (( $row [ 'gravity' ] == GRAVITY_PARENT ) && ! empty ( $row [ 'causer-id' ])) {
2021-02-17 18:59:19 +00:00
$causer = [ 'uid' => 0 , 'id' => $row [ 'causer-id' ],
'network' => $row [ 'causer-network' ], 'url' => $row [ 'causer-link' ]];
2021-05-29 19:47:19 +00:00
$row [ 'reshared' ] = DI :: l10n () -> t ( '%s reshared this.' , '<a href="' . htmlentities ( Contact :: magicLinkByContact ( $causer )) . '">' . htmlentities ( $row [ 'causer-name' ]) . '</a>' );
2020-09-22 05:36:01 +00:00
}
2021-05-29 19:47:19 +00:00
$row [ 'direction' ] = [ 'direction' => 3 , 'title' => ( empty ( $row [ 'causer-id' ]) ? DI :: l10n () -> t ( 'Reshared' ) : DI :: l10n () -> t ( 'Reshared by %s <%s>' , $row [ 'causer-name' ], $row [ 'causer-link' ]))];
2020-09-13 14:15:28 +00:00
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_COMMENT :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 5 , 'title' => DI :: l10n () -> t ( '%s is participating in this thread.' , $row [ 'author-name' ])];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_STORED :
2020-09-13 14:15:28 +00:00
$row [ 'direction' ] = [ 'direction' => 8 , 'title' => DI :: l10n () -> t ( 'Stored' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_GLOBAL :
2020-09-14 17:48:57 +00:00
$row [ 'direction' ] = [ 'direction' => 9 , 'title' => DI :: l10n () -> t ( 'Global' )];
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_RELAY :
2021-05-29 19:47:19 +00:00
$row [ 'direction' ] = [ 'direction' => 10 , 'title' => ( empty ( $row [ 'causer-id' ]) ? DI :: l10n () -> t ( 'Relayed' ) : DI :: l10n () -> t ( 'Relayed by %s <%s>' , $row [ 'causer-name' ], $row [ 'causer-link' ]))];
2020-09-21 12:31:20 +00:00
break ;
2021-04-07 06:02:06 +00:00
case Item :: PR_FETCHED :
2021-05-29 19:47:19 +00:00
$row [ 'direction' ] = [ 'direction' => 2 , 'title' => ( empty ( $row [ 'causer-id' ]) ? DI :: l10n () -> t ( 'Fetched' ) : DI :: l10n () -> t ( 'Fetched because of %s <%s>' , $row [ 'causer-name' ], $row [ 'causer-link' ]))];
2020-09-21 15:17:33 +00:00
break ;
}
2020-09-12 17:45:04 +00:00
2019-11-08 06:52:44 +00:00
if ( $row [ 'gravity' ] == GRAVITY_PARENT ) {
$row [ 'pinned' ] = $pinned ;
}
2019-04-03 18:51:50 +00:00
$comments [] = $row ;
}
DBA :: close ( $thread_items );
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2019-04-03 18:51:50 +00:00
return $comments ;
}
2018-01-04 10:02:56 +00:00
/**
2020-01-19 06:05:23 +00:00
* Add comments to top level entries that had been fetched before
2018-01-04 10:02:56 +00:00
*
* The system will fetch the comments for the local user whenever possible .
* This behaviour is currently needed to allow commenting on Friendica posts .
*
* @ param array $parents Parent items
*
2019-01-07 15:24:06 +00:00
* @ param $block_authors
* @ param $order
* @ param $uid
2018-01-04 10:02:56 +00:00
* @ return array items with parents and comments
2019-01-07 15:24:06 +00:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2018-01-04 10:02:56 +00:00
*/
2018-07-13 19:47:14 +00:00
function conversation_add_children ( array $parents , $block_authors , $order , $uid ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2020-06-16 06:49:53 +00:00
if ( count ( $parents ) > 1 ) {
$max_comments = DI :: config () -> get ( 'system' , 'max_comments' , 100 );
} else {
$max_comments = DI :: config () -> get ( 'system' , 'max_display_comments' , 1000 );
}
2018-02-26 22:15:57 +00:00
2020-08-10 08:26:09 +00:00
$params = [ 'order' => [ 'gravity' , 'uid' , 'commented' => true ]];
2018-06-10 07:26:37 +00:00
2018-02-26 22:15:57 +00:00
if ( $max_comments > 0 ) {
2018-06-10 07:26:37 +00:00
$params [ 'limit' ] = $max_comments ;
2018-02-26 22:15:57 +00:00
}
2018-01-04 10:02:56 +00:00
2018-01-15 13:05:12 +00:00
$items = [];
2018-01-04 10:02:56 +00:00
2020-05-07 18:39:39 +00:00
foreach ( $parents AS $parent ) {
2020-11-03 19:24:47 +00:00
if ( ! empty ( $parent [ 'thr-parent-id' ]) && ! empty ( $parent [ 'gravity' ]) && ( $parent [ 'gravity' ] == GRAVITY_ACTIVITY )) {
2021-01-16 22:37:27 +00:00
$condition = [ " `parent-uri-id` = ? AND `uid` IN (0, ?) AND (`vid` != ? OR `vid` IS NULL) " ,
2020-11-03 19:24:47 +00:00
$parent [ 'thr-parent-id' ], $uid , Verb :: getID ( Activity :: FOLLOW )];
2020-11-28 06:23:17 +00:00
if ( ! empty ( $parent [ 'author-id' ])) {
$activity = [ 'causer-id' => $parent [ 'author-id' ]];
foreach ([ 'commented' , 'received' , 'created' ] as $orderfields ) {
if ( ! empty ( $parent [ $orderfields ])) {
2021-02-21 19:38:53 +00:00
$activity [ $orderfields ] = $parent [ $orderfields ];
}
2020-11-28 06:23:17 +00:00
}
}
2020-11-03 19:24:47 +00:00
} else {
2021-01-27 10:01:42 +00:00
$condition = [ " `parent-uri-id` = ? AND `uid` IN (0, ?) AND (`vid` != ? OR `vid` IS NULL) " ,
$parent [ 'uri-id' ], $uid , Verb :: getID ( Activity :: FOLLOW )];
2020-11-28 06:23:17 +00:00
$activity = [];
2020-11-03 20:30:59 +00:00
}
2020-11-28 06:23:17 +00:00
$items = conversation_fetch_items ( $parent , $items , $condition , $block_authors , $params , $activity );
2018-01-04 10:02:56 +00:00
}
foreach ( $items as $index => $item ) {
if ( $item [ 'uid' ] == 0 ) {
2019-07-01 18:00:55 +00:00
$items [ $index ][ 'writable' ] = in_array ( $item [ 'network' ], Protocol :: FEDERATED );
2018-01-04 10:02:56 +00:00
}
}
2018-02-26 06:38:27 +00:00
$items = conv_sort ( $items , $order );
2018-01-04 10:02:56 +00:00
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2018-01-04 10:02:56 +00:00
return $items ;
}
2020-05-07 18:39:39 +00:00
/**
* Fetch conversation items
*
2020-11-03 20:30:59 +00:00
* @ param array $parent Parent Item array
* @ param array $items Item array
* @ param array $condition SQL condition
* @ param boolean $block_authors Don ' t show posts from contacts that are hidden ( used on the community page )
* @ param array $params SQL parameters
2020-11-28 06:23:17 +00:00
* @ param array $activity Contact data of the resharer
2020-05-07 18:39:39 +00:00
* @ return array
*/
2020-11-28 06:23:17 +00:00
function conversation_fetch_items ( array $parent , array $items , array $condition , bool $block_authors , array $params , array $activity ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2020-05-07 18:39:39 +00:00
if ( $block_authors ) {
2021-01-16 22:37:27 +00:00
$condition [ 0 ] .= " AND NOT `author-hidden` " ;
2020-05-07 18:39:39 +00:00
}
2021-04-08 19:53:59 +00:00
$thread_items = Post :: selectForUser ( local_user (), array_merge ( Item :: DISPLAY_FIELDLIST , [ 'pinned' , 'contact-uid' , 'gravity' , 'post-type' , 'post-reason' ]), $condition , $params );
2020-05-07 18:39:39 +00:00
2020-11-28 06:23:17 +00:00
$comments = conversation_fetch_comments ( $thread_items , $parent [ 'pinned' ] ? ? false , $activity );
2020-05-07 18:39:39 +00:00
if ( count ( $comments ) != 0 ) {
$items = array_merge ( $items , $comments );
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2020-05-07 18:39:39 +00:00
return $items ;
}
2021-05-04 12:45:27 +00:00
function item_photo_menu ( $item )
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2016-10-23 02:49:12 +00:00
$sub_link = '' ;
$poke_link = '' ;
$contact_url = '' ;
$pm_url = '' ;
$status_link = '' ;
$photos_link = '' ;
$posts_link = '' ;
2019-03-11 20:42:32 +00:00
$block_link = '' ;
$ignore_link = '' ;
2012-09-10 08:36:30 +00:00
2021-02-28 07:47:07 +00:00
if ( local_user () && local_user () == $item [ 'uid' ] && $item [ 'gravity' ] == GRAVITY_PARENT && ! $item [ 'self' ] && ! $item [ 'mention' ]) {
2021-01-30 20:51:27 +00:00
$sub_link = 'javascript:doFollowThread(' . $item [ 'id' ] . '); return false;' ;
2012-09-28 02:53:55 +00:00
}
2018-07-02 05:41:55 +00:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
2019-02-26 09:19:08 +00:00
$profile_link = Contact :: magicLinkByContact ( $author , $item [ 'author-link' ]);
2018-06-01 06:46:34 +00:00
$sparkle = ( strpos ( $profile_link , 'redir/' ) === 0 );
2012-09-10 08:36:30 +00:00
2016-06-05 18:01:38 +00:00
$cid = 0 ;
2021-02-17 18:59:19 +00:00
$pcid = $item [ 'author-id' ];
2016-10-23 02:49:12 +00:00
$network = '' ;
2016-06-05 18:01:38 +00:00
$rel = 0 ;
2018-11-08 16:28:29 +00:00
$condition = [ 'uid' => local_user (), 'nurl' => Strings :: normaliseLink ( $item [ 'author-link' ])];
2018-07-20 12:19:26 +00:00
$contact = DBA :: selectFirst ( 'contact' , [ 'id' , 'network' , 'rel' ], $condition );
2018-07-21 12:46:04 +00:00
if ( DBA :: isResult ( $contact )) {
2018-01-11 08:26:30 +00:00
$cid = $contact [ 'id' ];
$network = $contact [ 'network' ];
$rel = $contact [ 'rel' ];
2016-06-05 18:01:38 +00:00
}
2017-04-04 17:46:56 +00:00
if ( $sparkle ) {
2020-01-28 00:21:18 +00:00
$status_link = $profile_link . '/status' ;
2019-02-26 09:19:08 +00:00
$photos_link = str_replace ( '/profile/' , '/photos/' , $profile_link );
2020-01-28 00:21:18 +00:00
$profile_link = $profile_link . '/profile' ;
2016-10-23 02:49:12 +00:00
}
2012-09-10 08:36:30 +00:00
2019-03-11 20:42:32 +00:00
if ( ! empty ( $pcid )) {
$contact_url = 'contact/' . $pcid ;
2020-04-20 15:42:27 +00:00
$posts_link = $contact_url . '/posts' ;
2021-05-04 12:45:27 +00:00
$block_link = $item [ 'self' ] ? '' : $contact_url . '/block' ;
$ignore_link = $item [ 'self' ] ? '' : $contact_url . '/ignore' ;
2019-03-11 20:42:32 +00:00
}
2016-10-23 02:49:12 +00:00
if ( $cid && ! $item [ 'self' ]) {
2018-10-17 11:49:27 +00:00
$contact_url = 'contact/' . $cid ;
2020-04-20 15:42:27 +00:00
$poke_link = $contact_url . '/poke' ;
$posts_link = $contact_url . '/posts' ;
2012-09-10 08:36:30 +00:00
2019-07-01 18:00:55 +00:00
if ( in_array ( $network , [ Protocol :: ACTIVITYPUB , Protocol :: DFRN , Protocol :: DIASPORA ])) {
2016-10-23 02:49:12 +00:00
$pm_url = 'message/new/' . $cid ;
}
2012-09-10 08:36:30 +00:00
}
2015-10-10 14:23:20 +00:00
if ( local_user ()) {
2018-01-15 13:05:12 +00:00
$menu = [
2020-01-18 19:52:34 +00:00
DI :: l10n () -> t ( 'Follow Thread' ) => $sub_link ,
DI :: l10n () -> t ( 'View Status' ) => $status_link ,
DI :: l10n () -> t ( 'View Profile' ) => $profile_link ,
DI :: l10n () -> t ( 'View Photos' ) => $photos_link ,
DI :: l10n () -> t ( 'Network Posts' ) => $posts_link ,
DI :: l10n () -> t ( 'View Contact' ) => $contact_url ,
DI :: l10n () -> t ( 'Send PM' ) => $pm_url ,
DI :: l10n () -> t ( 'Block' ) => $block_link ,
DI :: l10n () -> t ( 'Ignore' ) => $ignore_link
2018-01-15 13:05:12 +00:00
];
2015-10-10 14:23:20 +00:00
2020-10-04 18:52:28 +00:00
if ( ! empty ( $item [ 'language' ])) {
$menu [ DI :: l10n () -> t ( 'Languages' )] = 'javascript:alert(\'' . Item :: getLanguageMessage ( $item ) . '\');' ;
}
2018-08-11 20:40:44 +00:00
if ( $network == Protocol :: DFRN ) {
2020-01-18 19:52:34 +00:00
$menu [ DI :: l10n () -> t ( " Poke " )] = $poke_link ;
2016-10-23 02:49:12 +00:00
}
2015-10-10 14:23:20 +00:00
2018-07-25 02:53:46 +00:00
if ((( $cid == 0 ) || ( $rel == Contact :: FOLLOWER )) &&
2019-07-01 18:00:55 +00:00
in_array ( $item [ 'network' ], Protocol :: FEDERATED )) {
2020-10-20 03:49:58 +00:00
$menu [ DI :: l10n () -> t ( 'Connect/Follow' )] = 'follow?url=' . urlencode ( $item [ 'author-link' ]) . '&auto=1' ;
2016-10-23 02:49:12 +00:00
}
} else {
2020-01-18 19:52:34 +00:00
$menu = [ DI :: l10n () -> t ( 'View Profile' ) => $item [ 'author-link' ]];
2016-10-23 02:49:12 +00:00
}
2012-09-10 08:36:30 +00:00
2018-01-15 13:05:12 +00:00
$args = [ 'item' => $item , 'menu' => $menu ];
2012-09-10 08:36:30 +00:00
2018-12-26 06:06:24 +00:00
Hook :: callAll ( 'item_photo_menu' , $args );
2012-09-10 08:36:30 +00:00
$menu = $args [ 'menu' ];
2016-10-23 02:49:12 +00:00
$o = '' ;
foreach ( $menu as $k => $v ) {
if ( strpos ( $v , 'javascript:' ) === 0 ) {
$v = substr ( $v , 11 );
$o .= '<li role="menuitem"><a onclick="' . $v . '">' . $k . '</a></li>' . PHP_EOL ;
2021-05-04 12:45:27 +00:00
} elseif ( $v ) {
2016-10-23 02:49:12 +00:00
$o .= '<li role="menuitem"><a href="' . $v . '">' . $k . '</a></li>' . PHP_EOL ;
2012-09-28 02:53:55 +00:00
}
2012-09-10 08:36:30 +00:00
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2012-09-10 08:36:30 +00:00
return $o ;
2017-08-09 21:12:41 +00:00
}
2011-04-13 00:58:16 +00:00
2015-06-03 18:57:30 +00:00
/**
2020-01-19 06:05:23 +00:00
* Checks item to see if it is one of the builtin activities ( like / dislike , event attendance , consensus items , etc . )
*
2015-06-03 18:57:30 +00:00
* Increments the count of each matching activity and adds a link to the author as needed .
*
2020-11-21 16:08:44 +00:00
* @ param array $activity
2015-06-03 18:57:30 +00:00
* @ param array & $conv_responses ( already created with builtin activity structure )
* @ return void
2019-01-07 15:24:06 +00:00
* @ throws ImagickException
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2015-06-03 18:57:30 +00:00
*/
2020-11-21 16:08:44 +00:00
function builtin_activity_puller ( array $activity , array & $conv_responses )
{
2017-04-04 17:46:56 +00:00
foreach ( $conv_responses as $mode => $v ) {
2015-06-03 18:57:30 +00:00
$sparkle = '' ;
2011-04-13 00:58:16 +00:00
2017-04-08 18:00:54 +00:00
switch ( $mode ) {
2015-06-03 18:57:30 +00:00
case 'like' :
2019-10-23 22:25:43 +00:00
$verb = Activity :: LIKE ;
2015-06-03 18:57:30 +00:00
break ;
case 'dislike' :
2019-10-23 22:25:43 +00:00
$verb = Activity :: DISLIKE ;
2015-06-03 18:57:30 +00:00
break ;
case 'attendyes' :
2019-10-23 22:25:43 +00:00
$verb = Activity :: ATTEND ;
2015-06-03 18:57:30 +00:00
break ;
case 'attendno' :
2019-10-23 22:25:43 +00:00
$verb = Activity :: ATTENDNO ;
2015-06-03 18:57:30 +00:00
break ;
case 'attendmaybe' :
2019-10-23 22:25:43 +00:00
$verb = Activity :: ATTENDMAYBE ;
2015-06-03 18:57:30 +00:00
break ;
2019-04-02 05:38:42 +00:00
case 'announce' :
2019-10-23 22:25:43 +00:00
$verb = Activity :: ANNOUNCE ;
2019-04-02 05:38:42 +00:00
break ;
2015-06-03 18:57:30 +00:00
default :
return ;
}
2012-09-10 08:36:30 +00:00
2020-11-21 16:08:44 +00:00
if ( ! empty ( $activity [ 'verb' ]) && DI :: activity () -> match ( $activity [ 'verb' ], $verb ) && ( $activity [ 'gravity' ] != GRAVITY_PARENT )) {
$author = [
'uid' => 0 ,
'id' => $activity [ 'author-id' ],
'network' => $activity [ 'author-network' ],
'url' => $activity [ 'author-link' ]
];
2019-02-22 02:29:22 +00:00
$url = Contact :: magicLinkByContact ( $author );
2018-06-01 06:46:34 +00:00
if ( strpos ( $url , 'redir/' ) === 0 ) {
2015-06-03 18:57:30 +00:00
$sparkle = ' class="sparkle" ' ;
2017-04-08 17:05:50 +00:00
}
2015-11-18 22:57:53 +00:00
2020-11-21 16:08:44 +00:00
$link = '<a href="' . $url . '"' . $sparkle . '>' . htmlentities ( $activity [ 'author-name' ]) . '</a>' ;
2012-09-10 08:36:30 +00:00
2021-01-27 10:01:42 +00:00
if ( empty ( $activity [ 'thr-parent-id' ])) {
$activity [ 'thr-parent-id' ] = $activity [ 'parent-uri-id' ];
2017-04-08 17:05:50 +00:00
}
2012-09-10 08:36:30 +00:00
2020-09-28 11:36:47 +00:00
// Skip when the causer of the parent is the same than the author of the announce
2021-01-27 10:01:42 +00:00
if (( $verb == Activity :: ANNOUNCE ) && Post :: exists ([ 'uri-id' => $activity [ 'thr-parent-id' ],
2020-11-21 16:08:44 +00:00
'uid' => $activity [ 'uid' ], 'causer-id' => $activity [ 'author-id' ], 'gravity' => GRAVITY_PARENT ])) {
2020-09-28 14:13:14 +00:00
continue ;
2020-09-28 11:36:47 +00:00
}
2021-01-27 10:01:42 +00:00
if ( ! isset ( $conv_responses [ $mode ][ $activity [ 'thr-parent-id' ]])) {
$conv_responses [ $mode ][ $activity [ 'thr-parent-id' ]] = [
2020-11-21 16:08:44 +00:00
'links' => [],
'self' => 0 ,
];
2021-01-27 10:01:42 +00:00
} elseif ( in_array ( $link , $conv_responses [ $mode ][ $activity [ 'thr-parent-id' ]][ 'links' ])) {
2020-11-21 20:56:07 +00:00
// only list each unique author once
continue ;
2017-04-08 17:05:50 +00:00
}
2015-05-31 23:23:04 +00:00
2020-11-21 16:08:44 +00:00
if ( public_contact () == $activity [ 'author-id' ]) {
2021-01-27 10:01:42 +00:00
$conv_responses [ $mode ][ $activity [ 'thr-parent-id' ]][ 'self' ] = 1 ;
2017-03-06 10:07:17 +00:00
}
2016-09-24 15:50:23 +00:00
2021-01-27 10:01:42 +00:00
$conv_responses [ $mode ][ $activity [ 'thr-parent-id' ]][ 'links' ][] = $link ;
2015-06-03 18:57:30 +00:00
// there can only be one activity verb per item so if we found anything, we can stop looking
return ;
}
2012-09-10 08:36:30 +00:00
}
2017-12-12 04:52:33 +00:00
}
2011-04-13 00:58:16 +00:00
2017-04-08 17:05:50 +00:00
/**
2020-11-21 16:08:44 +00:00
* Format the activity text for an item / photo / video
2019-01-07 15:24:06 +00:00
*
2020-11-21 16:08:44 +00:00
* @ param array $links = array of pre - linked names of actors
* @ param string $verb = one of 'like, ' dislike ', ' attendyes ', ' attendno ', ' attendmaybe '
* @ param int $id = item id
2018-02-03 17:25:58 +00:00
* @ return string formatted text
2019-01-07 15:24:06 +00:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2017-04-08 17:05:50 +00:00
*/
2020-11-21 16:08:44 +00:00
function format_activity ( array $links , $verb , $id ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2012-09-10 08:36:30 +00:00
$o = '' ;
2015-06-03 18:57:30 +00:00
$expanded = '' ;
2018-12-14 03:30:43 +00:00
$phrase = '' ;
2015-06-03 18:57:30 +00:00
2020-11-21 16:08:44 +00:00
$total = count ( $links );
if ( $total == 1 ) {
$likers = $links [ 0 ];
2012-12-22 19:57:29 +00:00
2015-10-14 17:48:57 +00:00
// Phrase if there is only one liker. In other cases it will be uses for the expanded
// list which show all likers
2020-11-21 16:08:44 +00:00
switch ( $verb ) {
2015-10-14 17:48:57 +00:00
case 'like' :
2020-01-18 19:52:34 +00:00
$phrase = DI :: l10n () -> t ( '%s likes this.' , $likers );
2015-10-14 17:48:57 +00:00
break ;
case 'dislike' :
2020-01-18 19:52:34 +00:00
$phrase = DI :: l10n () -> t ( '%s doesn\'t like this.' , $likers );
2015-10-14 17:48:57 +00:00
break ;
case 'attendyes' :
2020-01-18 19:52:34 +00:00
$phrase = DI :: l10n () -> t ( '%s attends.' , $likers );
2015-10-14 17:48:57 +00:00
break ;
case 'attendno' :
2020-01-18 19:52:34 +00:00
$phrase = DI :: l10n () -> t ( '%s doesn\'t attend.' , $likers );
2015-10-14 17:48:57 +00:00
break ;
case 'attendmaybe' :
2020-01-18 19:52:34 +00:00
$phrase = DI :: l10n () -> t ( '%s attends maybe.' , $likers );
2015-10-14 17:48:57 +00:00
break ;
2019-04-02 05:38:42 +00:00
case 'announce' :
2020-01-18 19:52:34 +00:00
$phrase = DI :: l10n () -> t ( '%s reshared this.' , $likers );
2019-04-02 05:38:42 +00:00
break ;
2015-10-14 17:48:57 +00:00
}
2020-11-21 16:08:44 +00:00
} elseif ( $total > 1 ) {
2017-04-04 17:46:56 +00:00
if ( $total < MAX_LIKERS ) {
2020-11-21 16:08:44 +00:00
$likers = implode ( ', ' , array_slice ( $links , 0 , - 1 ));
$likers .= ' ' . DI :: l10n () -> t ( 'and' ) . ' ' . $links [ count ( $links ) - 1 ];
2019-01-07 17:51:48 +00:00
} else {
2020-11-21 16:08:44 +00:00
$likers = implode ( ', ' , array_slice ( $links , 0 , MAX_LIKERS - 1 ));
$likers .= ' ' . DI :: l10n () -> t ( 'and %d other people' , $total - MAX_LIKERS );
2012-11-06 15:43:19 +00:00
}
2015-06-03 18:57:30 +00:00
2020-11-21 16:08:44 +00:00
$spanatts = " class= \" fakelink \" onclick= \" openClose(' { $verb } list- $id '); \" " ;
2015-11-18 22:57:53 +00:00
2019-01-07 17:51:48 +00:00
$explikers = '' ;
2020-11-21 16:08:44 +00:00
switch ( $verb ) {
2015-06-03 18:57:30 +00:00
case 'like' :
2020-11-21 16:08:44 +00:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> like this' , $spanatts , $total );
2020-01-18 19:52:34 +00:00
$explikers = DI :: l10n () -> t ( '%s like this.' , $likers );
2015-06-03 18:57:30 +00:00
break ;
case 'dislike' :
2020-11-21 16:08:44 +00:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> don\'t like this' , $spanatts , $total );
2020-01-18 19:52:34 +00:00
$explikers = DI :: l10n () -> t ( '%s don\'t like this.' , $likers );
2015-06-03 18:57:30 +00:00
break ;
case 'attendyes' :
2020-11-21 16:08:44 +00:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> attend' , $spanatts , $total );
2020-01-18 19:52:34 +00:00
$explikers = DI :: l10n () -> t ( '%s attend.' , $likers );
2015-06-03 18:57:30 +00:00
break ;
case 'attendno' :
2020-11-21 16:08:44 +00:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> don\'t attend' , $spanatts , $total );
2020-01-18 19:52:34 +00:00
$explikers = DI :: l10n () -> t ( '%s don\'t attend.' , $likers );
2015-06-03 18:57:30 +00:00
break ;
case 'attendmaybe' :
2020-11-21 16:08:44 +00:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> attend maybe' , $spanatts , $total );
2020-01-18 19:52:34 +00:00
$explikers = DI :: l10n () -> t ( '%s attend maybe.' , $likers );
2015-06-03 18:57:30 +00:00
break ;
2019-04-02 05:38:42 +00:00
case 'announce' :
2020-11-21 16:08:44 +00:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> reshared this' , $spanatts , $total );
2020-01-18 19:52:34 +00:00
$explikers = DI :: l10n () -> t ( '%s reshared this.' , $likers );
2019-04-02 05:38:42 +00:00
break ;
2015-06-03 18:57:30 +00:00
}
2015-10-14 17:48:57 +00:00
2020-11-21 16:08:44 +00:00
$expanded .= " \t " . '<p class="wall-item-' . $verb . '-expanded" id="' . $verb . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</p>' ;
2012-09-10 08:36:30 +00:00
}
2015-06-03 18:57:30 +00:00
2018-10-31 14:44:06 +00:00
$o .= Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'voting_fakelink.tpl' ), [
2015-06-03 18:57:30 +00:00
'$phrase' => $phrase ,
2020-11-21 16:08:44 +00:00
'$type' => $verb ,
2015-06-03 18:57:30 +00:00
'$id' => $id
2018-01-15 13:05:12 +00:00
]);
2015-06-03 18:57:30 +00:00
$o .= $expanded ;
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2012-09-10 08:36:30 +00:00
return $o ;
2017-12-12 04:52:33 +00:00
}
2011-04-20 12:48:12 +00:00
2018-01-01 20:27:33 +00:00
function status_editor ( App $a , $x , $notes_cid = 0 , $popup = false )
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2012-09-10 08:36:30 +00:00
$o = '' ;
2018-11-30 14:06:22 +00:00
$geotag = ! empty ( $x [ 'allow_location' ]) ? Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'jot_geotag.tpl' ), []) : '' ;
2012-09-10 08:36:30 +00:00
2018-10-31 14:44:06 +00:00
$tpl = Renderer :: getMarkupTemplate ( 'jot-header.tpl' );
2019-12-30 19:02:09 +00:00
DI :: page ()[ 'htmlhead' ] .= Renderer :: replaceMacros ( $tpl , [
2018-01-01 20:27:33 +00:00
'$newpost' => 'true' ,
2019-12-30 22:00:08 +00:00
'$baseurl' => DI :: baseUrl () -> get ( true ),
2018-01-01 20:27:33 +00:00
'$geotag' => $geotag ,
'$nickname' => $x [ 'nickname' ],
2020-01-18 19:52:34 +00:00
'$ispublic' => DI :: l10n () -> t ( 'Visible to <strong>everybody</strong>' ),
'$linkurl' => DI :: l10n () -> t ( 'Please enter a image/video/audio/webpage URL:' ),
'$term' => DI :: l10n () -> t ( 'Tag term:' ),
'$fileas' => DI :: l10n () -> t ( 'Save to Folder:' ),
'$whereareu' => DI :: l10n () -> t ( 'Where are you right now?' ),
2020-12-23 08:25:55 +00:00
'$delitems' => DI :: l10n () -> t ( " Delete item \x28 s \x29 ? " ),
'$is_mobile' => DI :: mode () -> isMobile (),
2018-01-15 13:05:12 +00:00
]);
2012-09-10 08:36:30 +00:00
2015-06-27 13:11:18 +00:00
$jotplugins = '' ;
2018-12-26 06:06:24 +00:00
Hook :: callAll ( 'jot_tool' , $jotplugins );
2012-09-10 08:36:30 +00:00
2018-10-31 14:44:06 +00:00
$tpl = Renderer :: getMarkupTemplate ( " jot.tpl " );
2012-09-10 08:36:30 +00:00
2020-11-21 16:08:44 +00:00
$o .= Renderer :: replaceMacros ( $tpl , [
2020-01-18 19:52:34 +00:00
'$new_post' => DI :: l10n () -> t ( 'New Post' ),
2020-09-09 04:15:25 +00:00
'$return_path' => DI :: args () -> getQueryString (),
2018-01-01 20:27:33 +00:00
'$action' => 'item' ,
2020-01-18 19:52:34 +00:00
'$share' => ( $x [ 'button' ] ? ? '' ) ? : DI :: l10n () -> t ( 'Share' ),
2020-01-30 03:50:10 +00:00
'$loading' => DI :: l10n () -> t ( 'Loading...' ),
2020-01-18 19:52:34 +00:00
'$upload' => DI :: l10n () -> t ( 'Upload photo' ),
'$shortupload' => DI :: l10n () -> t ( 'upload photo' ),
'$attach' => DI :: l10n () -> t ( 'Attach file' ),
'$shortattach' => DI :: l10n () -> t ( 'attach file' ),
'$edbold' => DI :: l10n () -> t ( 'Bold' ),
'$editalic' => DI :: l10n () -> t ( 'Italic' ),
'$eduline' => DI :: l10n () -> t ( 'Underline' ),
'$edquote' => DI :: l10n () -> t ( 'Quote' ),
'$edcode' => DI :: l10n () -> t ( 'Code' ),
'$edimg' => DI :: l10n () -> t ( 'Image' ),
'$edurl' => DI :: l10n () -> t ( 'Link' ),
'$edattach' => DI :: l10n () -> t ( 'Link or Media' ),
2021-05-10 22:56:07 +00:00
'$edvideo' => DI :: l10n () -> t ( 'Video' ),
2020-01-18 19:52:34 +00:00
'$setloc' => DI :: l10n () -> t ( 'Set your location' ),
'$shortsetloc' => DI :: l10n () -> t ( 'set location' ),
'$noloc' => DI :: l10n () -> t ( 'Clear browser location' ),
'$shortnoloc' => DI :: l10n () -> t ( 'clear location' ),
2019-10-16 12:43:59 +00:00
'$title' => $x [ 'title' ] ? ? '' ,
2020-01-18 19:52:34 +00:00
'$placeholdertitle' => DI :: l10n () -> t ( 'Set title' ),
2019-10-16 12:43:59 +00:00
'$category' => $x [ 'category' ] ? ? '' ,
2020-01-18 19:52:34 +00:00
'$placeholdercategory' => Feature :: isEnabled ( local_user (), 'categories' ) ? DI :: l10n () -> t ( " Categories \x28 comma-separated list \x29 " ) : '' ,
'$wait' => DI :: l10n () -> t ( 'Please wait' ),
'$permset' => DI :: l10n () -> t ( 'Permission settings' ),
2020-09-08 01:25:04 +00:00
'$shortpermset' => DI :: l10n () -> t ( 'Permissions' ),
2018-07-19 13:52:05 +00:00
'$wall' => $notes_cid ? 0 : 1 ,
'$posttype' => $notes_cid ? Item :: PT_PERSONAL_NOTE : Item :: PT_ARTICLE ,
2019-10-16 12:43:59 +00:00
'$content' => $x [ 'content' ] ? ? '' ,
'$post_id' => $x [ 'post_id' ] ? ? '' ,
2019-12-30 22:00:08 +00:00
'$baseurl' => DI :: baseUrl () -> get ( true ),
2018-01-01 20:27:33 +00:00
'$defloc' => $x [ 'default_location' ],
'$visitor' => $x [ 'visitor' ],
'$pvisit' => $notes_cid ? 'none' : $x [ 'visitor' ],
2020-01-18 19:52:34 +00:00
'$public' => DI :: l10n () -> t ( 'Public post' ),
2018-01-01 20:27:33 +00:00
'$lockstate' => $x [ 'lockstate' ],
'$bang' => $x [ 'bang' ],
'$profile_uid' => $x [ 'profile_uid' ],
2020-01-18 19:52:34 +00:00
'$preview' => DI :: l10n () -> t ( 'Preview' ),
2018-01-01 20:27:33 +00:00
'$jotplugins' => $jotplugins ,
'$notes_cid' => $notes_cid ,
2020-01-18 19:52:34 +00:00
'$cancel' => DI :: l10n () -> t ( 'Cancel' ),
2018-11-05 08:37:03 +00:00
'$rand_num' => Crypto :: randomDigits ( 12 ),
2013-01-26 19:52:21 +00:00
// ACL permissions box
2018-01-01 20:27:33 +00:00
'$acl' => $x [ 'acl' ],
2016-06-25 10:21:13 +00:00
//jot nav tab (used in some themes)
2020-01-18 19:52:34 +00:00
'$message' => DI :: l10n () -> t ( 'Message' ),
'$browser' => DI :: l10n () -> t ( 'Browser' ),
2020-04-01 14:10:57 +00:00
'$compose_link_title' => DI :: l10n () -> t ( 'Open Compose page' ),
2018-01-15 13:05:12 +00:00
]);
2012-09-10 08:36:30 +00:00
2017-04-08 18:00:54 +00:00
if ( $popup == true ) {
2018-01-01 20:27:33 +00:00
$o = '<div id="jot-popup" style="display: none;">' . $o . '</div>' ;
2012-09-10 08:36:30 +00:00
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2012-09-10 08:36:30 +00:00
return $o ;
2011-07-07 12:02:58 +00:00
}
2012-01-03 00:54:37 +00:00
2017-11-19 05:57:06 +00:00
/**
2017-11-19 15:42:00 +00:00
* Plucks the children of the given parent from a given item list .
2017-11-19 13:41:16 +00:00
*
2017-11-19 05:57:06 +00:00
* @ param array $item_list
* @ param array $parent
2019-01-07 15:24:06 +00:00
* @ param bool $recursive
* @ return array
2017-11-19 05:57:06 +00:00
*/
2017-11-19 15:42:00 +00:00
function get_item_children ( array & $item_list , array $parent , $recursive = true )
2017-11-19 05:57:06 +00:00
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2017-11-19 05:57:06 +00:00
$children = [];
2017-11-19 15:42:00 +00:00
foreach ( $item_list as $i => $item ) {
2020-05-27 12:19:06 +00:00
if ( $item [ 'gravity' ] != GRAVITY_PARENT ) {
2017-11-19 05:57:06 +00:00
if ( $recursive ) {
2012-09-10 08:36:30 +00:00
// Fallback to parent-uri if thr-parent is not set
2021-01-27 10:01:42 +00:00
$thr_parent = $item [ 'thr-parent-id' ];
2017-04-08 17:05:50 +00:00
if ( $thr_parent == '' ) {
2021-01-27 10:01:42 +00:00
$thr_parent = $item [ 'parent-uri-id' ];
2017-04-08 17:05:50 +00:00
}
2012-09-10 08:36:30 +00:00
2021-01-27 10:01:42 +00:00
if ( $thr_parent == $parent [ 'uri-id' ]) {
2017-11-19 05:57:06 +00:00
$item [ 'children' ] = get_item_children ( $item_list , $item );
2012-09-10 08:36:30 +00:00
$children [] = $item ;
2017-11-19 15:42:00 +00:00
unset ( $item_list [ $i ]);
2012-09-10 08:36:30 +00:00
}
2021-01-27 10:01:42 +00:00
} elseif ( $item [ 'parent-uri-id' ] == $parent [ 'uri-id' ]) {
2012-09-10 08:36:30 +00:00
$children [] = $item ;
2017-11-19 15:42:00 +00:00
unset ( $item_list [ $i ]);
2012-09-10 08:36:30 +00:00
}
}
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2012-09-10 08:36:30 +00:00
return $children ;
2012-07-27 20:08:57 +00:00
}
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* Recursively sorts a tree - like item array
2017-11-19 05:57:06 +00:00
*
* @ param array $items
* @ return array
*/
function sort_item_children ( array $items )
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2012-09-10 08:36:30 +00:00
$result = $items ;
2019-07-07 21:30:33 +00:00
usort ( $result , 'sort_thr_received_rev' );
2017-04-04 17:46:56 +00:00
foreach ( $result as $k => $i ) {
2017-11-19 05:57:06 +00:00
if ( isset ( $result [ $k ][ 'children' ])) {
2012-09-10 08:36:30 +00:00
$result [ $k ][ 'children' ] = sort_item_children ( $result [ $k ][ 'children' ]);
}
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2012-09-10 08:36:30 +00:00
return $result ;
2012-07-27 20:08:57 +00:00
}
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* Recursively add all children items at the top level of a list
2017-11-19 05:57:06 +00:00
*
* @ param array $children List of items to append
* @ param array $item_list
*/
function add_children_to_list ( array $children , array & $item_list )
{
foreach ( $children as $child ) {
$item_list [] = $child ;
if ( isset ( $child [ 'children' ])) {
add_children_to_list ( $child [ 'children' ], $item_list );
2017-04-04 17:46:56 +00:00
}
2012-09-10 08:36:30 +00:00
}
2012-07-27 20:08:57 +00:00
}
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* Selectively flattens a tree - like item structure to prevent threading stairs
*
2017-11-19 05:57:06 +00:00
* This recursive function takes the item tree structure created by conv_sort () and
* flatten the extraneous depth levels when people reply sequentially , removing the
* stairs effect in threaded conversations limiting the available content width .
*
* The basic principle is the following : if a post item has only one reply and is
* the last reply of its parent , then the reply is moved to the parent .
*
* This process is rendered somewhat more complicated because items can be either
* replies or likes , and these don ' t factor at all in the reply count / last reply .
*
* @ param array $parent A tree - like array of items
* @ return array
*/
function smart_flatten_conversation ( array $parent )
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2018-02-27 09:29:11 +00:00
if ( ! isset ( $parent [ 'children' ]) || count ( $parent [ 'children' ]) == 0 ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2017-11-19 05:57:06 +00:00
return $parent ;
2017-04-04 17:46:56 +00:00
}
2012-09-10 08:36:30 +00:00
2017-11-19 05:57:06 +00:00
// We use a for loop to ensure we process the newly-moved items
for ( $i = 0 ; $i < count ( $parent [ 'children' ]); $i ++ ) {
$child = $parent [ 'children' ][ $i ];
2015-11-18 22:57:53 +00:00
2017-11-19 05:57:06 +00:00
if ( isset ( $child [ 'children' ]) && count ( $child [ 'children' ])) {
// This helps counting only the regular posts
$count_post_closure = function ( $var ) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2019-10-23 22:25:43 +00:00
return $var [ 'verb' ] === Activity :: POST ;
2017-11-19 05:57:06 +00:00
};
$child_post_count = count ( array_filter ( $child [ 'children' ], $count_post_closure ));
$remaining_post_count = count ( array_filter ( array_slice ( $parent [ 'children' ], $i ), $count_post_closure ));
// If there's only one child's children post and this is the last child post
if ( $child_post_count == 1 && $remaining_post_count == 1 ) {
// Searches the post item in the children
$j = 0 ;
2019-10-23 22:25:43 +00:00
while ( $child [ 'children' ][ $j ][ 'verb' ] !== Activity :: POST && $j < count ( $child [ 'children' ])) {
2017-11-19 05:57:06 +00:00
$j ++ ;
}
$moved_item = $child [ 'children' ][ $j ];
unset ( $parent [ 'children' ][ $i ][ 'children' ][ $j ]);
$parent [ 'children' ][] = $moved_item ;
} else {
$parent [ 'children' ][ $i ] = smart_flatten_conversation ( $child );
}
2017-04-04 17:46:56 +00:00
}
}
2015-11-18 22:57:53 +00:00
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2017-11-19 05:57:06 +00:00
return $parent ;
}
2012-09-10 08:36:30 +00:00
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* Expands a flat list of items into corresponding tree - like conversation structures .
*
2019-07-07 21:30:33 +00:00
* sort the top - level posts either on " received " or " commented " , and finally
2017-11-19 05:57:06 +00:00
* append all the items at the top level ( ? ? ? )
*
* @ param array $item_list A list of items belonging to one or more conversations
2019-07-07 21:30:33 +00:00
* @ param string $order Either on " received " or " commented "
2017-11-19 05:57:06 +00:00
* @ return array
2019-01-07 15:24:06 +00:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2017-11-19 05:57:06 +00:00
*/
function conv_sort ( array $item_list , $order )
{
2021-07-27 04:57:29 +00:00
DI :: profiler () -> startRecording ( 'rendering' );
2017-11-19 05:57:06 +00:00
$parents = [];
if ( ! ( is_array ( $item_list ) && count ( $item_list ))) {
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2017-11-19 05:57:06 +00:00
return $parents ;
}
2018-08-10 04:27:52 +00:00
$blocklist = conv_get_blocklist ();
2017-11-19 05:57:06 +00:00
$item_array = [];
// Dedupes the item list on the uri to prevent infinite loops
foreach ( $item_list as $item ) {
2018-08-10 04:27:52 +00:00
if ( in_array ( $item [ 'author-id' ], $blocklist )) {
continue ;
}
2021-01-27 10:01:42 +00:00
$item_array [ $item [ 'uri-id' ]] = $item ;
2017-11-19 05:57:06 +00:00
}
// Extract the top level items
foreach ( $item_array as $item ) {
2020-05-27 12:19:06 +00:00
if ( $item [ 'gravity' ] == GRAVITY_PARENT ) {
2017-11-19 05:57:06 +00:00
$parents [] = $item ;
2017-04-04 17:46:56 +00:00
}
}
2012-09-10 08:36:30 +00:00
2019-11-07 07:39:50 +00:00
if ( stristr ( $order , 'pinned_received' )) {
usort ( $parents , 'sort_thr_pinned_received' );
} elseif ( stristr ( $order , 'received' )) {
2019-07-07 21:30:33 +00:00
usort ( $parents , 'sort_thr_received' );
2017-04-08 18:07:28 +00:00
} elseif ( stristr ( $order , 'commented' )) {
2017-04-14 13:30:50 +00:00
usort ( $parents , 'sort_thr_commented' );
2017-04-04 17:46:56 +00:00
}
2012-09-10 08:36:30 +00:00
2017-11-19 15:42:00 +00:00
/*
* Plucks children from the item_array , second pass collects eventual orphan
* items and add them as children of their top - level post .
*/
2017-11-19 05:57:06 +00:00
foreach ( $parents as $i => $parent ) {
2017-11-19 15:42:00 +00:00
$parents [ $i ][ 'children' ] =
2017-11-28 18:54:39 +00:00
array_merge ( get_item_children ( $item_array , $parent , true ),
2017-11-24 21:39:12 +00:00
get_item_children ( $item_array , $parent , false ));
2017-04-04 17:46:56 +00:00
}
2012-09-10 08:36:30 +00:00
2017-11-19 05:57:06 +00:00
foreach ( $parents as $i => $parent ) {
$parents [ $i ][ 'children' ] = sort_item_children ( $parents [ $i ][ 'children' ]);
}
2020-01-18 15:50:57 +00:00
if ( ! DI :: pConfig () -> get ( local_user (), 'system' , 'no_smart_threading' , 0 )) {
2017-11-19 05:57:06 +00:00
foreach ( $parents as $i => $parent ) {
$parents [ $i ] = smart_flatten_conversation ( $parent );
2012-09-10 08:36:30 +00:00
}
}
2017-11-19 05:57:06 +00:00
/// @TODO: Stop recusrsively adding all children back to the top level (!!!)
/// However, this apparently ensures responses (likes, attendance) display (?!)
foreach ( $parents as $parent ) {
if ( count ( $parent [ 'children' ])) {
add_children_to_list ( $parent [ 'children' ], $parents );
2012-09-10 08:36:30 +00:00
}
}
2021-07-27 04:57:29 +00:00
DI :: profiler () -> stopRecording ();
2017-11-19 05:57:06 +00:00
return $parents ;
2012-01-03 00:54:37 +00:00
}
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* usort () callback to sort item arrays by pinned and the received key
2017-11-19 05:57:06 +00:00
*
* @ param array $a
* @ param array $b
* @ return int
*/
2019-11-07 07:39:50 +00:00
function sort_thr_pinned_received ( array $a , array $b )
2017-11-19 05:57:06 +00:00
{
2019-11-07 07:09:46 +00:00
if ( $b [ 'pinned' ] && ! $a [ 'pinned' ]) {
return 1 ;
} elseif ( ! $b [ 'pinned' ] && $a [ 'pinned' ]) {
return - 1 ;
}
2019-07-07 21:30:33 +00:00
return strcmp ( $b [ 'received' ], $a [ 'received' ]);
2012-01-03 00:54:37 +00:00
}
2019-11-07 07:39:50 +00:00
/**
2020-01-19 06:05:23 +00:00
* usort () callback to sort item arrays by the received key
2019-11-07 07:39:50 +00:00
*
* @ param array $a
* @ param array $b
* @ return int
*/
function sort_thr_received ( array $a , array $b )
{
return strcmp ( $b [ 'received' ], $a [ 'received' ]);
}
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* usort () callback to reverse sort item arrays by the received key
2017-11-19 05:57:06 +00:00
*
* @ param array $a
* @ param array $b
* @ return int
*/
2019-07-07 21:30:33 +00:00
function sort_thr_received_rev ( array $a , array $b )
2017-11-19 05:57:06 +00:00
{
2019-07-07 21:30:33 +00:00
return strcmp ( $a [ 'received' ], $b [ 'received' ]);
2012-01-03 00:54:37 +00:00
}
2017-11-19 05:57:06 +00:00
/**
2020-01-19 06:05:23 +00:00
* usort () callback to sort item arrays by the commented key
2017-11-19 05:57:06 +00:00
*
* @ param array $a
* @ param array $b
2019-01-21 16:36:01 +00:00
* @ return int
2017-11-19 05:57:06 +00:00
*/
function sort_thr_commented ( array $a , array $b )
{
2017-04-08 17:05:50 +00:00
return strcmp ( $b [ 'commented' ], $a [ 'commented' ]);
2012-01-03 00:54:37 +00:00
}