2020-10-13 04:23:17 +00:00
< ? php
2022-01-02 09:49:50 +00:00
/**
* @ copyright Copyright ( C ) 2010 - 2022 , the Friendica project
*
* @ 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 />.
*
*/
2020-10-13 04:23:17 +00:00
namespace Friendica\Module\Conversation ;
use Friendica\BaseModule ;
use Friendica\Content\BoundariesPager ;
use Friendica\Content\ForumManager ;
use Friendica\Content\Nav ;
use Friendica\Content\Widget ;
use Friendica\Content\Text\HTML ;
use Friendica\Core\ACL ;
use Friendica\Core\Hook ;
use Friendica\Core\Renderer ;
2020-10-17 18:52:05 +00:00
use Friendica\Core\Session ;
2020-10-13 04:23:17 +00:00
use Friendica\Database\DBA ;
use Friendica\DI ;
use Friendica\Model\Contact ;
use Friendica\Model\Group ;
use Friendica\Model\Item ;
2021-01-16 04:16:09 +00:00
use Friendica\Model\Post ;
2020-10-13 04:23:17 +00:00
use Friendica\Model\Profile ;
use Friendica\Model\User ;
2021-06-05 20:29:19 +00:00
use Friendica\Model\Verb ;
2020-10-13 04:23:17 +00:00
use Friendica\Module\Contact as ModuleContact ;
use Friendica\Module\Security\Login ;
2021-06-05 20:29:19 +00:00
use Friendica\Protocol\Activity ;
2020-10-13 04:23:17 +00:00
use Friendica\Util\DateTimeFormat ;
class Network extends BaseModule
{
/** @var int */
private static $groupId ;
/** @var int */
private static $forumContactId ;
/** @var string */
private static $selectedTab ;
/** @var mixed */
private static $min_id ;
/** @var mixed */
private static $max_id ;
2020-10-14 02:30:40 +00:00
/** @var string */
private static $accountTypeString ;
2020-10-13 04:23:17 +00:00
/** @var int */
private static $accountType ;
/** @var string */
private static $network ;
/** @var int */
private static $itemsPerPage ;
/** @var string */
private static $dateFrom ;
/** @var string */
private static $dateTo ;
/** @var int */
private static $star ;
/** @var int */
private static $mention ;
/** @var string */
protected static $order ;
2021-11-20 14:38:03 +00:00
protected function content ( array $request = []) : string
2020-10-13 04:23:17 +00:00
{
if ( ! local_user ()) {
return Login :: form ();
}
2021-11-14 22:19:25 +00:00
$this -> parseRequest ( $_GET );
2020-10-13 04:23:17 +00:00
$module = 'network' ;
2022-06-30 12:49:51 +00:00
DI :: page ()[ 'aside' ] .= Widget :: accountTypes ( $module , self :: $accountTypeString );
2020-10-13 04:23:17 +00:00
DI :: page ()[ 'aside' ] .= Group :: sidebarWidget ( $module , $module . '/group' , 'standard' , self :: $groupId );
DI :: page ()[ 'aside' ] .= ForumManager :: widget ( $module . '/forum' , local_user (), self :: $forumContactId );
DI :: page ()[ 'aside' ] .= Widget :: postedByYear ( $module . '/archive' , local_user (), false );
DI :: page ()[ 'aside' ] .= Widget :: networks ( $module , ! self :: $forumContactId ? self :: $network : '' );
DI :: page ()[ 'aside' ] .= Widget\SavedSearches :: getHTML ( DI :: args () -> getQueryString ());
2022-06-30 12:52:14 +00:00
DI :: page ()[ 'aside' ] .= Widget :: fileAs ( 'filed' , '' );
2020-10-13 04:23:17 +00:00
$arr = [ 'query' => DI :: args () -> getQueryString ()];
Hook :: callAll ( 'network_content_init' , $arr );
$o = '' ;
// Fetch a page full of parent items for this page
$params = [ 'limit' => self :: $itemsPerPage ];
$table = 'network-thread-view' ;
$items = self :: getItems ( $table , $params );
if ( DI :: pConfig () -> get ( local_user (), 'system' , 'infinite_scroll' ) && ( $_GET [ 'mode' ] ? ? '' ) != 'minimal' ) {
$tpl = Renderer :: getMarkupTemplate ( 'infinite_scroll_head.tpl' );
$o .= Renderer :: replaceMacros ( $tpl , [ '$reload_uri' => DI :: args () -> getQueryString ()]);
}
if ( ! ( isset ( $_GET [ 'mode' ]) AND ( $_GET [ 'mode' ] == 'raw' ))) {
$o .= self :: getTabsHTML ( self :: $selectedTab );
Nav :: setSelected ( DI :: args () -> get ( 0 ));
$content = '' ;
if ( self :: $forumContactId ) {
// If self::$forumContactId belongs to a communitity forum or a privat goup,.add a mention to the status editor
2022-02-09 06:52:16 +00:00
$condition = [ " `id` = ? AND `contact-type` = ? " , self :: $forumContactId , Contact :: TYPE_COMMUNITY ];
2020-10-13 04:23:17 +00:00
$contact = DBA :: selectFirst ( 'contact' , [ 'addr' ], $condition );
if ( ! empty ( $contact [ 'addr' ])) {
$content = '!' . $contact [ 'addr' ];
}
}
$a = DI :: app ();
$default_permissions = [];
if ( self :: $groupId ) {
$default_permissions [ 'allow_gid' ] = [ self :: $groupId ];
}
$allowedCids = [];
if ( self :: $forumContactId ) {
$allowedCids [] = ( int ) self :: $forumContactId ;
} elseif ( self :: $network ) {
$condition = [
'uid' => local_user (),
'network' => self :: $network ,
'self' => false ,
'blocked' => false ,
'pending' => false ,
'archive' => false ,
'rel' => [ Contact :: SHARING , Contact :: FRIEND ],
];
$contactStmt = DBA :: select ( 'contact' , [ 'id' ], $condition );
while ( $contact = DBA :: fetch ( $contactStmt )) {
$allowedCids [] = ( int ) $contact [ 'id' ];
}
DBA :: close ( $contactStmt );
}
if ( count ( $allowedCids )) {
$default_permissions [ 'allow_cid' ] = $allowedCids ;
}
$x = [
2021-08-09 20:33:46 +00:00
'lockstate' => self :: $groupId || self :: $forumContactId || self :: $network || ACL :: getLockstateForUserId ( $a -> getLoggedInUserId ()) ? 'lock' : 'unlock' ,
'acl' => ACL :: getFullSelectorHTML ( DI :: page (), $a -> getLoggedInUserId (), true , $default_permissions ),
2020-10-13 04:23:17 +00:00
'bang' => (( self :: $groupId || self :: $forumContactId || self :: $network ) ? '!' : '' ),
'content' => $content ,
];
2021-09-23 21:18:36 +00:00
$o .= DI :: conversation () -> statusEditor ( $x );
2020-10-13 04:23:17 +00:00
}
if ( self :: $groupId ) {
$group = DBA :: selectFirst ( 'group' , [ 'name' ], [ 'id' => self :: $groupId , 'uid' => local_user ()]);
if ( ! DBA :: isResult ( $group )) {
2022-10-17 18:55:22 +00:00
DI :: sysmsg () -> addNotice ( DI :: l10n () -> t ( 'No such group' ));
2020-10-13 04:23:17 +00:00
}
$o = Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'section_title.tpl' ), [
'$title' => DI :: l10n () -> t ( 'Group: %s' , $group [ 'name' ])
]) . $o ;
} elseif ( self :: $forumContactId ) {
$contact = Contact :: getById ( self :: $forumContactId );
if ( DBA :: isResult ( $contact )) {
$o = Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'viewcontact_template.tpl' ), [
'contacts' => [ ModuleContact :: getContactTemplateVars ( $contact )],
'id' => DI :: args () -> get ( 0 ),
]) . $o ;
} else {
2022-10-17 18:55:22 +00:00
DI :: sysmsg () -> addNotice ( DI :: l10n () -> t ( 'Invalid contact.' ));
2020-10-13 04:23:17 +00:00
}
} elseif ( ! DI :: config () -> get ( 'theme' , 'hide_eventlist' )) {
$o .= Profile :: getBirthdays ();
$o .= Profile :: getEventsReminderHTML ();
}
if ( self :: $order === 'received' ) {
$ordering = '`received`' ;
2022-04-20 21:03:33 +00:00
} elseif ( self :: $order === 'created' ) {
$ordering = '`created`' ;
2020-10-13 04:23:17 +00:00
} else {
$ordering = '`commented`' ;
}
2021-09-23 21:18:36 +00:00
$o .= DI :: conversation () -> create ( $items , 'network' , false , false , $ordering , local_user ());
2020-10-13 04:23:17 +00:00
if ( DI :: pConfig () -> get ( local_user (), 'system' , 'infinite_scroll' )) {
$o .= HTML :: scrollLoader ();
} else {
$pager = new BoundariesPager (
DI :: l10n (),
DI :: args () -> getQueryString (),
2020-11-11 08:05:12 +00:00
$items [ 0 ][ self :: $order ] ? ? null ,
$items [ count ( $items ) - 1 ][ self :: $order ] ? ? null ,
2020-10-13 04:23:17 +00:00
self :: $itemsPerPage
);
$o .= $pager -> renderMinimal ( count ( $items ));
}
return $o ;
}
/**
* Sets items as seen
*
* @ param array $condition The array with the SQL condition
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function setItemsSeenByCondition ( array $condition )
{
if ( empty ( $condition )) {
return ;
}
2021-01-16 04:16:09 +00:00
$unseen = Post :: exists ( $condition );
2020-10-13 04:23:17 +00:00
if ( $unseen ) {
2020-12-26 18:51:36 +00:00
/// @todo handle huge "unseen" updates in the background to avoid timeout errors
2020-10-13 04:23:17 +00:00
Item :: update ([ 'unseen' => false ], $condition );
}
}
/**
* Get the network tabs menu
*
* @ param string $selectedTab
* @ return string Html of the network tabs
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function getTabsHTML ( string $selectedTab )
{
$cmd = DI :: args () -> getCommand ();
// tabs
$tabs = [
[
'label' => DI :: l10n () -> t ( 'Latest Activity' ),
'url' => $cmd . '?' . http_build_query ([ 'order' => 'commented' ]),
'sel' => ! $selectedTab || $selectedTab == 'commented' ? 'active' : '' ,
'title' => DI :: l10n () -> t ( 'Sort by latest activity' ),
'id' => 'activity-order-tab' ,
'accesskey' => 'e' ,
],
[
'label' => DI :: l10n () -> t ( 'Latest Posts' ),
'url' => $cmd . '?' . http_build_query ([ 'order' => 'received' ]),
'sel' => $selectedTab == 'received' ? 'active' : '' ,
'title' => DI :: l10n () -> t ( 'Sort by post received date' ),
'id' => 'post-order-tab' ,
'accesskey' => 't' ,
],
2022-04-20 21:03:33 +00:00
[
'label' => DI :: l10n () -> t ( 'Latest Creation' ),
'url' => $cmd . '?' . http_build_query ([ 'order' => 'created' ]),
'sel' => $selectedTab == 'created' ? 'active' : '' ,
'title' => DI :: l10n () -> t ( 'Sort by post creation date' ),
'id' => 'creation-order-tab' ,
'accesskey' => 'q' ,
],
2020-10-13 04:23:17 +00:00
[
'label' => DI :: l10n () -> t ( 'Personal' ),
'url' => $cmd . '?' . http_build_query ([ 'mention' => true ]),
'sel' => $selectedTab == 'mention' ? 'active' : '' ,
'title' => DI :: l10n () -> t ( 'Posts that mention or involve you' ),
'id' => 'personal-tab' ,
'accesskey' => 'r' ,
],
[
'label' => DI :: l10n () -> t ( 'Starred' ),
'url' => $cmd . '?' . http_build_query ([ 'star' => true ]),
'sel' => $selectedTab == 'star' ? 'active' : '' ,
'title' => DI :: l10n () -> t ( 'Favourite Posts' ),
'id' => 'starred-posts-tab' ,
'accesskey' => 'm' ,
],
];
$arr = [ 'tabs' => $tabs ];
Hook :: callAll ( 'network_tabs' , $arr );
$tpl = Renderer :: getMarkupTemplate ( 'common_tabs.tpl' );
return Renderer :: replaceMacros ( $tpl , [ '$tabs' => $arr [ 'tabs' ]]);
}
2021-11-14 22:19:25 +00:00
protected function parseRequest ( array $get )
2020-10-13 04:23:17 +00:00
{
2021-11-14 22:19:25 +00:00
self :: $groupId = $this -> parameters [ 'group_id' ] ? ? 0 ;
2020-10-13 04:23:17 +00:00
2021-11-14 22:19:25 +00:00
self :: $forumContactId = $this -> parameters [ 'contact_id' ] ? ? 0 ;
2020-10-13 04:23:17 +00:00
2022-10-18 19:10:37 +00:00
self :: $selectedTab = DI :: session () -> get ( 'network-tab' , DI :: pConfig () -> get ( local_user (), 'network.view' , 'selected_tab' , '' ));
2020-10-13 04:23:17 +00:00
if ( ! empty ( $get [ 'star' ])) {
self :: $selectedTab = 'star' ;
2020-12-19 16:48:12 +00:00
self :: $star = true ;
} else {
self :: $star = self :: $selectedTab == 'star' ;
2020-10-13 04:23:17 +00:00
}
if ( ! empty ( $get [ 'mention' ])) {
self :: $selectedTab = 'mention' ;
2020-12-19 16:48:12 +00:00
self :: $mention = true ;
} else {
self :: $mention = self :: $selectedTab == 'mention' ;
2020-10-13 04:23:17 +00:00
}
if ( ! empty ( $get [ 'order' ])) {
self :: $selectedTab = $get [ 'order' ];
2020-10-26 06:54:10 +00:00
self :: $order = $get [ 'order' ];
2021-02-21 11:14:35 +00:00
self :: $star = false ;
self :: $mention = false ;
2022-04-21 13:58:24 +00:00
} elseif ( in_array ( self :: $selectedTab , [ 'received' , 'star' ])) {
2020-10-30 22:13:14 +00:00
self :: $order = 'received' ;
2022-04-21 05:52:08 +00:00
} elseif ( self :: $selectedTab == 'created' ) {
2022-04-20 21:03:33 +00:00
self :: $order = 'created' ;
2022-04-21 05:52:08 +00:00
} else {
self :: $order = 'commented' ;
2020-10-13 04:23:17 +00:00
}
2020-10-17 18:52:05 +00:00
self :: $selectedTab = self :: $selectedTab ? ? self :: $order ;
2021-02-21 12:18:50 +00:00
// Prohibit combined usage of "star" and "mention"
if ( self :: $selectedTab == 'star' ) {
self :: $mention = false ;
} elseif ( self :: $selectedTab == 'mention' ) {
self :: $star = false ;
}
2022-10-18 19:12:23 +00:00
DI :: session () -> set ( 'network-tab' , self :: $selectedTab );
2020-10-24 13:11:44 +00:00
DI :: pConfig () -> set ( local_user (), 'network.view' , 'selected_tab' , self :: $selectedTab );
2020-10-13 04:23:17 +00:00
2021-11-14 22:19:25 +00:00
self :: $accountTypeString = $get [ 'accounttype' ] ? ? $this -> parameters [ 'accounttype' ] ? ? '' ;
2020-10-14 02:30:40 +00:00
self :: $accountType = User :: getAccountTypeByString ( self :: $accountTypeString );
2020-10-13 04:23:17 +00:00
self :: $network = $get [ 'nets' ] ? ? '' ;
2021-11-14 22:19:25 +00:00
self :: $dateFrom = $this -> parameters [ 'from' ] ? ? '' ;
self :: $dateTo = $this -> parameters [ 'to' ] ? ? '' ;
2020-10-13 04:23:17 +00:00
if ( DI :: mode () -> isMobile ()) {
self :: $itemsPerPage = DI :: pConfig () -> get ( local_user (), 'system' , 'itemspage_mobile_network' ,
DI :: config () -> get ( 'system' , 'itemspage_network_mobile' ));
} else {
self :: $itemsPerPage = DI :: pConfig () -> get ( local_user (), 'system' , 'itemspage_network' ,
DI :: config () -> get ( 'system' , 'itemspage_network' ));
}
2020-10-17 19:24:51 +00:00
self :: $min_id = $get [ 'min_id' ] ? ? null ;
self :: $max_id = $get [ 'max_id' ] ? ? null ;
2020-10-13 04:23:17 +00:00
2020-10-17 07:31:03 +00:00
switch ( self :: $order ) {
2020-10-13 04:23:17 +00:00
case 'received' :
2020-10-17 19:24:51 +00:00
self :: $max_id = $get [ 'last_received' ] ? ? self :: $max_id ;
2020-10-13 04:23:17 +00:00
break ;
case 'created' :
2020-10-18 04:05:52 +00:00
self :: $max_id = $get [ 'last_created' ] ? ? self :: $max_id ;
2020-10-13 04:23:17 +00:00
break ;
case 'uriid' :
2020-10-18 04:05:52 +00:00
self :: $max_id = $get [ 'last_uriid' ] ? ? self :: $max_id ;
2020-10-13 04:23:17 +00:00
break ;
2020-10-24 13:11:44 +00:00
default :
self :: $order = 'commented' ;
self :: $max_id = $get [ 'last_commented' ] ? ? self :: $max_id ;
2020-10-13 04:23:17 +00:00
}
}
protected static function getItems ( string $table , array $params , array $conditionFields = [])
{
$conditionFields [ 'uid' ] = local_user ();
$conditionStrings = [];
2020-10-14 02:30:40 +00:00
if ( ! is_null ( self :: $accountType )) {
2020-10-13 04:23:17 +00:00
$conditionFields [ 'contact-type' ] = self :: $accountType ;
}
if ( self :: $star ) {
$conditionFields [ 'starred' ] = true ;
}
if ( self :: $mention ) {
$conditionFields [ 'mention' ] = true ;
}
if ( self :: $network ) {
$conditionFields [ 'network' ] = self :: $network ;
}
if ( self :: $dateFrom ) {
2021-10-03 16:38:47 +00:00
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `received` <= ? " , DateTimeFormat :: convert ( self :: $dateFrom , 'UTC' , DI :: app () -> getTimeZone ())]);
2020-10-13 04:23:17 +00:00
}
if ( self :: $dateTo ) {
2021-10-03 16:38:47 +00:00
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `received` >= ? " , DateTimeFormat :: convert ( self :: $dateTo , 'UTC' , DI :: app () -> getTimeZone ())]);
2020-10-13 04:23:17 +00:00
}
if ( self :: $groupId ) {
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `contact-id` IN (SELECT `contact-id` FROM `group_member` WHERE `gid` = ?) " , self :: $groupId ]);
} elseif ( self :: $forumContactId ) {
2021-06-05 20:29:19 +00:00
$conditionStrings = DBA :: mergeConditions ( $conditionStrings ,
2022-09-24 17:56:07 +00:00
[ " ((`contact-id` = ?) OR `uri-id` IN (SELECT `parent-uri-id` FROM `post-user-view` WHERE (`contact-id` = ? AND `gravity` = ? AND `vid` = ? AND `uid` = ?))) " ,
2022-09-12 21:12:11 +00:00
self :: $forumContactId , self :: $forumContactId , Item :: GRAVITY_ACTIVITY , Verb :: getID ( Activity :: ANNOUNCE ), local_user ()]);
2020-10-13 04:23:17 +00:00
}
// Currently only the order modes "received" and "commented" are in use
if ( isset ( self :: $max_id )) {
switch ( self :: $order ) {
case 'received' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `received` < ? " , self :: $max_id ]);
break ;
case 'commented' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `commented` < ? " , self :: $max_id ]);
break ;
case 'created' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `created` < ? " , self :: $max_id ]);
break ;
case 'uriid' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `uri-id` < ? " , self :: $max_id ]);
break ;
}
}
if ( isset ( self :: $min_id )) {
switch ( self :: $order ) {
case 'received' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `received` > ? " , self :: $min_id ]);
break ;
case 'commented' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `commented` > ? " , self :: $min_id ]);
break ;
case 'created' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `created` > ? " , self :: $min_id ]);
break ;
case 'uriid' :
$conditionStrings = DBA :: mergeConditions ( $conditionStrings , [ " `uri-id` > ? " , self :: $min_id ]);
break ;
}
}
if ( isset ( self :: $min_id ) && ! isset ( self :: $max_id )) {
// min_id quirk: querying in reverse order with min_id gets the most recent rows, regardless of how close
// they are to min_id. We change the query ordering to get the expected data, and we need to reverse the
// order of the results.
$params [ 'order' ] = [ self :: $order => false ];
} else {
$params [ 'order' ] = [ self :: $order => true ];
}
$items = DBA :: selectToArray ( $table , [], DBA :: mergeConditions ( $conditionFields , $conditionStrings ), $params );
// min_id quirk, continued
if ( isset ( self :: $min_id ) && ! isset ( self :: $max_id )) {
$items = array_reverse ( $items );
}
if ( DBA :: isResult ( $items )) {
2021-02-13 19:56:03 +00:00
$parents = array_column ( $items , 'parent-uri-id' );
2020-10-17 07:31:03 +00:00
} else {
$parents = [];
2020-10-13 04:23:17 +00:00
}
// We aren't going to try and figure out at the item, group, and page
// level which items you've seen and which you haven't. If you're looking
// at the top level network page just mark everything seen.
2020-10-17 07:31:03 +00:00
if ( ! self :: $groupId && ! self :: $forumContactId && ! self :: $star && ! self :: $mention ) {
2020-10-13 04:23:17 +00:00
$condition = [ 'unseen' => true , 'uid' => local_user ()];
self :: setItemsSeenByCondition ( $condition );
2020-10-17 07:31:03 +00:00
} elseif ( ! empty ( $parents )) {
2021-02-13 19:56:03 +00:00
$condition = [ 'unseen' => true , 'uid' => local_user (), 'parent-uri-id' => $parents ];
2020-10-13 04:23:17 +00:00
self :: setItemsSeenByCondition ( $condition );
}
return $items ;
}
}