2023-09-09 09:14:36 +00:00
< ? php
/**
* @ copyright Copyright ( C ) 2010 - 2023 , 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 />.
*
*/
namespace Friendica\Module\Conversation ;
use Friendica\App ;
use Friendica\App\Mode ;
use Friendica\BaseModule ;
use Friendica\Content\Conversation\Collection\Timelines ;
use Friendica\Content\Conversation\Entity\Timeline as TimelineEntity ;
use Friendica\Core\Cache\Capability\ICanCache ;
use Friendica\Core\Cache\Enum\Duration ;
use Friendica\Core\Config\Capability\IManageConfigValues ;
use Friendica\Core\L10n ;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues ;
use Friendica\Core\Renderer ;
use Friendica\Core\Session\Capability\IHandleUserSessions ;
use Friendica\Model\Contact ;
use Friendica\Model\User ;
use Friendica\Database\Database ;
2023-09-09 12:00:22 +00:00
use Friendica\Database\DBA ;
2023-09-09 09:14:36 +00:00
use Friendica\Model\Item ;
use Friendica\Model\Post ;
use Friendica\Module\Response ;
use Friendica\Util\DateTimeFormat ;
use Friendica\Util\Profiler ;
use Psr\Log\LoggerInterface ;
class Timeline extends BaseModule
{
/** @var string */
2023-09-09 12:48:51 +00:00
protected $selectedTab ;
2023-09-09 09:14:36 +00:00
/** @var mixed */
2023-09-09 13:02:20 +00:00
protected $minId ;
2023-09-09 09:14:36 +00:00
/** @var mixed */
2023-09-09 13:02:20 +00:00
protected $maxId ;
2023-09-09 09:14:36 +00:00
/** @var string */
2023-09-09 12:48:51 +00:00
protected $accountTypeString ;
2023-09-09 09:14:36 +00:00
/** @var int */
2023-09-09 12:48:51 +00:00
protected $accountType ;
2023-09-09 09:14:36 +00:00
/** @var int */
2023-09-09 12:48:51 +00:00
protected $itemUriId ;
2023-09-09 09:14:36 +00:00
/** @var int */
2023-09-09 12:48:51 +00:00
protected $itemsPerPage ;
2023-09-09 09:14:36 +00:00
/** @var bool */
2023-09-09 12:48:51 +00:00
protected $noSharer ;
2023-09-09 09:14:36 +00:00
/** @var App\Mode $mode */
protected $mode ;
2023-09-09 14:13:58 +00:00
/** @var IHandleUserSessions */
2023-09-09 09:14:36 +00:00
protected $session ;
/** @var Database */
protected $database ;
/** @var IManagePersonalConfigValues */
protected $pConfig ;
/** @var IManageConfigValues The config */
protected $config ;
/** @var ICanCache */
protected $cache ;
public function __construct ( Mode $mode , IHandleUserSessions $session , Database $database , IManagePersonalConfigValues $pConfig , IManageConfigValues $config , ICanCache $cache , L10n $l10n , App\BaseURL $baseUrl , App\Arguments $args , LoggerInterface $logger , Profiler $profiler , Response $response , array $server , array $parameters = [])
{
parent :: __construct ( $l10n , $baseUrl , $args , $logger , $profiler , $response , $server , $parameters );
$this -> mode = $mode ;
$this -> session = $session ;
$this -> database = $database ;
$this -> pConfig = $pConfig ;
$this -> config = $config ;
$this -> cache = $cache ;
}
/**
* Computes module parameters from the request and local configuration
*
* @ throws HTTPException\BadRequestException
* @ throws HTTPException\ForbiddenException
*/
protected function parseRequest ( array $request )
{
2023-09-09 12:00:22 +00:00
$this -> logger -> debug ( 'Got request' , $request );
2023-09-09 12:48:51 +00:00
$this -> selectedTab = $this -> parameters [ 'content' ] ? ? '' ;
2023-09-09 09:14:36 +00:00
2023-09-09 12:48:51 +00:00
$this -> accountTypeString = $request [ 'accounttype' ] ? ? $this -> parameters [ 'accounttype' ] ? ? '' ;
$this -> accountType = User :: getAccountTypeByString ( $this -> accountTypeString );
2023-09-09 09:14:36 +00:00
if ( $this -> mode -> isMobile ()) {
2023-09-09 12:48:51 +00:00
$this -> itemsPerPage = $this -> pConfig -> get (
2023-09-09 09:14:36 +00:00
$this -> session -> getLocalUserId (),
'system' ,
'itemspage_mobile_network' ,
$this -> config -> get ( 'system' , 'itemspage_network_mobile' )
);
} else {
2023-09-09 12:48:51 +00:00
$this -> itemsPerPage = $this -> pConfig -> get (
2023-09-09 09:14:36 +00:00
$this -> session -> getLocalUserId (),
'system' ,
'itemspage_network' ,
$this -> config -> get ( 'system' , 'itemspage_network' )
);
}
2023-09-09 12:00:22 +00:00
if ( ! empty ( $request [ 'item' ])) {
2023-09-09 13:02:20 +00:00
$item = Post :: selectFirst ([ 'parent' , 'parent-uri-id' ], [ 'id' => $request [ 'item' ]]);
2023-09-09 12:48:51 +00:00
$this -> itemUriId = $item [ 'parent-uri-id' ] ? ? 0 ;
2023-09-09 12:00:22 +00:00
} else {
2023-09-09 12:48:51 +00:00
$this -> itemUriId = 0 ;
2023-09-09 12:00:22 +00:00
}
2023-09-09 13:02:20 +00:00
$this -> minId = $request [ 'min_id' ] ? ? null ;
$this -> maxId = $request [ 'max_id' ] ? ? null ;
2023-09-09 09:14:36 +00:00
2023-09-09 12:48:51 +00:00
$this -> noSharer = ! empty ( $request [ 'no_sharer' ]);
2023-09-09 09:14:36 +00:00
}
protected function getNoSharerWidget ( string $base ) : string
{
2023-09-09 12:48:51 +00:00
$path = $this -> selectedTab ;
if ( ! empty ( $this -> accountTypeString )) {
$path .= '/' . $this -> accountTypeString ;
2023-09-09 09:14:36 +00:00
}
$query_parameters = [];
2023-09-09 13:02:20 +00:00
if ( ! empty ( $this -> minId )) {
$query_parameters [ 'min_id' ] = $this -> minId ;
2023-09-09 09:14:36 +00:00
}
2023-09-09 13:02:20 +00:00
if ( ! empty ( $this -> maxId )) {
$query_parameters [ 'max_id' ] = $this -> maxId ;
2023-09-09 09:14:36 +00:00
}
2023-09-09 09:30:55 +00:00
$path_all = $path . ( ! empty ( $query_parameters ) ? '?' . http_build_query ( $query_parameters ) : '' );
2023-09-09 09:14:36 +00:00
$path_no_sharer = $path . '?' . http_build_query ( array_merge ( $query_parameters , [ 'no_sharer' => true ]));
return Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'widget/community_sharer.tpl' ), [
'$title' => $this -> l10n -> t ( 'Own Contacts' ),
'$path_all' => $path_all ,
'$path_no_sharer' => $path_no_sharer ,
2023-09-09 12:48:51 +00:00
'$no_sharer' => $this -> noSharer ,
2023-09-09 09:14:36 +00:00
'$all' => $this -> l10n -> t ( 'Include' ),
'$no_sharer_label' => $this -> l10n -> t ( 'Hide' ),
'$base' => $base ,
]);
}
protected function getTabArray ( Timelines $timelines , string $prefix ) : array
{
$tabs = [];
foreach ( $timelines as $tab ) {
$tabs [] = [
'label' => $tab -> label ,
'url' => $tab -> path ? ? $prefix . '/' . $tab -> code ,
2023-09-09 12:48:51 +00:00
'sel' => $this -> selectedTab == $tab -> code ? 'active' : '' ,
2023-09-09 09:14:36 +00:00
'title' => $tab -> description ,
'id' => $prefix . '-' . $tab -> code . '-tab' ,
'accesskey' => $tab -> accessKey ,
];
}
return $tabs ;
}
/**
* Database query for the channel page
*
* @ return array
* @ throws \Exception
*/
protected function getChannelItems ()
{
$uid = $this -> session -> getLocalUserId ();
2023-09-09 12:48:51 +00:00
if ( $this -> selectedTab == TimelineEntity :: WHATSHOT ) {
if ( ! is_null ( $this -> accountType )) {
$condition = [ " (`comments` >= ? OR `activities` >= ?) AND `contact-type` = ? " , $this -> getMedianComments ( $uid , 4 ), $this -> getMedianActivities ( $uid , 4 ), $this -> accountType ];
2023-09-09 09:14:36 +00:00
} else {
$condition = [ " (`comments` >= ? OR `activities` >= ?) AND `contact-type` != ? " , $this -> getMedianComments ( $uid , 4 ), $this -> getMedianActivities ( $uid , 4 ), Contact :: TYPE_COMMUNITY ];
}
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: FORYOU ) {
2023-09-09 09:14:36 +00:00
$cid = Contact :: getPublicIdByUserId ( $uid );
2023-09-09 09:30:55 +00:00
2023-09-09 09:14:36 +00:00
$condition = [
" (`owner-id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `relation-thread-score` > ?) OR
(( `comments` >= ? OR `activities` >= ? ) AND `owner-id` IN ( SELECT `cid` FROM `contact-relation` WHERE `follows` AND `relation-cid` = ? )) OR
( `owner-id` IN ( SELECT `pid` FROM `account-user-view` WHERE `uid` = ? AND `rel` IN ( ? , ? ) AND `notify_new_posts` ))) " ,
$cid , $this -> getMedianRelationThreadScore ( $cid , 4 ), $this -> getMedianComments ( $uid , 4 ), $this -> getMedianActivities ( $uid , 4 ), $cid ,
$uid , Contact :: FRIEND , Contact :: SHARING
];
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: FOLLOWERS ) {
2023-09-09 09:14:36 +00:00
$condition = [ " `owner-id` IN (SELECT `pid` FROM `account-user-view` WHERE `uid` = ? AND `rel` = ?) " , $uid , Contact :: FOLLOWER ];
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: SHARERSOFSHARERS ) {
2023-09-09 09:14:36 +00:00
$cid = Contact :: getPublicIdByUserId ( $uid );
// @todo Suggest posts from contacts that are followed most by our followers
$condition = [
" `owner-id` IN (SELECT `cid` FROM `contact-relation` WHERE `follows` AND `last-interaction` > ?
AND `relation-cid` IN ( SELECT `cid` FROM `contact-relation` WHERE `follows` AND `relation-cid` = ? AND `relation-thread-score` >= ? )
AND NOT `cid` IN ( SELECT `cid` FROM `contact-relation` WHERE `follows` AND `relation-cid` = ? )) " ,
DateTimeFormat :: utc ( 'now - ' . $this -> config -> get ( 'channel' , 'sharer_interaction_days' ) . ' day' ), $cid , $this -> getMedianRelationThreadScore ( $cid , 4 ), $cid
];
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: IMAGE ) {
2023-09-09 09:14:36 +00:00
$condition = [ " `media-type` & ? " , 1 ];
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: VIDEO ) {
2023-09-09 09:14:36 +00:00
$condition = [ " `media-type` & ? " , 2 ];
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: AUDIO ) {
2023-09-09 09:14:36 +00:00
$condition = [ " `media-type` & ? " , 4 ];
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == TimelineEntity :: LANGUAGE ) {
2023-09-09 09:14:36 +00:00
$condition = [ " JSON_EXTRACT(JSON_KEYS(language), ' $ [0]') = ? " , $this -> l10n -> convertCodeForLanguageDetection ( User :: getLanguageCode ( $uid ))];
}
2023-09-09 12:48:51 +00:00
if ( $this -> selectedTab != TimelineEntity :: LANGUAGE ) {
2023-09-09 09:14:36 +00:00
$condition = $this -> addLanguageCondition ( $uid , $condition );
}
2023-09-09 12:00:22 +00:00
$condition = DBA :: mergeConditions ( $condition , [ " NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` = `post-engagement`.`owner-id` AND (`ignored` OR `blocked` OR `collapsed`)) " , $uid ]);
2023-09-09 09:14:36 +00:00
2023-09-09 12:48:51 +00:00
if (( $this -> selectedTab != TimelineEntity :: WHATSHOT ) && ! is_null ( $this -> accountType )) {
$condition = DBA :: mergeConditions ( $condition , [ 'contact-type' => $this -> accountType ]);
2023-09-09 09:14:36 +00:00
}
2023-09-09 12:48:51 +00:00
$params = [ 'order' => [ 'created' => true ], 'limit' => $this -> itemsPerPage ];
2023-09-09 09:14:36 +00:00
2023-09-09 12:48:51 +00:00
if ( ! empty ( $this -> itemUriId )) {
$condition = DBA :: mergeConditions ( $condition , [ 'uri-id' => $this -> itemUriId ]);
2023-09-09 09:14:36 +00:00
} else {
2023-09-09 12:48:51 +00:00
if ( $this -> noSharer ) {
2023-09-09 12:00:22 +00:00
$condition = DBA :: mergeConditions ( $condition , [ " NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `post-user`.`uid` = ? AND `post-user`.`uri-id` = `post-engagement`.`uri-id`) " , $this -> session -> getLocalUserId ()]);
2023-09-09 09:14:36 +00:00
}
2023-09-09 13:02:20 +00:00
if ( isset ( $this -> maxId )) {
$condition = DBA :: mergeConditions ( $condition , [ " `created` < ? " , $this -> maxId ]);
2023-09-09 09:14:36 +00:00
}
2023-09-09 13:02:20 +00:00
if ( isset ( $this -> minId )) {
$condition = DBA :: mergeConditions ( $condition , [ " `created` > ? " , $this -> minId ]);
2023-09-09 09:14:36 +00:00
// Previous page case: we want the items closest to min_id but for that we need to reverse the query order
2023-09-09 13:02:20 +00:00
if ( ! isset ( $this -> maxId )) {
2023-09-09 09:14:36 +00:00
$params [ 'order' ][ 'created' ] = false ;
}
}
}
$items = $this -> database -> selectToArray ( 'post-engagement' , [ 'uri-id' , 'created' ], $condition , $params );
if ( empty ( $items )) {
return [];
}
// Previous page case: once we get the relevant items closest to min_id, we need to restore the expected display order
2023-09-09 13:02:20 +00:00
if ( empty ( $this -> itemUriId ) && isset ( $this -> minId ) && ! isset ( $this -> maxId )) {
2023-09-09 09:14:36 +00:00
$items = array_reverse ( $items );
}
2023-09-09 14:13:58 +00:00
$condition = [ 'unseen' => true , 'uid' => $uid , 'parent-uri-id' => array_column ( $items , 'uri-id' )];
$this -> setItemsSeenByCondition ( $condition );
2023-09-09 09:14:36 +00:00
return $items ;
}
private function addLanguageCondition ( int $uid , array $condition ) : array
{
$conditions = [];
$languages = $this -> pConfig -> get ( $uid , 'channel' , 'languages' , [ User :: getLanguageCode ( $uid )]);
$languages = $this -> l10n -> convertForLanguageDetection ( $languages );
foreach ( $languages as $language ) {
$conditions [] = " JSON_EXTRACT(JSON_KEYS(language), ' $ [0]') = ? " ;
$condition [] = $language ;
}
if ( ! empty ( $conditions )) {
$condition [ 0 ] .= " AND (`language` IS NULL OR " . implode ( ' OR ' , $conditions ) . " ) " ;
}
return $condition ;
}
private function getMedianComments ( int $uid , int $divider ) : int
{
$languages = $this -> pConfig -> get ( $uid , 'channel' , 'languages' , [ User :: getLanguageCode ( $uid )]);
$cache_key = 'Channel:getMedianComments:' . $divider . ':' . implode ( ':' , $languages );
$comments = $this -> cache -> get ( $cache_key );
if ( ! empty ( $comments )) {
return $comments ;
}
$condition = [ " `contact-type` != ? AND `comments` > ? " , Contact :: TYPE_COMMUNITY , 0 ];
$condition = $this -> addLanguageCondition ( $uid , $condition );
$limit = $this -> database -> count ( 'post-engagement' , $condition ) / $divider ;
$post = $this -> database -> selectToArray ( 'post-engagement' , [ 'comments' ], $condition , [ 'order' => [ 'comments' => true ], 'limit' => [ $limit , 1 ]]);
$comments = $post [ 0 ][ 'comments' ] ? ? 0 ;
if ( empty ( $comments )) {
return 0 ;
}
$this -> cache -> set ( $cache_key , $comments , Duration :: HALF_HOUR );
$this -> logger -> debug ( 'Calculated median comments' , [ 'divider' => $divider , 'languages' => $languages , 'median' => $comments ]);
return $comments ;
}
private function getMedianActivities ( int $uid , int $divider ) : int
{
$languages = $this -> pConfig -> get ( $uid , 'channel' , 'languages' , [ User :: getLanguageCode ( $uid )]);
$cache_key = 'Channel:getMedianActivities:' . $divider . ':' . implode ( ':' , $languages );
$activities = $this -> cache -> get ( $cache_key );
if ( ! empty ( $activities )) {
return $activities ;
}
$condition = [ " `contact-type` != ? AND `activities` > ? " , Contact :: TYPE_COMMUNITY , 0 ];
$condition = $this -> addLanguageCondition ( $uid , $condition );
$limit = $this -> database -> count ( 'post-engagement' , $condition ) / $divider ;
$post = $this -> database -> selectToArray ( 'post-engagement' , [ 'activities' ], $condition , [ 'order' => [ 'activities' => true ], 'limit' => [ $limit , 1 ]]);
$activities = $post [ 0 ][ 'activities' ] ? ? 0 ;
if ( empty ( $activities )) {
return 0 ;
}
$this -> cache -> set ( $cache_key , $activities , Duration :: HALF_HOUR );
$this -> logger -> debug ( 'Calculated median activities' , [ 'divider' => $divider , 'languages' => $languages , 'median' => $activities ]);
return $activities ;
}
private function getMedianRelationThreadScore ( int $cid , int $divider ) : int
{
$cache_key = 'Channel:getThreadScore:' . $cid . ':' . $divider ;
$score = $this -> cache -> get ( $cache_key );
if ( ! empty ( $score )) {
return $score ;
}
$condition = [ " `relation-cid` = ? AND `relation-thread-score` > ? " , $cid , 0 ];
$limit = $this -> database -> count ( 'contact-relation' , $condition ) / $divider ;
$relation = $this -> database -> selectToArray ( 'contact-relation' , [ 'relation-thread-score' ], $condition , [ 'order' => [ 'relation-thread-score' => true ], 'limit' => [ $limit , 1 ]]);
$score = $relation [ 0 ][ 'relation-thread-score' ] ? ? 0 ;
if ( empty ( $score )) {
return 0 ;
}
$this -> cache -> set ( $cache_key , $score , Duration :: HALF_HOUR );
$this -> logger -> debug ( 'Calculated median score' , [ 'cid' => $cid , 'divider' => $divider , 'median' => $score ]);
return $score ;
}
/**
* Computes the displayed items .
*
* Community pages have a restriction on how many successive posts by the same author can show on any given page ,
* so we may have to retrieve more content beyond the first query
*
* @ return array
* @ throws \Exception
*/
protected function getCommunityItems ()
{
$items = $this -> selectItems ();
$maxpostperauthor = ( int ) $this -> config -> get ( 'system' , 'max_author_posts_community_page' );
2023-09-09 12:48:51 +00:00
if ( $maxpostperauthor != 0 && $this -> selectedTab == 'local' ) {
2023-09-09 09:30:55 +00:00
$count = 1 ;
2023-09-09 09:14:36 +00:00
$previousauthor = '' ;
2023-09-09 09:30:55 +00:00
$numposts = 0 ;
2023-09-09 09:14:36 +00:00
$selected_items = [];
2023-09-09 12:48:51 +00:00
while ( count ( $selected_items ) < $this -> itemsPerPage && ++ $count < 50 && count ( $items ) > 0 ) {
2023-09-09 09:14:36 +00:00
foreach ( $items as $item ) {
if ( $previousauthor == $item [ " author-link " ]) {
++ $numposts ;
} else {
$numposts = 0 ;
}
$previousauthor = $item [ " author-link " ];
2023-09-09 12:48:51 +00:00
if (( $numposts < $maxpostperauthor ) && ( count ( $selected_items ) < $this -> itemsPerPage )) {
2023-09-09 09:14:36 +00:00
$selected_items [] = $item ;
}
}
// If we're looking at a "previous page", the lookup continues forward in time because the list is
// sorted in chronologically decreasing order
2023-09-09 13:02:20 +00:00
if ( isset ( $this -> minId )) {
$this -> minId = $items [ 0 ][ 'commented' ];
2023-09-09 09:14:36 +00:00
} else {
// In any other case, the lookup continues backwards in time
2023-09-09 13:02:20 +00:00
$this -> maxId = $items [ count ( $items ) - 1 ][ 'commented' ];
2023-09-09 09:14:36 +00:00
}
$items = $this -> selectItems ();
}
} else {
$selected_items = $items ;
}
2023-09-09 14:13:58 +00:00
$condition = [ 'unseen' => true , 'uid' => $this -> session -> getLocalUserId (), 'parent-uri-id' => array_column ( $selected_items , 'uri-id' )];
$this -> setItemsSeenByCondition ( $condition );
2023-09-09 09:14:36 +00:00
return $selected_items ;
}
/**
* Database query for the community page
*
* @ return array
* @ throws \Exception
* @ TODO Move to repository / factory
*/
private function selectItems ()
{
2023-09-09 12:48:51 +00:00
if ( $this -> selectedTab == 'local' ) {
if ( ! is_null ( $this -> accountType )) {
$condition = [ " `wall` AND `origin` AND `private` = ? AND `owner-contact-type` = ? " , Item :: PUBLIC , $this -> accountType ];
2023-09-09 09:14:36 +00:00
} else {
$condition = [ " `wall` AND `origin` AND `private` = ? " , Item :: PUBLIC ];
}
2023-09-09 12:48:51 +00:00
} elseif ( $this -> selectedTab == 'global' ) {
if ( ! is_null ( $this -> accountType )) {
$condition = [ " `uid` = ? AND `private` = ? AND `owner-contact-type` = ? " , 0 , Item :: PUBLIC , $this -> accountType ];
2023-09-09 09:14:36 +00:00
} else {
$condition = [ " `uid` = ? AND `private` = ? " , 0 , Item :: PUBLIC ];
}
} else {
return [];
}
2023-09-09 12:48:51 +00:00
$params = [ 'order' => [ 'commented' => true ], 'limit' => $this -> itemsPerPage ];
2023-09-09 09:14:36 +00:00
2023-09-09 12:48:51 +00:00
if ( ! empty ( $this -> itemUriId )) {
$condition = DBA :: mergeConditions ( $condition , [ 'uri-id' => $this -> itemUriId ]);
2023-09-09 09:14:36 +00:00
} else {
2023-09-09 12:48:51 +00:00
if ( $this -> session -> getLocalUserId () && $this -> noSharer ) {
2023-09-09 12:00:22 +00:00
$condition = DBA :: mergeConditions ( $condition , [ " NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `post-user`.`uid` = ? AND `post-user`.`uri-id` = `post-thread-user-view`.`uri-id`) " , $this -> session -> getLocalUserId ()]);
2023-09-09 09:14:36 +00:00
}
2023-09-09 13:02:20 +00:00
if ( isset ( $this -> maxId )) {
$condition = DBA :: mergeConditions ( $condition , [ " `commented` < ? " , $this -> maxId ]);
2023-09-09 09:14:36 +00:00
}
2023-09-09 13:02:20 +00:00
if ( isset ( $this -> minId )) {
$condition = DBA :: mergeConditions ( $condition , [ " `commented` > ? " , $this -> minId ]);
2023-09-09 09:14:36 +00:00
// Previous page case: we want the items closest to min_id but for that we need to reverse the query order
2023-09-09 13:02:20 +00:00
if ( ! isset ( $this -> maxId )) {
2023-09-09 09:14:36 +00:00
$params [ 'order' ][ 'commented' ] = false ;
}
}
}
$r = Post :: selectThreadForUser ( $this -> session -> getLocalUserId () ? : 0 , [ 'uri-id' , 'commented' , 'author-link' ], $condition , $params );
$items = Post :: toArray ( $r );
if ( empty ( $items )) {
return [];
}
// Previous page case: once we get the relevant items closest to min_id, we need to restore the expected display order
2023-09-09 13:02:20 +00:00
if ( empty ( $this -> itemUriId ) && isset ( $this -> minId ) && ! isset ( $this -> maxId )) {
2023-09-09 09:14:36 +00:00
$items = array_reverse ( $items );
}
return $items ;
}
2023-09-09 14:13:58 +00:00
/**
* Sets items as seen
*
* @ param array $condition The array with the SQL condition
* @ throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
protected function setItemsSeenByCondition ( array $condition )
{
if ( empty ( $condition )) {
return ;
}
$unseen = Post :: exists ( $condition );
if ( $unseen ) {
/// @todo handle huge "unseen" updates in the background to avoid timeout errors
Item :: update ([ 'unseen' => false ], $condition );
}
}
2023-09-09 09:14:36 +00:00
}