2011-04-11 00:21:16 -04:00
< ? php
2017-11-16 13:24:59 -05:00
/**
2020-02-09 10:18:46 -05:00
* @ copyright Copyright ( C ) 2020 , Friendica
*
* @ 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 13:24:59 -05:00
*/
2018-01-24 21:08:45 -05:00
2017-04-30 00:07:00 -04:00
use Friendica\App ;
2018-01-09 22:42:04 -05:00
use Friendica\Content\ContactSelector ;
2017-12-04 09:04:36 -05:00
use Friendica\Content\Feature ;
2018-02-04 19:23:49 -05:00
use Friendica\Content\Text\BBCode ;
2018-12-26 01:06:24 -05:00
use Friendica\Core\Hook ;
2018-10-29 17:20:46 -04:00
use Friendica\Core\Logger ;
2018-08-11 16:40:44 -04:00
use Friendica\Core\Protocol ;
2018-10-31 10:35:50 -04:00
use Friendica\Core\Renderer ;
2019-05-26 16:15:38 -04:00
use Friendica\Core\Session ;
2020-09-03 10:03:36 -04:00
use Friendica\Core\Theme ;
2018-07-20 08:19:26 -04:00
use Friendica\Database\DBA ;
2019-12-15 17:28:01 -05:00
use Friendica\DI ;
2017-12-07 23:33:36 -05:00
use Friendica\Model\Contact ;
2018-06-10 03:26:37 -04:00
use Friendica\Model\Item ;
2021-01-15 23:11:28 -05:00
use Friendica\Model\Post ;
2018-07-19 22:15:21 -04:00
use Friendica\Model\Profile ;
2020-04-26 11:24:58 -04:00
use Friendica\Model\Tag ;
2020-05-26 01:18:50 -04:00
use Friendica\Model\Verb ;
2021-01-16 07:35:44 -05:00
use Friendica\Object\Post as PostObject ;
2018-01-24 21:08:45 -05:00
use Friendica\Object\Thread ;
2019-10-22 20:05:11 -04:00
use Friendica\Protocol\Activity ;
2019-10-24 18:10:20 -04:00
use Friendica\Util\Crypto ;
2018-01-26 21:38:34 -05:00
use Friendica\Util\DateTimeFormat ;
2018-11-08 10:14:37 -05:00
use Friendica\Util\Strings ;
2019-10-24 18:10:20 -04:00
use Friendica\Util\Temporal ;
2018-02-03 12:25:58 -05:00
use Friendica\Util\XML ;
2017-04-30 00:07:00 -04:00
2012-07-07 18:20:24 -04:00
function item_extract_images ( $body ) {
2018-01-15 08:05:12 -05:00
$saved_image = [];
2012-09-10 04:36:30 -04:00
$orig_body = $body ;
$new_body = '' ;
2012-07-07 18:20:24 -04:00
2012-09-10 04:36:30 -04:00
$cnt = 0 ;
$img_start = strpos ( $orig_body , '[img' );
$img_st_close = ( $img_start !== false ? strpos ( substr ( $orig_body , $img_start ), ']' ) : false );
$img_end = ( $img_start !== false ? strpos ( substr ( $orig_body , $img_start ), '[/img]' ) : false );
2017-04-04 13:46:56 -04:00
while (( $img_st_close !== false ) && ( $img_end !== false )) {
2012-07-07 18:20:24 -04:00
2012-09-10 04:36:30 -04:00
$img_st_close ++ ; // make it point to AFTER the closing bracket
$img_end += $img_start ;
2012-07-07 18:20:24 -04:00
2018-02-27 04:29:11 -05:00
if ( ! strcmp ( substr ( $orig_body , $img_start + $img_st_close , 5 ), 'data:' )) {
2012-09-10 04:36:30 -04:00
// This is an embedded image
2012-07-07 18:20:24 -04:00
2012-09-10 04:36:30 -04:00
$saved_image [ $cnt ] = substr ( $orig_body , $img_start + $img_st_close , $img_end - ( $img_start + $img_st_close ));
$new_body = $new_body . substr ( $orig_body , 0 , $img_start ) . '[!#saved_image' . $cnt . '#!]' ;
2012-07-07 20:47:13 -04:00
2012-09-10 04:36:30 -04:00
$cnt ++ ;
2017-04-08 13:05:50 -04:00
} else {
2012-09-10 04:36:30 -04:00
$new_body = $new_body . substr ( $orig_body , 0 , $img_end + strlen ( '[/img]' ));
2017-04-08 13:05:50 -04:00
}
2012-07-07 18:20:24 -04:00
2012-09-10 04:36:30 -04:00
$orig_body = substr ( $orig_body , $img_end + strlen ( '[/img]' ));
2012-07-07 18:20:24 -04:00
2017-04-08 13:05:50 -04:00
if ( $orig_body === false ) {
// in case the body ends on a closing image tag
2012-09-10 04:36:30 -04:00
$orig_body = '' ;
2017-04-08 13:05:50 -04:00
}
2012-07-07 18:20:24 -04:00
2012-09-10 04:36:30 -04:00
$img_start = strpos ( $orig_body , '[img' );
$img_st_close = ( $img_start !== false ? strpos ( substr ( $orig_body , $img_start ), ']' ) : false );
$img_end = ( $img_start !== false ? strpos ( substr ( $orig_body , $img_start ), '[/img]' ) : false );
}
2012-07-07 18:20:24 -04:00
2012-09-10 04:36:30 -04:00
$new_body = $new_body . $orig_body ;
2012-07-07 18:20:24 -04:00
2018-01-15 08:05:12 -05:00
return [ 'body' => $new_body , 'images' => $saved_image ];
2017-12-11 23:52:33 -05:00
}
2012-07-07 18:20:24 -04:00
function item_redir_and_replace_images ( $body , $images , $cid ) {
2012-09-10 04:36:30 -04:00
$origbody = $body ;
$newbody = '' ;
$cnt = 1 ;
2018-02-04 19:23:49 -05:00
$pos = BBCode :: getTagPosition ( $origbody , 'url' , 0 );
2017-04-04 13:46:56 -04:00
while ( $pos !== false && $cnt < 1000 ) {
2012-09-10 04:36:30 -04:00
$search = '/\[url\=(.*?)\]\[!#saved_image([0-9]*)#!\]\[\/url\]' . '/is' ;
2019-12-30 17:00:08 -05:00
$replace = '[url=' . DI :: baseUrl () . '/redir/' . $cid
2020-01-13 15:10:13 -05:00
. '?url=' . '$1' . '][!#saved_image' . '$2' . '#!][/url]' ;
2012-09-10 04:36:30 -04:00
$newbody .= substr ( $origbody , 0 , $pos [ 'start' ][ 'open' ]);
$subject = substr ( $origbody , $pos [ 'start' ][ 'open' ], $pos [ 'end' ][ 'close' ] - $pos [ 'start' ][ 'open' ]);
$origbody = substr ( $origbody , $pos [ 'end' ][ 'close' ]);
2017-04-08 14:00:54 -04:00
if ( $origbody === false ) {
2012-09-10 04:36:30 -04:00
$origbody = '' ;
2017-04-08 14:00:54 -04:00
}
2012-09-10 04:36:30 -04:00
$subject = preg_replace ( $search , $replace , $subject );
$newbody .= $subject ;
$cnt ++ ;
2018-02-04 19:23:49 -05:00
// Isn't this supposed to use $cnt value for $occurrences? - @MrPetovan
$pos = BBCode :: getTagPosition ( $origbody , 'url' , 0 );
2012-09-10 04:36:30 -04:00
}
$newbody .= $origbody ;
$cnt = 0 ;
2016-12-20 15:13:50 -05:00
foreach ( $images as $image ) {
2017-04-08 13:05:50 -04:00
/*
* We 're depending on the property of ' foreach ' ( specified on the PHP website ) that
* it loops over the array starting from the first element and going sequentially
* to the last element .
*/
2012-09-10 04:36:30 -04:00
$newbody = str_replace ( '[!#saved_image' . $cnt . '#!]' , '[img]' . $image . '[/img]' , $newbody );
$cnt ++ ;
}
return $newbody ;
2017-12-11 23:52:33 -05:00
}
2012-07-07 18:20:24 -04:00
2011-04-18 11:37:02 -04:00
/**
* Render actions localized
2019-01-07 10:24:06 -05:00
*
* @ param $item
* @ throws ImagickException
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2011-04-18 11:37:02 -04:00
*/
2018-06-19 15:06:17 -04:00
function localize_item ( & $item )
{
2012-09-10 04:36:30 -04:00
$extracted = item_extract_images ( $item [ 'body' ]);
2017-04-08 14:00:54 -04:00
if ( $extracted [ 'images' ]) {
2012-09-10 04:36:30 -04:00
$item [ 'body' ] = item_redir_and_replace_images ( $extracted [ 'body' ], $extracted [ 'images' ], $item [ 'contact-id' ]);
2017-04-08 14:00:54 -04:00
}
2012-09-10 04:36:30 -04:00
2020-04-04 16:00:40 -04:00
/// @todo The following functionality needs to be cleaned up.
if ( ! empty ( $item [ 'verb' ])) {
$activity = DI :: activity ();
2020-04-05 13:25:36 -04:00
$xmlhead = " < " . " ?xml version='1.0' encoding='UTF-8' ? " . " > " ;
2020-04-04 16:00:40 -04:00
if ( stristr ( $item [ 'verb' ], Activity :: POKE )) {
2020-04-05 03:08:20 -04:00
$verb = urldecode ( substr ( $item [ 'verb' ], strpos ( $item [ 'verb' ], '#' ) + 1 ));
2020-04-04 16:00:40 -04:00
if ( ! $verb ) {
return ;
}
2020-04-05 03:08:20 -04:00
if ( $item [ 'object-type' ] == " " || $item [ 'object-type' ] !== Activity\ObjectType :: PERSON ) {
2020-04-04 16:00:40 -04:00
return ;
2012-09-10 04:36:30 -04:00
}
2020-04-04 16:00:40 -04:00
$Aname = $item [ 'author-name' ];
$Alink = $item [ 'author-link' ];
2012-09-10 04:36:30 -04:00
2020-04-05 03:08:20 -04:00
$obj = XML :: parseString ( $xmlhead . $item [ 'object' ]);
2012-09-10 04:36:30 -04:00
2020-04-04 16:00:40 -04:00
$Bname = $obj -> title ;
$Blink = $obj -> id ;
$Bphoto = " " ;
2018-08-29 09:00:01 -04:00
2020-04-04 16:00:40 -04: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 04:36:30 -04:00
}
2020-04-04 16:00:40 -04:00
$A = '[url=' . Contact :: magicLink ( $Alink ) . ']' . $Aname . '[/url]' ;
$B = '[url=' . Contact :: magicLink ( $Blink ) . ']' . $Bname . '[/url]' ;
if ( $Bphoto != " " ) {
$Bphoto = '[url=' . Contact :: magicLink ( $Blink ) . '][img=80x80]' . $Bphoto . '[/img][/url]' ;
}
2015-10-04 15:17:28 -04:00
2020-04-04 16:00:40 -04: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 04:36:30 -04:00
2020-04-04 16:00:40 -04:00
// now translate the verb
2020-04-05 03:11:47 -04:00
$poked_t = trim ( sprintf ( $txt , '' , '' ));
2020-04-04 16:00:40 -04:00
$txt = str_replace ( $poked_t , DI :: l10n () -> t ( $verb ), $txt );
2012-09-10 04:36:30 -04:00
2020-04-04 16:00:40 -04:00
// then do the sprintf on the translation string
2012-09-10 04:36:30 -04:00
2020-04-05 03:11:47 -04:00
$item [ 'body' ] = sprintf ( $txt , $A , $B ) . " \n \n \n " . $Bphoto ;
2012-09-10 04:36:30 -04:00
2017-04-08 14:00:54 -04:00
}
2020-04-05 03:08:20 -04:00
if ( $activity -> match ( $item [ 'verb' ], Activity :: TAG )) {
2020-04-04 16:00:40 -04:00
$fields = [ 'author-id' , 'author-link' , 'author-name' , 'author-network' ,
'verb' , 'object-type' , 'resource-id' , 'body' , 'plink' ];
2021-01-15 23:11:28 -05:00
$obj = Post :: selectFirst ( $fields , [ 'uri' => $item [ 'parent-uri' ]]);
2020-04-04 16:00:40 -04:00
if ( ! DBA :: isResult ( $obj )) {
return ;
}
2012-09-10 04:36:30 -04:00
2020-04-04 16:00:40 -04: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 04:36:30 -04:00
2020-04-05 13:25:36 -04:00
$parsedobj = XML :: parseString ( $xmlhead . $item [ 'object' ]);
2012-09-10 04:36:30 -04:00
2020-04-04 16:00:40 -04: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 04:36:30 -04:00
}
}
2020-04-04 16:00:40 -04:00
2012-09-10 04:36:30 -04:00
$matches = null ;
2017-04-08 14:00:54 -04:00
if ( preg_match_all ( '/@\[url=(.*?)\]/is' , $item [ 'body' ], $matches , PREG_SET_ORDER )) {
2017-04-04 13:46:56 -04:00
foreach ( $matches as $mtch ) {
2018-02-27 04:29:11 -05:00
if ( ! strpos ( $mtch [ 1 ], 'zrl=' )) {
2018-06-02 04:05:06 -04:00
$item [ 'body' ] = str_replace ( $mtch [ 0 ], '@[url=' . Contact :: magicLink ( $mtch [ 1 ]) . ']' , $item [ 'body' ]);
2017-04-08 14:00:54 -04:00
}
2012-09-10 04:36:30 -04:00
}
}
// add zrl's to public images
2016-01-15 17:32:13 -05:00
$photo_pattern = " / \ [url=(.*?) \ /photos \ /(.*?) \ /image \ /(.*?) \ ] \ [img(.*?) \ ]h(.*?) \ [ \ /img \ ] \ [ \ /url \ ]/is " ;
2017-04-08 14:00:54 -04:00
if ( preg_match ( $photo_pattern , $item [ 'body' ])) {
2020-11-21 11:08:44 -05:00
$photo_replace = '[url=' . Profile :: zrl ( '$1' . '/photos/' . '$2' . '/image/' . '$3' , true ) . '][img' . '$4' . ']h' . '$5' . '[/img][/url]' ;
2018-02-04 19:23:49 -05:00
$item [ 'body' ] = BBCode :: pregReplaceInTag ( $photo_pattern , $photo_replace , 'url' , $item [ 'body' ]);
2016-01-15 17:32:13 -05:00
}
2012-09-10 04:36:30 -04:00
// add sparkle links to appropriate permalinks
2018-07-02 01:41:55 -04:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
2018-07-10 08:27:56 -04:00
2018-10-21 16:23:08 -04:00
// Only create a redirection to a magic link when logged in
2019-09-28 14:09:11 -04:00
if ( ! empty ( $item [ 'plink' ]) && Session :: isAuthenticated ()) {
2019-02-21 21:29:22 -05:00
$item [ 'plink' ] = Contact :: magicLinkByContact ( $author , $item [ 'plink' ]);
2018-07-10 08:27:56 -04:00
}
2011-04-18 11:37:02 -04:00
}
2012-08-07 03:53:53 -04:00
/**
* Count the total of comments on this item and its desendants
2017-04-08 14:00:54 -04:00
* @ TODO proper type - hint + doc - tag
2019-01-07 10:24:06 -05:00
* @ param $item
* @ return int
2012-08-07 03:53:53 -04:00
*/
function count_descendants ( $item ) {
2012-09-10 04:36:30 -04:00
$total = count ( $item [ 'children' ]);
2017-04-04 13:46:56 -04:00
if ( $total > 0 ) {
foreach ( $item [ 'children' ] as $child ) {
2018-02-27 04:29:11 -05:00
if ( ! visible_activity ( $child )) {
2012-09-10 04:36:30 -04:00
$total -- ;
2017-04-08 14:03:21 -04:00
}
2012-09-10 04:36:30 -04:00
$total += count_descendants ( $child );
}
}
return $total ;
2012-08-07 03:53:53 -04:00
}
2012-09-18 23:12:55 -04:00
function visible_activity ( $item ) {
2019-12-15 17:28:01 -05:00
$activity = DI :: activity ();
2019-10-22 20:05:11 -04:00
2019-11-18 01:39:56 -05:00
if ( empty ( $item [ 'verb' ]) || $activity -> isHidden ( $item [ 'verb' ])) {
2019-10-23 18:25:43 -04:00
return false ;
2015-05-31 19:23:04 -04:00
}
2012-09-18 23:12:55 -04:00
2018-05-14 16:25:39 -04:00
// @TODO below if() block can be rewritten to a single line: $isVisible = allConditionsHere;
2019-10-23 18:25:43 -04:00
if ( $activity -> match ( $item [ 'verb' ], Activity :: FOLLOW ) &&
2019-10-24 18:10:20 -04:00
$item [ 'object-type' ] === Activity\ObjectType :: NOTE &&
2019-10-23 18:25:43 -04:00
empty ( $item [ 'self' ]) &&
$item [ 'uid' ] == local_user ()) {
2018-05-13 10:58:40 -04:00
return false ;
2012-09-27 22:53:55 -04:00
}
2012-09-18 23:12:55 -04:00
return true ;
}
2018-08-10 00:27:52 -04:00
function conv_get_blocklist ()
{
if ( ! local_user ()) {
return [];
}
2020-07-18 21:21:15 -04:00
$str_blocked = str_replace ([ " \n " , " \r " ], " , " , DI :: pConfig () -> get ( local_user (), 'system' , 'blocked' ));
2018-08-10 00:27:52 -04:00
if ( empty ( $str_blocked )) {
return [];
}
$blocklist = [];
foreach ( explode ( ',' , $str_blocked ) as $entry ) {
2020-12-11 09:16:29 -05:00
$cid = Contact :: getIdForURL ( trim ( $entry ), 0 , false );
2018-08-10 00:27:52 -04:00
if ( ! empty ( $cid )) {
$blocklist [] = $cid ;
}
}
return $blocklist ;
}
2011-04-12 20:58:16 -04: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 03:19:08 -04:00
* figures out how to determine page owner and other contextual items
2011-04-12 20:58:16 -04:00
* that are based on unique features of the calling module .
2019-01-07 10:24:06 -05: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-12 20:58:16 -04:00
*/
2020-02-13 23:40:00 -05:00
function conversation ( App $a , array $items , $mode , $update , $preview = false , $order = 'commented' , $uid = 0 )
2018-10-24 02:15:24 -04:00
{
2020-09-03 10:03:36 -04: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 00:27:52 -04:00
$ssl_state = ( local_user () ? true : false );
2012-09-10 03:19:08 -04:00
2012-09-10 04:36:30 -04:00
$profile_owner = 0 ;
2012-10-09 11:41:33 -04:00
$live_update_div = '' ;
2012-09-10 03:19:08 -04:00
2018-08-10 00:27:52 -04:00
$blocklist = conv_get_blocklist ();
2013-04-29 00:02:53 -04:00
2012-09-10 04:36:30 -04:00
$previewing = (( $preview ) ? ' preview ' : '' );
2012-09-10 03:19:08 -04:00
2017-04-04 13:46:56 -04:00
if ( $mode === 'network' ) {
2018-05-26 14:07:27 -04:00
$items = conversation_add_children ( $items , false , $order , $uid );
2012-09-10 04:36:30 -04:00
$profile_owner = local_user ();
2017-04-04 13:46:56 -04:00
if ( ! $update ) {
2017-04-08 13:05:50 -04: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 11:41:33 -04:00
$live_update_div = '<div id="live-network"></div>' . " \r \n "
2015-10-07 18:25:55 -04:00
. " <script> var profile_uid = " . $_SESSION [ 'uid' ]
2019-12-15 19:33:13 -05:00
. " ; var netargs = ' " . substr ( DI :: args () -> getCommand (), 8 )
2012-10-09 11:41:33 -04:00
. '?f='
2020-05-17 11:01:27 -04: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 11:41:33 -04:00
2020-02-13 23:40:00 -05:00
. " '; </script> \r \n " ;
2012-10-09 11:41:33 -04:00
}
2017-04-08 13:05:50 -04:00
} elseif ( $mode === 'profile' ) {
2018-08-20 00:26:05 -04:00
$items = conversation_add_children ( $items , false , $order , $uid );
2019-11-02 21:19:42 -04:00
$profile_owner = $a -> profile [ 'uid' ];
2012-09-10 03:19:08 -04:00
2017-04-04 13:46:56 -04:00
if ( ! $update ) {
2018-01-01 15:27:33 -05:00
$tab = 'posts' ;
2018-11-30 09:06:22 -05:00
if ( ! empty ( $_GET [ 'tab' ])) {
2018-11-09 13:29:42 -05:00
$tab = Strings :: escapeTags ( trim ( $_GET [ 'tab' ]));
2018-01-01 15:27:33 -05:00
}
2017-04-04 13:46:56 -04:00
if ( $tab === 'posts' ) {
2017-04-08 13:05:50 -04: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 11:41:33 -04:00
$live_update_div = '<div id="live-profile"></div>' . " \r \n "
2019-11-02 21:19:42 -04:00
. " <script> var profile_uid = " . $a -> profile [ 'uid' ]
2020-02-13 23:40:00 -05:00
. " ; var netargs = '?f='; </script> \r \n " ;
2012-10-09 11:41:33 -04:00
}
}
2017-04-08 13:05:50 -04:00
} elseif ( $mode === 'notes' ) {
2018-12-13 15:09:19 -05:00
$items = conversation_add_children ( $items , false , $order , local_user ());
2012-09-10 04:36:30 -04:00
$profile_owner = local_user ();
2018-07-30 22:06:22 -04:00
2017-04-04 13:46:56 -04:00
if ( ! $update ) {
2012-10-09 11:41:33 -04:00
$live_update_div = '<div id="live-notes"></div>' . " \r \n "
2015-10-07 18:25:55 -04:00
. " <script> var profile_uid = " . local_user ()
2020-02-13 23:40:00 -05:00
. " ; var netargs = '/?f='; </script> \r \n " ;
2012-10-09 11:41:33 -04:00
}
2017-04-08 13:05:50 -04:00
} elseif ( $mode === 'display' ) {
2018-08-20 16:32:55 -04:00
$items = conversation_add_children ( $items , false , $order , $uid );
2012-09-10 04:36:30 -04:00
$profile_owner = $a -> profile [ 'uid' ];
2018-07-30 22:06:22 -04:00
2017-04-04 13:46:56 -04:00
if ( ! $update ) {
2012-11-01 20:31:50 -04:00
$live_update_div = '<div id="live-display"></div>' . " \r \n "
2019-05-26 16:15:38 -04:00
. " <script> var profile_uid = " . Session :: get ( 'uid' , 0 ) . " ; "
2020-02-13 23:40:00 -05:00
. " </script> " ;
2012-11-01 20:31:50 -04:00
}
2017-04-08 13:05:50 -04:00
} elseif ( $mode === 'community' ) {
2018-05-26 16:03:30 -04:00
$items = conversation_add_children ( $items , true , $order , $uid );
2012-09-10 04:36:30 -04:00
$profile_owner = 0 ;
2018-07-30 22:06:22 -04:00
2018-01-04 10:46:56 -05:00
if ( ! $update ) {
$live_update_div = '<div id="live-community"></div>' . " \r \n "
2019-12-15 19:33:13 -05:00
. " <script> var profile_uid = -1; var netargs = ' " . substr ( DI :: args () -> getCommand (), 10 )
2020-09-26 14:01:10 -04:00
. '?f='
. ( ! empty ( $_GET [ 'no_sharer' ]) ? '&no_sharer=' . rawurlencode ( $_GET [ 'no_sharer' ]) : '' )
. " '; </script> \r \n " ;
2018-01-04 10:46:56 -05:00
}
2018-08-25 09:48:00 -04:00
} elseif ( $mode === 'contacts' ) {
2018-11-25 13:50:41 -05:00
$items = conversation_add_children ( $items , false , $order , $uid );
2018-08-25 09:48:00 -04:00
$profile_owner = 0 ;
if ( ! $update ) {
2020-10-06 14:47:23 -04: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-13 23:40:00 -05:00
. " /?f='; </script> \r \n " ;
2018-08-25 09:48:00 -04:00
}
2017-04-08 13:05:50 -04:00
} elseif ( $mode === 'search' ) {
2012-10-09 11:41:33 -04:00
$live_update_div = '<div id="live-search"></div>' . " \r \n " ;
2012-09-10 04:36:30 -04:00
}
2012-09-10 03:19:08 -04:00
2012-09-10 04:36:30 -04:00
$page_dropping = (( local_user () && local_user () == $profile_owner ) ? true : false );
2012-09-10 03:19:08 -04:00
2018-01-03 21:12:19 -05:00
if ( ! $update ) {
2019-12-15 19:30:34 -05:00
$_SESSION [ 'return_path' ] = DI :: args () -> getQueryString ();
2017-04-08 13:05:50 -04:00
}
2012-03-15 00:20:20 -04:00
2018-01-15 08:05:12 -05:00
$cb = [ 'items' => $items , 'mode' => $mode , 'update' => $update , 'preview' => $preview ];
2020-11-21 11:08:44 -05:00
Hook :: callAll ( 'conversation_start' , $cb );
2012-01-09 23:03:00 -05:00
2012-09-10 04:36:30 -04:00
$items = $cb [ 'items' ];
2011-04-11 02:01:38 -04:00
2018-01-15 08:05:12 -05:00
$conv_responses = [
2020-02-22 20:41:12 -05:00
'like' => [],
'dislike' => [],
'attendyes' => [],
'attendno' => [],
2020-02-26 15:53:46 -05:00
'attendmaybe' => [],
'announce' => [],
2018-01-15 08:05:12 -05:00
];
2011-05-20 04:15:02 -04:00
2020-02-19 22:20:26 -05:00
if ( DI :: pConfig () -> get ( local_user (), 'system' , 'hide_dislike' )) {
unset ( $conv_responses [ 'dislike' ]);
}
2012-09-10 04:36:30 -04:00
// array with html for each thread (parent+comments)
2018-01-15 08:05:12 -05:00
$threads = [];
2012-09-10 04:36:30 -04:00
$threadsid = - 1 ;
2011-07-05 00:52:21 -04:00
2018-10-31 10:44:06 -04:00
$page_template = Renderer :: getMarkupTemplate ( " conversation.tpl " );
2012-08-10 02:01:37 -04:00
2018-07-30 22:06:22 -04:00
if ( ! empty ( $items )) {
2018-08-25 09:48:00 -04:00
if ( in_array ( $mode , [ 'community' , 'contacts' ])) {
2018-01-31 18:22:41 -05:00
$writable = true ;
2017-12-20 05:16:25 -05:00
} else {
2019-07-01 14:00:55 -04:00
$writable = ( $items [ 0 ][ 'uid' ] == 0 ) && in_array ( $items [ 0 ][ 'network' ], Protocol :: FEDERATED );
2017-12-20 05:16:25 -05:00
}
2012-08-10 02:01:37 -04:00
2018-01-04 09:39:47 -05:00
if ( ! local_user ()) {
$writable = false ;
}
2020-10-13 00:23:17 -04:00
if ( in_array ( $mode , [ 'filed' , 'search' , 'contact-posts' ])) {
2011-04-11 02:01:38 -04:00
2017-04-08 14:00:54 -04: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 00:21:16 -04:00
2012-09-10 04:36:30 -04:00
$tpl = 'search_item.tpl' ;
2017-04-04 13:46:56 -04:00
foreach ( $items as $item ) {
2014-01-05 10:22:42 -05:00
2018-02-27 04:29:11 -05:00
if ( ! visible_activity ( $item )) {
continue ;
}
2018-08-10 00:27:52 -04:00
if ( in_array ( $item [ 'author-id' ], $blocklist )) {
continue ;
2013-04-29 00:02:53 -04:00
}
2013-09-15 04:40:58 -04:00
2012-09-10 04:36:30 -04:00
$threadsid ++ ;
// prevent private email from leaking.
2018-08-11 16:40:44 -04:00
if ( $item [ 'network' ] === Protocol :: MAIL && local_user () != $item [ 'uid' ]) {
2017-04-08 13:05:50 -04:00
continue ;
}
2012-09-10 04:36:30 -04:00
2018-06-24 06:48:29 -04:00
$profile_name = $item [ 'author-name' ];
if ( ! empty ( $item [ 'author-link' ]) && empty ( $item [ 'author-name' ])) {
2012-09-10 04:36:30 -04:00
$profile_name = $item [ 'author-link' ];
2017-04-08 13:05:50 -04:00
}
2012-09-10 04:36:30 -04:00
2020-05-01 02:01:22 -04:00
$tags = Tag :: populateFromItem ( $item );
2013-01-13 11:13:01 -05:00
2018-07-02 01:41:55 -04:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
2019-02-21 21:29:22 -05:00
$profile_link = Contact :: magicLinkByContact ( $author );
2017-04-08 13:05:50 -04:00
2020-09-13 19:50:39 -04:00
$sparkle = '' ;
2018-06-01 02:46:34 -04:00
if ( strpos ( $profile_link , 'redir/' ) === 0 ) {
2012-09-10 04:36:30 -04:00
$sparkle = ' sparkle' ;
2017-04-08 13:05:50 -04:00
}
2012-09-10 04:36:30 -04:00
2018-01-15 08:05:12 -05:00
$locate = [ 'location' => $item [ 'location' ], 'coord' => $item [ 'coord' ], 'html' => '' ];
2020-11-21 11:08:44 -05:00
Hook :: callAll ( 'render_location' , $locate );
2020-09-13 19:33:57 -04:00
$location_html = $locate [ 'html' ] ? : Strings :: escapeHtml ( $locate [ 'location' ] ? : $locate [ 'coord' ] ? : '' );
2012-09-10 04:36:30 -04:00
localize_item ( $item );
2020-10-13 00:23:17 -04:00
if ( $mode === 'filed' ) {
2012-09-10 04:36:30 -04:00
$dropping = true ;
2017-04-08 13:05:50 -04:00
} else {
2012-09-10 04:36:30 -04:00
$dropping = false ;
2017-04-08 13:05:50 -04:00
}
2012-09-10 04:36:30 -04:00
2018-01-15 08:05:12 -05:00
$drop = [
2012-09-10 04:36:30 -04:00
'dropping' => $dropping ,
2012-09-25 22:10:46 -04:00
'pagedrop' => $page_dropping ,
2020-01-18 14:52:34 -05:00
'select' => DI :: l10n () -> t ( 'Select' ),
'delete' => DI :: l10n () -> t ( 'Delete' ),
2018-01-15 08:05:12 -05:00
];
2012-09-10 04:36:30 -04:00
2020-02-13 20:42:15 -05:00
$likebuttons = [
2020-10-11 04:49:47 -04:00
'like' => null ,
'dislike' => null ,
'share' => null ,
'announce' => null ,
2020-02-13 20:42:15 -05:00
];
2012-09-10 04:36:30 -04:00
2020-02-19 22:20:26 -05:00
if ( DI :: pConfig () -> get ( local_user (), 'system' , 'hide_dislike' )) {
unset ( $likebuttons [ 'dislike' ]);
}
2020-09-13 19:37:43 -04:00
$body_html = Item :: prepareBody ( $item , true , $preview );
2012-09-23 22:22:48 -04:00
2019-12-15 17:28:01 -05:00
list ( $categories , $folders ) = DI :: contentItem () -> determineCategoriesTerms ( $item );
2012-09-25 22:10:46 -04:00
2020-01-18 10:50:57 -05:00
if ( ! empty ( $item [ 'content-warning' ]) && DI :: pConfig () -> get ( local_user (), 'system' , 'disable_cw' , false )) {
2019-02-22 23:03:32 -05:00
$title = ucfirst ( $item [ 'content-warning' ]);
2018-04-04 22:50:39 -04:00
} else {
2019-02-22 23:03:32 -05:00
$title = $item [ 'title' ];
2018-04-04 22:50:39 -04:00
}
2018-01-15 08:05:12 -05:00
$tmp_item = [
2012-09-10 04:36:30 -04:00
'template' => $tpl ,
2018-07-10 08:27:56 -04:00
'id' => ( $preview ? 'P0' : $item [ 'id' ]),
'guid' => ( $preview ? 'Q0' : $item [ 'guid' ]),
2020-09-30 15:14:13 -04:00
'commented' => $item [ 'commented' ],
'received' => $item [ 'received' ],
'created_date' => $item [ 'created' ],
'uriid' => $item [ 'uri-id' ],
2018-06-18 16:36:34 -04:00
'network' => $item [ 'network' ],
2019-12-27 12:24:29 -05:00
'network_name' => ContactSelector :: networkToName ( $item [ 'author-network' ], $item [ 'author-link' ], $item [ 'network' ]),
2019-08-28 02:38:35 -04:00
'network_icon' => ContactSelector :: networkToIcon ( $item [ 'network' ], $item [ 'author-link' ]),
2020-01-18 14:52:34 -05:00
'linktitle' => DI :: l10n () -> t ( 'View %s\'s profile @ %s' , $profile_name , $item [ 'author-link' ]),
2012-09-10 04:36:30 -04:00
'profile_url' => $profile_link ,
2020-09-13 19:40:59 -04:00
'item_photo_menu_html' => item_photo_menu ( $item ),
2019-02-22 23:03:32 -05:00
'name' => $profile_name ,
2012-09-10 04:36:30 -04:00
'sparkle' => $sparkle ,
2020-09-13 19:50:39 -04:00
'lock' => false ,
2020-07-28 15:30:55 -04:00
'thumb' => DI :: baseUrl () -> remove ( $item [ 'author-avatar' ]),
2019-02-22 23:03:32 -05:00
'title' => $title ,
2020-09-13 19:37:43 -04:00
'body_html' => $body_html ,
2019-02-22 23:03:32 -05:00
'tags' => $tags [ 'tags' ],
'hashtags' => $tags [ 'hashtags' ],
'mentions' => $tags [ 'mentions' ],
'implicit_mentions' => $tags [ 'implicit_mentions' ],
2020-01-18 14:52:34 -05:00
'txt_cats' => DI :: l10n () -> t ( 'Categories:' ),
'txt_folders' => DI :: l10n () -> t ( 'Filed under:' ),
2012-09-23 20:16:37 -04:00
'has_cats' => (( count ( $categories )) ? 'true' : '' ),
'has_folders' => (( count ( $folders )) ? 'true' : '' ),
2012-09-19 11:38:32 -04:00
'categories' => $categories ,
'folders' => $folders ,
2020-09-13 19:37:43 -04:00
'text' => strip_tags ( $body_html ),
2018-01-26 21:38:34 -05:00
'localtime' => DateTimeFormat :: local ( $item [ 'created' ], 'r' ),
2020-11-21 11:08:44 -05:00
'ago' => (( $item [ 'app' ]) ? DI :: l10n () -> t ( '%s from %s' , Temporal :: getRelativeDate ( $item [ 'created' ]), $item [ 'app' ]) : Temporal :: getRelativeDate ( $item [ 'created' ])),
2020-09-13 19:33:57 -04:00
'location_html' => $location_html ,
2012-09-10 04:36:30 -04:00
'indent' => '' ,
2020-09-13 19:50:39 -04:00
'owner_name' => '' ,
'owner_url' => '' ,
2020-07-28 15:30:55 -04:00
'owner_photo' => DI :: baseUrl () -> remove ( $item [ 'owner-avatar' ]),
2018-11-07 07:19:39 -05:00
'plink' => Item :: getPlink ( $item ),
2012-09-10 04:36:30 -04:00
'edpost' => false ,
2020-09-13 19:50:39 -04:00
'isstarred' => 'unstarred' ,
'star' => false ,
2012-09-10 04:36:30 -04:00
'drop' => $drop ,
'vote' => $likebuttons ,
2020-09-13 19:44:11 -04:00
'like_html' => '' ,
'dislike_html' => '' ,
2020-09-13 19:43:42 -04:00
'comment_html' => '' ,
2020-01-18 14:52:34 -05:00
'conv' => (( $preview ) ? '' : [ 'href' => 'display/' . $item [ 'guid' ], 'title' => DI :: l10n () -> t ( 'View in context' )]),
2012-09-10 04:36:30 -04:00
'previewing' => $previewing ,
2020-01-18 14:52:34 -05:00
'wait' => DI :: l10n () -> t ( 'Please wait' ),
2012-09-10 04:36:30 -04:00
'thread_level' => 1 ,
2018-01-15 08:05:12 -05:00
];
2012-09-10 04:36:30 -04:00
2018-01-15 08:05:12 -05:00
$arr = [ 'item' => $item , 'output' => $tmp_item ];
2018-12-26 01:06:24 -05:00
Hook :: callAll ( 'display_item' , $arr );
2012-09-10 04:36:30 -04:00
2018-07-10 08:27:56 -04:00
$threads [ $threadsid ][ 'id' ] = $item [ 'id' ];
2018-06-18 16:36:34 -04:00
$threads [ $threadsid ][ 'network' ] = $item [ 'network' ];
2018-01-15 08:05:12 -05:00
$threads [ $threadsid ][ 'items' ] = [ $arr [ 'output' ]];
2012-09-10 04:36:30 -04:00
}
2017-04-08 13:05:50 -04:00
} else {
2012-09-10 04:36:30 -04:00
// Normal View
2018-10-31 10:44:06 -04:00
$page_template = Renderer :: getMarkupTemplate ( " threaded_conversation.tpl " );
2012-09-10 04:36:30 -04:00
2017-12-19 12:15:56 -05:00
$conv = new Thread ( $mode , $preview , $writable );
2012-09-10 04:36:30 -04:00
2017-04-08 13:05:50 -04: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 13:46:56 -04:00
foreach ( $items as $item ) {
2018-08-10 00:27:52 -04:00
if ( in_array ( $item [ 'author-id' ], $blocklist )) {
continue ;
2013-04-29 00:02:53 -04:00
}
2013-09-15 04:40:58 -04:00
2012-09-10 04:36:30 -04:00
// Can we put this after the visibility check?
2015-06-03 14:57:30 -04:00
builtin_activity_puller ( $item , $conv_responses );
2012-09-10 04:36:30 -04:00
// Only add what is visible
2018-08-11 16:40:44 -04:00
if ( $item [ 'network' ] === Protocol :: MAIL && local_user () != $item [ 'uid' ]) {
2012-09-10 04:36:30 -04:00
continue ;
}
2017-04-08 13:05:50 -04:00
2018-02-27 04:29:11 -05:00
if ( ! visible_activity ( $item )) {
2012-09-10 04:36:30 -04:00
continue ;
}
2018-07-08 09:52:11 -04:00
/// @todo Check if this call is needed or not
2018-07-08 08:01:36 -04:00
$arr = [ 'item' => $item ];
2018-12-26 01:06:24 -05:00
Hook :: callAll ( 'display_item' , $arr );
2013-01-22 02:11:13 -05:00
2012-09-25 22:10:46 -04:00
$item [ 'pagedrop' ] = $page_dropping ;
2020-05-27 08:19:06 -04:00
if ( $item [ 'gravity' ] == GRAVITY_PARENT ) {
2021-01-16 07:35:44 -05:00
$item_object = new PostObject ( $item );
2017-12-07 23:33:36 -05:00
$conv -> addParent ( $item_object );
2012-09-10 04:36:30 -04:00
}
}
2017-11-19 14:15:25 -05:00
$threads = $conv -> getTemplateData ( $conv_responses );
2017-04-04 13:46:56 -04:00
if ( ! $threads ) {
2018-10-30 09:58:45 -04:00
Logger :: log ( '[ERROR] conversation : Failed to get template data.' , Logger :: DEBUG );
2018-01-15 08:05:12 -05:00
$threads = [];
2012-09-10 04:36:30 -04:00
}
}
}
2018-10-31 10:35:50 -04:00
$o = Renderer :: replaceMacros ( $page_template , [
2019-12-30 17:00:08 -05:00
'$baseurl' => DI :: baseUrl () -> get ( $ssl_state ),
2019-12-15 19:30:34 -05:00
'$return_path' => DI :: args () -> getQueryString (),
2012-10-09 11:41:33 -04:00
'$live_update' => $live_update_div ,
2020-01-18 14:52:34 -05:00
'$remove' => DI :: l10n () -> t ( 'remove' ),
2012-09-10 04:36:30 -04:00
'$mode' => $mode ,
2020-10-20 16:43:51 -04:00
'$update' => $update ,
2012-09-10 04:36:30 -04:00
'$user' => $a -> user ,
'$threads' => $threads ,
2020-01-18 14:52:34 -05:00
'$dropping' => ( $page_dropping ? DI :: l10n () -> t ( 'Delete Selected Items' ) : False ),
2018-01-15 08:05:12 -05:00
]);
2012-09-10 04:36:30 -04:00
return $o ;
2017-12-11 23:52:33 -05:00
}
2011-04-12 20:58:16 -04:00
2019-04-03 14:51:50 -04:00
/**
* Fetch all comments from a query . Additionally set the newest resharer as thread owner .
*
2020-01-26 14:14:36 -05:00
* @ param mixed $thread_items Database statement with thread posts
2019-11-08 01:52:44 -05:00
* @ param boolean $pinned Is the item pinned ?
2020-11-28 01:23:17 -05:00
* @ param array $activity Contact data of the resharer
2019-11-08 01:52:44 -05:00
*
2019-04-03 14:51:50 -04:00
* @ return array items with parents and comments
*/
2020-11-28 01:23:17 -05:00
function conversation_fetch_comments ( $thread_items , bool $pinned , array $activity ) {
2019-04-03 14:51:50 -04:00
$comments = [];
while ( $row = Item :: fetch ( $thread_items )) {
2020-11-28 01:23:17 -05:00
if ( ! empty ( $activity )) {
2020-11-03 14:24:47 -05:00
if (( $row [ 'gravity' ] == GRAVITY_PARENT )) {
$row [ 'post-type' ] = Item :: PT_ANNOUNCEMENT ;
2020-11-28 01:23:17 -05:00
$row = array_merge ( $row , $activity );
2020-11-28 01:29:20 -05:00
$contact = Contact :: getById ( $activity [ 'causer-id' ], [ 'url' , 'name' , 'thumb' ]);
2020-11-03 14:24:47 -05: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 01:23:17 -05:00
( $row [ 'author-id' ] == $activity [ 'causer-id' ])) {
2020-11-03 14:24:47 -05:00
continue ;
}
}
2020-09-22 01:36:01 -04:00
$name = $row [ 'causer-contact-type' ] == Contact :: TYPE_RELAY ? $row [ 'causer-link' ] : $row [ 'causer-name' ];
2020-08-23 09:26:23 -04:00
2020-09-13 10:15:28 -04:00
switch ( $row [ 'post-type' ]) {
case Item :: PT_TO :
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'to' )];
break ;
case Item :: PT_CC :
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'cc' )];
break ;
case Item :: PT_BTO :
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'bto' )];
break ;
case Item :: PT_BCC :
$row [ 'direction' ] = [ 'direction' => 7 , 'title' => DI :: l10n () -> t ( 'You had been addressed (%s).' , 'bcc' )];
break ;
case Item :: PT_FOLLOWER :
2020-09-09 14:03:14 -04:00
$row [ 'direction' ] = [ 'direction' => 6 , 'title' => DI :: l10n () -> t ( 'You are following %s.' , $row [ 'author-name' ])];
2020-09-13 10:15:28 -04:00
break ;
case Item :: PT_TAG :
$row [ 'direction' ] = [ 'direction' => 4 , 'title' => DI :: l10n () -> t ( 'Tagged' )];
break ;
case Item :: PT_ANNOUNCEMENT :
2020-09-30 13:30:26 -04:00
if ( ! empty ( $row [ 'causer-id' ]) && DI :: pConfig () -> get ( local_user (), 'system' , 'display_resharer' )) {
2020-11-10 14:43:12 -05:00
$row [ 'owner-id' ] = $row [ 'causer-id' ];
2020-09-22 01:36:01 -04: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' ])) {
2020-12-22 01:01:43 -05:00
$row [ 'reshared' ] = DI :: l10n () -> t ( '%s reshared this.' , '<a href="' . htmlentities ( Contact :: magicLinkById ( $row [ 'causer-id' ])) . '">' . htmlentities ( $name ) . '</a>' );
2020-09-22 01:36:01 -04:00
}
$row [ 'direction' ] = [ 'direction' => 3 , 'title' => ( empty ( $row [ 'causer-id' ]) ? DI :: l10n () -> t ( 'Reshared' ) : DI :: l10n () -> t ( 'Reshared by %s' , $name ))];
2020-09-13 10:15:28 -04:00
break ;
case Item :: PT_COMMENT :
$row [ 'direction' ] = [ 'direction' => 5 , 'title' => DI :: l10n () -> t ( '%s is participating in this thread.' , $row [ 'author-name' ])];
break ;
case Item :: PT_STORED :
$row [ 'direction' ] = [ 'direction' => 8 , 'title' => DI :: l10n () -> t ( 'Stored' )];
break ;
2020-09-14 13:48:57 -04:00
case Item :: PT_GLOBAL :
$row [ 'direction' ] = [ 'direction' => 9 , 'title' => DI :: l10n () -> t ( 'Global' )];
break ;
2020-09-21 08:31:20 -04:00
case Item :: PT_RELAY :
2020-09-22 01:36:01 -04:00
$row [ 'direction' ] = [ 'direction' => 10 , 'title' => ( empty ( $row [ 'causer-id' ]) ? DI :: l10n () -> t ( 'Relayed' ) : DI :: l10n () -> t ( 'Relayed by %s.' , $name ))];
2020-09-21 08:31:20 -04:00
break ;
2020-09-21 11:17:33 -04:00
case Item :: PT_FETCHED :
2020-09-22 01:36:01 -04:00
$row [ 'direction' ] = [ 'direction' => 2 , 'title' => ( empty ( $row [ 'causer-id' ]) ? DI :: l10n () -> t ( 'Fetched' ) : DI :: l10n () -> t ( 'Fetched because of %s' , $name ))];
2020-09-21 11:17:33 -04:00
break ;
}
2020-09-12 13:45:04 -04:00
2019-11-08 01:52:44 -05:00
if ( $row [ 'gravity' ] == GRAVITY_PARENT ) {
$row [ 'pinned' ] = $pinned ;
}
2019-04-03 14:51:50 -04:00
$comments [] = $row ;
}
DBA :: close ( $thread_items );
return $comments ;
}
2018-01-04 05:02:56 -05:00
/**
2020-01-19 01:05:23 -05:00
* Add comments to top level entries that had been fetched before
2018-01-04 05:02:56 -05: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 10:24:06 -05:00
* @ param $block_authors
* @ param $order
* @ param $uid
2018-01-04 05:02:56 -05:00
* @ return array items with parents and comments
2019-01-07 10:24:06 -05:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2018-01-04 05:02:56 -05:00
*/
2018-07-13 15:47:14 -04:00
function conversation_add_children ( array $parents , $block_authors , $order , $uid ) {
2020-06-16 02:49:53 -04: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 17:15:57 -05:00
2020-08-10 04:26:09 -04:00
$params = [ 'order' => [ 'gravity' , 'uid' , 'commented' => true ]];
2018-06-10 03:26:37 -04:00
2018-02-26 17:15:57 -05:00
if ( $max_comments > 0 ) {
2018-06-10 03:26:37 -04:00
$params [ 'limit' ] = $max_comments ;
2018-02-26 17:15:57 -05:00
}
2018-01-04 05:02:56 -05:00
2018-01-15 08:05:12 -05:00
$items = [];
2018-01-04 05:02:56 -05:00
2020-05-07 14:39:39 -04:00
foreach ( $parents AS $parent ) {
2020-11-03 14:24:47 -05:00
if ( ! empty ( $parent [ 'thr-parent-id' ]) && ! empty ( $parent [ 'gravity' ]) && ( $parent [ 'gravity' ] == GRAVITY_ACTIVITY )) {
$condition = [ " `item`.`parent-uri-id` = ? AND `item`.`uid` IN (0, ?) AND (`vid` != ? OR `vid` IS NULL) " ,
$parent [ 'thr-parent-id' ], $uid , Verb :: getID ( Activity :: FOLLOW )];
2020-11-28 01:23:17 -05:00
if ( ! empty ( $parent [ 'author-id' ])) {
$activity = [ 'causer-id' => $parent [ 'author-id' ]];
foreach ([ 'commented' , 'received' , 'created' ] as $orderfields ) {
if ( ! empty ( $parent [ $orderfields ])) {
$activity [ $orderfields ] = $parent [ $orderfields ];
}
}
}
2020-11-03 14:24:47 -05:00
} else {
$condition = [ " `item`.`parent-uri` = ? AND `item`.`uid` IN (0, ?) AND (`vid` != ? OR `vid` IS NULL) " ,
$parent [ 'uri' ], $uid , Verb :: getID ( Activity :: FOLLOW )];
2020-11-28 01:23:17 -05:00
$activity = [];
2020-11-03 15:30:59 -05:00
}
2020-11-28 01:23:17 -05:00
$items = conversation_fetch_items ( $parent , $items , $condition , $block_authors , $params , $activity );
2018-01-04 05:02:56 -05:00
}
foreach ( $items as $index => $item ) {
if ( $item [ 'uid' ] == 0 ) {
2019-07-01 14:00:55 -04:00
$items [ $index ][ 'writable' ] = in_array ( $item [ 'network' ], Protocol :: FEDERATED );
2018-01-04 05:02:56 -05:00
}
}
2018-02-26 01:38:27 -05:00
$items = conv_sort ( $items , $order );
2018-01-04 05:02:56 -05:00
return $items ;
}
2020-05-07 14:39:39 -04:00
/**
* Fetch conversation items
*
2020-11-03 15:30:59 -05: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 01:23:17 -05:00
* @ param array $activity Contact data of the resharer
2020-05-07 14:39:39 -04:00
* @ return array
*/
2020-11-28 01:23:17 -05:00
function conversation_fetch_items ( array $parent , array $items , array $condition , bool $block_authors , array $params , array $activity ) {
2020-05-07 14:39:39 -04:00
if ( $block_authors ) {
2020-05-28 02:08:03 -04:00
$condition [ 0 ] .= " AND NOT `author`.`hidden` " ;
2020-05-07 14:39:39 -04:00
}
2021-01-15 23:11:28 -05:00
$thread_items = Item :: selectForUser ( local_user (), array_merge ( Item :: DISPLAY_FIELDLIST , [ 'pinned' , 'contact-uid' , 'gravity' , 'post-type' ]), $condition , $params );
2020-05-07 14:39:39 -04:00
2020-11-28 01:23:17 -05:00
$comments = conversation_fetch_comments ( $thread_items , $parent [ 'pinned' ] ? ? false , $activity );
2020-05-07 14:39:39 -04:00
if ( count ( $comments ) != 0 ) {
$items = array_merge ( $items , $comments );
}
return $items ;
}
2017-04-08 13:05:50 -04:00
function item_photo_menu ( $item ) {
2016-10-22 22:49:12 -04:00
$sub_link = '' ;
$poke_link = '' ;
$contact_url = '' ;
$pm_url = '' ;
$status_link = '' ;
$photos_link = '' ;
$posts_link = '' ;
2019-03-11 16:42:32 -04:00
$block_link = '' ;
$ignore_link = '' ;
2012-09-10 04:36:30 -04:00
2020-05-28 12:02:36 -04:00
if ( local_user () && local_user () == $item [ 'uid' ] && $item [ 'gravity' ] == GRAVITY_PARENT && ! $item [ 'self' ]) {
2012-09-27 22:53:55 -04:00
$sub_link = 'javascript:dosubthread(' . $item [ 'id' ] . '); return false;' ;
}
2018-07-02 01:41:55 -04:00
$author = [ 'uid' => 0 , 'id' => $item [ 'author-id' ],
'network' => $item [ 'author-network' ], 'url' => $item [ 'author-link' ]];
2019-02-26 04:19:08 -05:00
$profile_link = Contact :: magicLinkByContact ( $author , $item [ 'author-link' ]);
2018-06-01 02:46:34 -04:00
$sparkle = ( strpos ( $profile_link , 'redir/' ) === 0 );
2012-09-10 04:36:30 -04:00
2016-06-05 14:01:38 -04:00
$cid = 0 ;
2020-07-15 17:08:42 -04:00
$pcid = Contact :: getIdForURL ( $item [ 'author-link' ], 0 , false );
2016-10-22 22:49:12 -04:00
$network = '' ;
2016-06-05 14:01:38 -04:00
$rel = 0 ;
2018-11-08 11:28:29 -05:00
$condition = [ 'uid' => local_user (), 'nurl' => Strings :: normaliseLink ( $item [ 'author-link' ])];
2018-07-20 08:19:26 -04:00
$contact = DBA :: selectFirst ( 'contact' , [ 'id' , 'network' , 'rel' ], $condition );
2018-07-21 08:46:04 -04:00
if ( DBA :: isResult ( $contact )) {
2018-01-11 03:26:30 -05:00
$cid = $contact [ 'id' ];
$network = $contact [ 'network' ];
$rel = $contact [ 'rel' ];
2016-06-05 14:01:38 -04:00
}
2017-04-04 13:46:56 -04:00
if ( $sparkle ) {
2020-01-27 19:21:18 -05:00
$status_link = $profile_link . '/status' ;
2019-02-26 04:19:08 -05:00
$photos_link = str_replace ( '/profile/' , '/photos/' , $profile_link );
2020-01-27 19:21:18 -05:00
$profile_link = $profile_link . '/profile' ;
2016-10-22 22:49:12 -04:00
}
2012-09-10 04:36:30 -04:00
2019-03-11 16:42:32 -04:00
if ( ! empty ( $pcid )) {
$contact_url = 'contact/' . $pcid ;
2020-04-20 11:42:27 -04:00
$posts_link = $contact_url . '/posts' ;
$block_link = $contact_url . '/block' ;
$ignore_link = $contact_url . '/ignore' ;
2019-03-11 16:42:32 -04:00
}
2016-10-22 22:49:12 -04:00
if ( $cid && ! $item [ 'self' ]) {
2018-10-17 07:49:27 -04:00
$contact_url = 'contact/' . $cid ;
2020-04-20 11:42:27 -04:00
$poke_link = $contact_url . '/poke' ;
$posts_link = $contact_url . '/posts' ;
2012-09-10 04:36:30 -04:00
2019-07-01 14:00:55 -04:00
if ( in_array ( $network , [ Protocol :: ACTIVITYPUB , Protocol :: DFRN , Protocol :: DIASPORA ])) {
2016-10-22 22:49:12 -04:00
$pm_url = 'message/new/' . $cid ;
}
2012-09-10 04:36:30 -04:00
}
2015-10-10 10:23:20 -04:00
if ( local_user ()) {
2018-01-15 08:05:12 -05:00
$menu = [
2020-01-18 14:52:34 -05: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 08:05:12 -05:00
];
2015-10-10 10:23:20 -04:00
2020-10-04 14:52:28 -04:00
if ( ! empty ( $item [ 'language' ])) {
$menu [ DI :: l10n () -> t ( 'Languages' )] = 'javascript:alert(\'' . Item :: getLanguageMessage ( $item ) . '\');' ;
}
2018-08-11 16:40:44 -04:00
if ( $network == Protocol :: DFRN ) {
2020-01-18 14:52:34 -05:00
$menu [ DI :: l10n () -> t ( " Poke " )] = $poke_link ;
2016-10-22 22:49:12 -04:00
}
2015-10-10 10:23:20 -04:00
2018-07-24 22:53:46 -04:00
if ((( $cid == 0 ) || ( $rel == Contact :: FOLLOWER )) &&
2019-07-01 14:00:55 -04:00
in_array ( $item [ 'network' ], Protocol :: FEDERATED )) {
2020-10-19 23:49:58 -04:00
$menu [ DI :: l10n () -> t ( 'Connect/Follow' )] = 'follow?url=' . urlencode ( $item [ 'author-link' ]) . '&auto=1' ;
2016-10-22 22:49:12 -04:00
}
} else {
2020-01-18 14:52:34 -05:00
$menu = [ DI :: l10n () -> t ( 'View Profile' ) => $item [ 'author-link' ]];
2016-10-22 22:49:12 -04:00
}
2012-09-10 04:36:30 -04:00
2018-01-15 08:05:12 -05:00
$args = [ 'item' => $item , 'menu' => $menu ];
2012-09-10 04:36:30 -04:00
2018-12-26 01:06:24 -05:00
Hook :: callAll ( 'item_photo_menu' , $args );
2012-09-10 04:36:30 -04:00
$menu = $args [ 'menu' ];
2016-10-22 22:49:12 -04: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 ;
} elseif ( $v != '' ) {
$o .= '<li role="menuitem"><a href="' . $v . '">' . $k . '</a></li>' . PHP_EOL ;
2012-09-27 22:53:55 -04:00
}
2012-09-10 04:36:30 -04:00
}
return $o ;
2017-08-09 17:12:41 -04:00
}
2011-04-12 20:58:16 -04:00
2015-06-03 14:57:30 -04:00
/**
2020-01-19 01:05:23 -05:00
* Checks item to see if it is one of the builtin activities ( like / dislike , event attendance , consensus items , etc . )
*
2015-06-03 14:57:30 -04:00
* Increments the count of each matching activity and adds a link to the author as needed .
*
2020-11-21 11:08:44 -05:00
* @ param array $activity
2015-06-03 14:57:30 -04:00
* @ param array & $conv_responses ( already created with builtin activity structure )
* @ return void
2019-01-07 10:24:06 -05:00
* @ throws ImagickException
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2015-06-03 14:57:30 -04:00
*/
2020-11-21 11:08:44 -05:00
function builtin_activity_puller ( array $activity , array & $conv_responses )
{
2017-04-04 13:46:56 -04:00
foreach ( $conv_responses as $mode => $v ) {
2015-06-03 14:57:30 -04:00
$sparkle = '' ;
2011-04-12 20:58:16 -04:00
2017-04-08 14:00:54 -04:00
switch ( $mode ) {
2015-06-03 14:57:30 -04:00
case 'like' :
2019-10-23 18:25:43 -04:00
$verb = Activity :: LIKE ;
2015-06-03 14:57:30 -04:00
break ;
case 'dislike' :
2019-10-23 18:25:43 -04:00
$verb = Activity :: DISLIKE ;
2015-06-03 14:57:30 -04:00
break ;
case 'attendyes' :
2019-10-23 18:25:43 -04:00
$verb = Activity :: ATTEND ;
2015-06-03 14:57:30 -04:00
break ;
case 'attendno' :
2019-10-23 18:25:43 -04:00
$verb = Activity :: ATTENDNO ;
2015-06-03 14:57:30 -04:00
break ;
case 'attendmaybe' :
2019-10-23 18:25:43 -04:00
$verb = Activity :: ATTENDMAYBE ;
2015-06-03 14:57:30 -04:00
break ;
2019-04-02 01:38:42 -04:00
case 'announce' :
2019-10-23 18:25:43 -04:00
$verb = Activity :: ANNOUNCE ;
2019-04-02 01:38:42 -04:00
break ;
2015-06-03 14:57:30 -04:00
default :
return ;
}
2012-09-10 04:36:30 -04:00
2020-11-21 11:08:44 -05: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-21 21:29:22 -05:00
$url = Contact :: magicLinkByContact ( $author );
2018-06-01 02:46:34 -04:00
if ( strpos ( $url , 'redir/' ) === 0 ) {
2015-06-03 14:57:30 -04:00
$sparkle = ' class="sparkle" ' ;
2017-04-08 13:05:50 -04:00
}
2015-11-18 17:57:53 -05:00
2020-11-21 11:08:44 -05:00
$link = '<a href="' . $url . '"' . $sparkle . '>' . htmlentities ( $activity [ 'author-name' ]) . '</a>' ;
2012-09-10 04:36:30 -04:00
2020-11-21 11:08:44 -05:00
if ( empty ( $activity [ 'thr-parent' ])) {
$activity [ 'thr-parent' ] = $activity [ 'parent-uri' ];
2017-04-08 13:05:50 -04:00
}
2012-09-10 04:36:30 -04:00
2020-09-28 07:36:47 -04:00
// Skip when the causer of the parent is the same than the author of the announce
2021-01-15 23:11:28 -05:00
if (( $verb == Activity :: ANNOUNCE ) && Post :: exists ([ 'uri' => $activity [ 'thr-parent' ],
2020-11-21 11:08:44 -05:00
'uid' => $activity [ 'uid' ], 'causer-id' => $activity [ 'author-id' ], 'gravity' => GRAVITY_PARENT ])) {
2020-09-28 10:13:14 -04:00
continue ;
2020-09-28 07:36:47 -04:00
}
2020-11-21 11:08:44 -05:00
if ( ! isset ( $conv_responses [ $mode ][ $activity [ 'thr-parent' ]])) {
$conv_responses [ $mode ][ $activity [ 'thr-parent' ]] = [
'links' => [],
'self' => 0 ,
];
2020-11-21 15:56:07 -05:00
} elseif ( in_array ( $link , $conv_responses [ $mode ][ $activity [ 'thr-parent' ]][ 'links' ])) {
// only list each unique author once
continue ;
2017-04-08 13:05:50 -04:00
}
2015-05-31 19:23:04 -04:00
2020-11-21 11:08:44 -05:00
if ( public_contact () == $activity [ 'author-id' ]) {
$conv_responses [ $mode ][ $activity [ 'thr-parent' ]][ 'self' ] = 1 ;
2017-03-06 05:07:17 -05:00
}
2016-09-24 11:50:23 -04:00
2020-11-21 11:08:44 -05:00
$conv_responses [ $mode ][ $activity [ 'thr-parent' ]][ 'links' ][] = $link ;
2015-06-03 14:57:30 -04:00
// there can only be one activity verb per item so if we found anything, we can stop looking
return ;
}
2012-09-10 04:36:30 -04:00
}
2017-12-11 23:52:33 -05:00
}
2011-04-12 20:58:16 -04:00
2017-04-08 13:05:50 -04:00
/**
2020-11-21 11:08:44 -05:00
* Format the activity text for an item / photo / video
2019-01-07 10:24:06 -05:00
*
2020-11-21 11:08:44 -05: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 12:25:58 -05:00
* @ return string formatted text
2019-01-07 10:24:06 -05:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2017-04-08 13:05:50 -04:00
*/
2020-11-21 11:08:44 -05:00
function format_activity ( array $links , $verb , $id ) {
2012-09-10 04:36:30 -04:00
$o = '' ;
2015-06-03 14:57:30 -04:00
$expanded = '' ;
2018-12-13 22:30:43 -05:00
$phrase = '' ;
2015-06-03 14:57:30 -04:00
2020-11-21 11:08:44 -05:00
$total = count ( $links );
if ( $total == 1 ) {
$likers = $links [ 0 ];
2012-12-22 14:57:29 -05:00
2015-10-14 13:48:57 -04: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 11:08:44 -05:00
switch ( $verb ) {
2015-10-14 13:48:57 -04:00
case 'like' :
2020-01-18 14:52:34 -05:00
$phrase = DI :: l10n () -> t ( '%s likes this.' , $likers );
2015-10-14 13:48:57 -04:00
break ;
case 'dislike' :
2020-01-18 14:52:34 -05:00
$phrase = DI :: l10n () -> t ( '%s doesn\'t like this.' , $likers );
2015-10-14 13:48:57 -04:00
break ;
case 'attendyes' :
2020-01-18 14:52:34 -05:00
$phrase = DI :: l10n () -> t ( '%s attends.' , $likers );
2015-10-14 13:48:57 -04:00
break ;
case 'attendno' :
2020-01-18 14:52:34 -05:00
$phrase = DI :: l10n () -> t ( '%s doesn\'t attend.' , $likers );
2015-10-14 13:48:57 -04:00
break ;
case 'attendmaybe' :
2020-01-18 14:52:34 -05:00
$phrase = DI :: l10n () -> t ( '%s attends maybe.' , $likers );
2015-10-14 13:48:57 -04:00
break ;
2019-04-02 01:38:42 -04:00
case 'announce' :
2020-01-18 14:52:34 -05:00
$phrase = DI :: l10n () -> t ( '%s reshared this.' , $likers );
2019-04-02 01:38:42 -04:00
break ;
2015-10-14 13:48:57 -04:00
}
2020-11-21 11:08:44 -05:00
} elseif ( $total > 1 ) {
2017-04-04 13:46:56 -04:00
if ( $total < MAX_LIKERS ) {
2020-11-21 11:08:44 -05:00
$likers = implode ( ', ' , array_slice ( $links , 0 , - 1 ));
$likers .= ' ' . DI :: l10n () -> t ( 'and' ) . ' ' . $links [ count ( $links ) - 1 ];
2019-01-07 12:51:48 -05:00
} else {
2020-11-21 11:08:44 -05:00
$likers = implode ( ', ' , array_slice ( $links , 0 , MAX_LIKERS - 1 ));
$likers .= ' ' . DI :: l10n () -> t ( 'and %d other people' , $total - MAX_LIKERS );
2012-11-06 10:43:19 -05:00
}
2015-06-03 14:57:30 -04:00
2020-11-21 11:08:44 -05:00
$spanatts = " class= \" fakelink \" onclick= \" openClose(' { $verb } list- $id '); \" " ;
2015-11-18 17:57:53 -05:00
2019-01-07 12:51:48 -05:00
$explikers = '' ;
2020-11-21 11:08:44 -05:00
switch ( $verb ) {
2015-06-03 14:57:30 -04:00
case 'like' :
2020-11-21 11:08:44 -05:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> like this' , $spanatts , $total );
2020-01-18 14:52:34 -05:00
$explikers = DI :: l10n () -> t ( '%s like this.' , $likers );
2015-06-03 14:57:30 -04:00
break ;
case 'dislike' :
2020-11-21 11:08:44 -05:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> don\'t like this' , $spanatts , $total );
2020-01-18 14:52:34 -05:00
$explikers = DI :: l10n () -> t ( '%s don\'t like this.' , $likers );
2015-06-03 14:57:30 -04:00
break ;
case 'attendyes' :
2020-11-21 11:08:44 -05:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> attend' , $spanatts , $total );
2020-01-18 14:52:34 -05:00
$explikers = DI :: l10n () -> t ( '%s attend.' , $likers );
2015-06-03 14:57:30 -04:00
break ;
case 'attendno' :
2020-11-21 11:08:44 -05:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> don\'t attend' , $spanatts , $total );
2020-01-18 14:52:34 -05:00
$explikers = DI :: l10n () -> t ( '%s don\'t attend.' , $likers );
2015-06-03 14:57:30 -04:00
break ;
case 'attendmaybe' :
2020-11-21 11:08:44 -05:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> attend maybe' , $spanatts , $total );
2020-01-18 14:52:34 -05:00
$explikers = DI :: l10n () -> t ( '%s attend maybe.' , $likers );
2015-06-03 14:57:30 -04:00
break ;
2019-04-02 01:38:42 -04:00
case 'announce' :
2020-11-21 11:08:44 -05:00
$phrase = DI :: l10n () -> t ( '<span %1$s>%2$d people</span> reshared this' , $spanatts , $total );
2020-01-18 14:52:34 -05:00
$explikers = DI :: l10n () -> t ( '%s reshared this.' , $likers );
2019-04-02 01:38:42 -04:00
break ;
2015-06-03 14:57:30 -04:00
}
2015-10-14 13:48:57 -04:00
2020-11-21 11:08:44 -05:00
$expanded .= " \t " . '<p class="wall-item-' . $verb . '-expanded" id="' . $verb . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</p>' ;
2012-09-10 04:36:30 -04:00
}
2015-06-03 14:57:30 -04:00
2018-10-31 10:44:06 -04:00
$o .= Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'voting_fakelink.tpl' ), [
2015-06-03 14:57:30 -04:00
'$phrase' => $phrase ,
2020-11-21 11:08:44 -05:00
'$type' => $verb ,
2015-06-03 14:57:30 -04:00
'$id' => $id
2018-01-15 08:05:12 -05:00
]);
2015-06-03 14:57:30 -04:00
$o .= $expanded ;
2012-09-10 04:36:30 -04:00
return $o ;
2017-12-11 23:52:33 -05:00
}
2011-04-20 08:48:12 -04:00
2018-01-01 15:27:33 -05:00
function status_editor ( App $a , $x , $notes_cid = 0 , $popup = false )
{
2012-09-10 04:36:30 -04:00
$o = '' ;
2018-11-30 09:06:22 -05:00
$geotag = ! empty ( $x [ 'allow_location' ]) ? Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'jot_geotag.tpl' ), []) : '' ;
2012-09-10 04:36:30 -04:00
2018-10-31 10:44:06 -04:00
$tpl = Renderer :: getMarkupTemplate ( 'jot-header.tpl' );
2019-12-30 14:02:09 -05:00
DI :: page ()[ 'htmlhead' ] .= Renderer :: replaceMacros ( $tpl , [
2018-01-01 15:27:33 -05:00
'$newpost' => 'true' ,
2019-12-30 17:00:08 -05:00
'$baseurl' => DI :: baseUrl () -> get ( true ),
2018-01-01 15:27:33 -05:00
'$geotag' => $geotag ,
'$nickname' => $x [ 'nickname' ],
2020-01-18 14:52:34 -05: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 03:25:55 -05:00
'$delitems' => DI :: l10n () -> t ( " Delete item \x28 s \x29 ? " ),
'$is_mobile' => DI :: mode () -> isMobile (),
2018-01-15 08:05:12 -05:00
]);
2012-09-10 04:36:30 -04:00
2015-06-27 09:11:18 -04:00
$jotplugins = '' ;
2018-12-26 01:06:24 -05:00
Hook :: callAll ( 'jot_tool' , $jotplugins );
2012-09-10 04:36:30 -04:00
2018-10-31 10:44:06 -04:00
$tpl = Renderer :: getMarkupTemplate ( " jot.tpl " );
2012-09-10 04:36:30 -04:00
2020-11-21 11:08:44 -05:00
$o .= Renderer :: replaceMacros ( $tpl , [
2020-01-18 14:52:34 -05:00
'$new_post' => DI :: l10n () -> t ( 'New Post' ),
2020-09-09 00:15:25 -04:00
'$return_path' => DI :: args () -> getQueryString (),
2018-01-01 15:27:33 -05:00
'$action' => 'item' ,
2020-01-18 14:52:34 -05:00
'$share' => ( $x [ 'button' ] ? ? '' ) ? : DI :: l10n () -> t ( 'Share' ),
2020-01-29 22:50:10 -05:00
'$loading' => DI :: l10n () -> t ( 'Loading...' ),
2020-01-18 14:52:34 -05: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' ),
'$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 08:43:59 -04:00
'$title' => $x [ 'title' ] ? ? '' ,
2020-01-18 14:52:34 -05:00
'$placeholdertitle' => DI :: l10n () -> t ( 'Set title' ),
2019-10-16 08:43:59 -04:00
'$category' => $x [ 'category' ] ? ? '' ,
2020-01-18 14:52:34 -05: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-07 21:25:04 -04:00
'$shortpermset' => DI :: l10n () -> t ( 'Permissions' ),
2018-07-19 09:52:05 -04:00
'$wall' => $notes_cid ? 0 : 1 ,
'$posttype' => $notes_cid ? Item :: PT_PERSONAL_NOTE : Item :: PT_ARTICLE ,
2019-10-16 08:43:59 -04:00
'$content' => $x [ 'content' ] ? ? '' ,
'$post_id' => $x [ 'post_id' ] ? ? '' ,
2019-12-30 17:00:08 -05:00
'$baseurl' => DI :: baseUrl () -> get ( true ),
2018-01-01 15:27:33 -05:00
'$defloc' => $x [ 'default_location' ],
'$visitor' => $x [ 'visitor' ],
'$pvisit' => $notes_cid ? 'none' : $x [ 'visitor' ],
2020-01-18 14:52:34 -05:00
'$public' => DI :: l10n () -> t ( 'Public post' ),
2018-01-01 15:27:33 -05:00
'$lockstate' => $x [ 'lockstate' ],
'$bang' => $x [ 'bang' ],
'$profile_uid' => $x [ 'profile_uid' ],
2020-01-18 14:52:34 -05:00
'$preview' => DI :: l10n () -> t ( 'Preview' ),
2018-01-01 15:27:33 -05:00
'$jotplugins' => $jotplugins ,
'$notes_cid' => $notes_cid ,
2020-01-18 14:52:34 -05:00
'$sourceapp' => DI :: l10n () -> t ( $a -> sourcename ),
'$cancel' => DI :: l10n () -> t ( 'Cancel' ),
2018-11-05 03:37:03 -05:00
'$rand_num' => Crypto :: randomDigits ( 12 ),
2013-01-26 14:52:21 -05:00
// ACL permissions box
2018-01-01 15:27:33 -05:00
'$acl' => $x [ 'acl' ],
2016-06-25 06:21:13 -04:00
//jot nav tab (used in some themes)
2020-01-18 14:52:34 -05:00
'$message' => DI :: l10n () -> t ( 'Message' ),
'$browser' => DI :: l10n () -> t ( 'Browser' ),
2020-04-01 10:10:57 -04:00
'$compose_link_title' => DI :: l10n () -> t ( 'Open Compose page' ),
2018-01-15 08:05:12 -05:00
]);
2012-09-10 04:36:30 -04:00
2017-04-08 14:00:54 -04:00
if ( $popup == true ) {
2018-01-01 15:27:33 -05:00
$o = '<div id="jot-popup" style="display: none;">' . $o . '</div>' ;
2012-09-10 04:36:30 -04:00
}
return $o ;
2011-07-07 08:02:58 -04:00
}
2012-01-02 19:54:37 -05:00
2017-11-19 00:57:06 -05:00
/**
2017-11-19 10:42:00 -05:00
* Plucks the children of the given parent from a given item list .
2017-11-19 08:41:16 -05:00
*
2017-11-19 00:57:06 -05:00
* @ param array $item_list
* @ param array $parent
2019-01-07 10:24:06 -05:00
* @ param bool $recursive
* @ return array
2017-11-19 00:57:06 -05:00
*/
2017-11-19 10:42:00 -05:00
function get_item_children ( array & $item_list , array $parent , $recursive = true )
2017-11-19 00:57:06 -05:00
{
$children = [];
2017-11-19 10:42:00 -05:00
foreach ( $item_list as $i => $item ) {
2020-05-27 08:19:06 -04:00
if ( $item [ 'gravity' ] != GRAVITY_PARENT ) {
2017-11-19 00:57:06 -05:00
if ( $recursive ) {
2012-09-10 04:36:30 -04:00
// Fallback to parent-uri if thr-parent is not set
$thr_parent = $item [ 'thr-parent' ];
2017-04-08 13:05:50 -04:00
if ( $thr_parent == '' ) {
2012-09-10 04:36:30 -04:00
$thr_parent = $item [ 'parent-uri' ];
2017-04-08 13:05:50 -04:00
}
2012-09-10 04:36:30 -04:00
2017-04-04 13:46:56 -04:00
if ( $thr_parent == $parent [ 'uri' ]) {
2017-11-19 00:57:06 -05:00
$item [ 'children' ] = get_item_children ( $item_list , $item );
2012-09-10 04:36:30 -04:00
$children [] = $item ;
2017-11-19 10:42:00 -05:00
unset ( $item_list [ $i ]);
2012-09-10 04:36:30 -04:00
}
2017-04-08 13:05:50 -04:00
} elseif ( $item [ 'parent' ] == $parent [ 'id' ]) {
2012-09-10 04:36:30 -04:00
$children [] = $item ;
2017-11-19 10:42:00 -05:00
unset ( $item_list [ $i ]);
2012-09-10 04:36:30 -04:00
}
}
}
return $children ;
2012-07-27 16:08:57 -04:00
}
2017-11-19 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* Recursively sorts a tree - like item array
2017-11-19 00:57:06 -05:00
*
* @ param array $items
* @ return array
*/
function sort_item_children ( array $items )
{
2012-09-10 04:36:30 -04:00
$result = $items ;
2019-07-07 17:30:33 -04:00
usort ( $result , 'sort_thr_received_rev' );
2017-04-04 13:46:56 -04:00
foreach ( $result as $k => $i ) {
2017-11-19 00:57:06 -05:00
if ( isset ( $result [ $k ][ 'children' ])) {
2012-09-10 04:36:30 -04:00
$result [ $k ][ 'children' ] = sort_item_children ( $result [ $k ][ 'children' ]);
}
}
return $result ;
2012-07-27 16:08:57 -04:00
}
2017-11-19 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* Recursively add all children items at the top level of a list
2017-11-19 00:57:06 -05: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 13:46:56 -04:00
}
2012-09-10 04:36:30 -04:00
}
2012-07-27 16:08:57 -04:00
}
2017-11-19 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* Selectively flattens a tree - like item structure to prevent threading stairs
*
2017-11-19 00:57:06 -05: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 )
{
2018-02-27 04:29:11 -05:00
if ( ! isset ( $parent [ 'children' ]) || count ( $parent [ 'children' ]) == 0 ) {
2017-11-19 00:57:06 -05:00
return $parent ;
2017-04-04 13:46:56 -04:00
}
2012-09-10 04:36:30 -04:00
2017-11-19 00:57:06 -05: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 17:57:53 -05:00
2017-11-19 00:57:06 -05:00
if ( isset ( $child [ 'children' ]) && count ( $child [ 'children' ])) {
// This helps counting only the regular posts
$count_post_closure = function ( $var ) {
2019-10-23 18:25:43 -04:00
return $var [ 'verb' ] === Activity :: POST ;
2017-11-19 00:57:06 -05: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 18:25:43 -04:00
while ( $child [ 'children' ][ $j ][ 'verb' ] !== Activity :: POST && $j < count ( $child [ 'children' ])) {
2017-11-19 00:57:06 -05: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 13:46:56 -04:00
}
}
2015-11-18 17:57:53 -05:00
2017-11-19 00:57:06 -05:00
return $parent ;
}
2012-09-10 04:36:30 -04:00
2017-11-19 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* Expands a flat list of items into corresponding tree - like conversation structures .
*
2019-07-07 17:30:33 -04:00
* sort the top - level posts either on " received " or " commented " , and finally
2017-11-19 00:57:06 -05: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 17:30:33 -04:00
* @ param string $order Either on " received " or " commented "
2017-11-19 00:57:06 -05:00
* @ return array
2019-01-07 10:24:06 -05:00
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
2017-11-19 00:57:06 -05:00
*/
function conv_sort ( array $item_list , $order )
{
$parents = [];
if ( ! ( is_array ( $item_list ) && count ( $item_list ))) {
return $parents ;
}
2018-08-10 00:27:52 -04:00
$blocklist = conv_get_blocklist ();
2017-11-19 00:57:06 -05:00
$item_array = [];
// Dedupes the item list on the uri to prevent infinite loops
foreach ( $item_list as $item ) {
2018-08-10 00:27:52 -04:00
if ( in_array ( $item [ 'author-id' ], $blocklist )) {
continue ;
}
2017-11-19 00:57:06 -05:00
$item_array [ $item [ 'uri' ]] = $item ;
}
// Extract the top level items
foreach ( $item_array as $item ) {
2020-05-27 08:19:06 -04:00
if ( $item [ 'gravity' ] == GRAVITY_PARENT ) {
2017-11-19 00:57:06 -05:00
$parents [] = $item ;
2017-04-04 13:46:56 -04:00
}
}
2012-09-10 04:36:30 -04:00
2019-11-07 02:39:50 -05:00
if ( stristr ( $order , 'pinned_received' )) {
usort ( $parents , 'sort_thr_pinned_received' );
} elseif ( stristr ( $order , 'received' )) {
2019-07-07 17:30:33 -04:00
usort ( $parents , 'sort_thr_received' );
2017-04-08 14:07:28 -04:00
} elseif ( stristr ( $order , 'commented' )) {
2017-04-14 09:30:50 -04:00
usort ( $parents , 'sort_thr_commented' );
2017-04-04 13:46:56 -04:00
}
2012-09-10 04:36:30 -04:00
2017-11-19 10:42:00 -05: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 00:57:06 -05:00
foreach ( $parents as $i => $parent ) {
2017-11-19 10:42:00 -05:00
$parents [ $i ][ 'children' ] =
2017-11-28 13:54:39 -05:00
array_merge ( get_item_children ( $item_array , $parent , true ),
2017-11-24 16:39:12 -05:00
get_item_children ( $item_array , $parent , false ));
2017-04-04 13:46:56 -04:00
}
2012-09-10 04:36:30 -04:00
2017-11-19 00:57:06 -05:00
foreach ( $parents as $i => $parent ) {
$parents [ $i ][ 'children' ] = sort_item_children ( $parents [ $i ][ 'children' ]);
}
2020-01-18 10:50:57 -05:00
if ( ! DI :: pConfig () -> get ( local_user (), 'system' , 'no_smart_threading' , 0 )) {
2017-11-19 00:57:06 -05:00
foreach ( $parents as $i => $parent ) {
$parents [ $i ] = smart_flatten_conversation ( $parent );
2012-09-10 04:36:30 -04:00
}
}
2017-11-19 00:57:06 -05: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 04:36:30 -04:00
}
}
2017-11-19 00:57:06 -05:00
return $parents ;
2012-01-02 19:54:37 -05:00
}
2017-11-19 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* usort () callback to sort item arrays by pinned and the received key
2017-11-19 00:57:06 -05:00
*
* @ param array $a
* @ param array $b
* @ return int
*/
2019-11-07 02:39:50 -05:00
function sort_thr_pinned_received ( array $a , array $b )
2017-11-19 00:57:06 -05:00
{
2019-11-07 02:09:46 -05:00
if ( $b [ 'pinned' ] && ! $a [ 'pinned' ]) {
return 1 ;
} elseif ( ! $b [ 'pinned' ] && $a [ 'pinned' ]) {
return - 1 ;
}
2019-07-07 17:30:33 -04:00
return strcmp ( $b [ 'received' ], $a [ 'received' ]);
2012-01-02 19:54:37 -05:00
}
2019-11-07 02:39:50 -05:00
/**
2020-01-19 01:05:23 -05:00
* usort () callback to sort item arrays by the received key
2019-11-07 02:39:50 -05: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 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* usort () callback to reverse sort item arrays by the received key
2017-11-19 00:57:06 -05:00
*
* @ param array $a
* @ param array $b
* @ return int
*/
2019-07-07 17:30:33 -04:00
function sort_thr_received_rev ( array $a , array $b )
2017-11-19 00:57:06 -05:00
{
2019-07-07 17:30:33 -04:00
return strcmp ( $a [ 'received' ], $b [ 'received' ]);
2012-01-02 19:54:37 -05:00
}
2017-11-19 00:57:06 -05:00
/**
2020-01-19 01:05:23 -05:00
* usort () callback to sort item arrays by the commented key
2017-11-19 00:57:06 -05:00
*
* @ param array $a
* @ param array $b
2019-01-21 11:36:01 -05:00
* @ return int
2017-11-19 00:57:06 -05:00
*/
function sort_thr_commented ( array $a , array $b )
{
2017-04-08 13:05:50 -04:00
return strcmp ( $b [ 'commented' ], $a [ 'commented' ]);
2012-01-02 19:54:37 -05:00
}