Version 5.0.13

This commit is contained in:
Neo committed 2025-12-19 19:04:57 -08:00
1 parent b89858b2ff
commit 5efe744c5f
1407 files changed
+69690 -30177

No files matched your search

+119 -119
View File
@@ -24,6 +24,7 @@ use IPS\Content\Comment;
use IPS\Content\Item;
use IPS\Content\Search\Index;
use IPS\Content\Search\SearchContent;
use IPS\Content\Taggable;
use IPS\Content\ViewUpdates;
use IPS\Data\Store;
use IPS\DateTime;
@@ -57,6 +58,7 @@ use IPS\Member\Club;
use IPS\Member\Group;
use IPS\Node\Colorize;
use IPS\Node\DelayedCount;
use IPS\Node\Grouping;
use IPS\Node\Icon;
use IPS\Node\Model;
use IPS\Node\Permissions;
@@ -107,6 +109,7 @@ class Forum extends Model implements Permissions
use ClubContainer;
use Colorize;
use DelayedCount;
use Grouping;
use Statistics;
use ViewUpdates;
use Icon;
@@ -284,7 +287,7 @@ class Forum extends Model implements Permissions
*/
public function __set( mixed $key, mixed $value ) : void
{
if( mb_strpos( $key, "forum_" ) === 0 AND $key !== 'forum_allow_rating' )
if( mb_strpos( $key, "forum_" ) === 0 )
{
$key = preg_replace( "/^forum_(.+?)$/", "$1", $key );
$this->$key = $value;
@@ -705,6 +708,8 @@ class Forum extends Model implements Permissions
*/
public function lastPost( int $count=1, bool $isChild=false ): ?array
{
$results = [];
if ( $count > 5 )
{
throw new OverflowException( 'Too many posts to return, maximum is 5' );
@@ -718,13 +723,15 @@ class Forum extends Model implements Permissions
{
try
{
$results = [];
foreach(
new ActiveRecordIterator(
Db::i()->select( '*', 'forums_posts', array( 'topic_id=? AND queued=0', Db::i()->select( 'tid', 'forums_topics', array( 'forum_id=? AND approved=1 AND starter_id=? AND is_future_entry=0', $this->_id, Member::loggedIn()->member_id ), 'last_post DESC', 1 )->first() ), 'post_date DESC', $count ),
Post::class ) as $post )
{
/* @var Post $post */
$results[ $post->post_date ] = [
'_author' => $post->author()->member_id,
'author' => $post->author(),
'topic_url' => $post->item()->url(),
'topic_title' => $post->item()->title,
@@ -743,33 +750,24 @@ class Forum extends Model implements Permissions
foreach( $this->children() as $child )
{
/* We need to merge all children and pick the top 5 */
if ( $childLastPost = $child->lastPost( $count ) )
if ( $childLastPost = $child->lastPost( $count, true ) )
{
$results = $results + $childLastPost;
if ( is_array( $childLastPost ) )
{
if ( isset( $childLastPost['date'] ) )
{
$results[$childLastPost['date']] = $childLastPost;
}
else
{
$results = $results + $childLastPost;
}
}
}
}
if ( count( $results ) )
{
krsort( $results );
if ( $count === 1 )
{
/* return the first from the array */
return array_shift( $results );
}
/* array_slice re-indexes, and we'd lose the krsort timestamp key */
return array_intersect_key( $results, array_flip( array_slice( array_keys( $results ), 0, $count ) ) );
}
else
{
return null;
}
}
elseif ( !$this->permission_showtopic and !$this->can('view') )
{
$results = [];
if( !$this->sub_can_post )
{
foreach( $this->children() as $child )
@@ -777,47 +775,38 @@ class Forum extends Model implements Permissions
/* We need to merge all children and pick the top 5 */
if ( $childLastPost = $child->lastPost( $count, true ) )
{
$results = $results + $childLastPost;
if ( is_array( $childLastPost ) )
{
if ( isset( $childLastPost['date'] ) )
{
$results[$childLastPost['date']] = $childLastPost;
}
else
{
$results = $results + $childLastPost;
}
}
}
}
}
if ( count( $results ) )
{
krsort( $results );
if ( $count === 1 )
{
/* return the first from the array */
return array_shift( $results );
}
/* array_slice re-indexes, and we'd lose the krsort timestamp key */
return array_intersect_key( $results, array_flip( array_slice( array_keys( $results ), 0, $count ) ) );
}
else
{
return null;
}
}
else
{
$results = [];
/* Do we have any data, or do we need to update? The default or cleared state is NULL, forums without topics should have [] */
if ( $this->sub_can_post and $this->posts and ! $this->_data['last_post_data'] )
if ( $this->sub_can_post and $this->posts and !$this->_data['last_post_data'] )
{
$this->setLastComment();
/* We can't use save as dynamic variables have now been assigned which confuses save() */
Db::i()->update( 'forums_forums', [ 'last_post_data' => $this->_data['last_post_data'] ], [ 'id=?', $this->_id ] );
Db::i()->update( 'forums_forums', ['last_post_data' => $this->_data['last_post_data']], ['id=?', $this->_id] );
}
$lastPostData = $this->_last_post_data;
if ( count( $lastPostData ) )
{
foreach( $lastPostData as $lastPostTime => $lastPost )
foreach ( $lastPostData as $lastPostTime => $lastPost )
{
if ( $this->sub_can_post and !$this->permission_showtopic and ! $this->can('read') )
if ( $this->sub_can_post and !$this->permission_showtopic and !$this->can( 'read' ) )
{
$lastPost['last_title'] = null;
}
@@ -829,31 +818,31 @@ class Forum extends Model implements Permissions
}
else
{
$author = ! empty( $lastPost['last_poster_id'] ) ? $lastPost['last_poster_id'] : ( $lastPost['last_poster_name'] ?? Member::loggedIn()->language()->addToStack( "guest" ) );
$author = !empty( $lastPost['last_poster_id'] ) ? $lastPost['last_poster_id'] : ( $lastPost['last_poster_name'] ?? Member::loggedIn()->language()->addToStack( "guest" ) );
}
$results[ $lastPostTime ] = array(
'author' => null,
'_author' => $author,
'topic_url' => Url::internal( "app=forums&module=forums&controller=topic&id={$lastPost['last_id']}", 'front', 'forums_topic', array( $lastPost['seo_last_title'] ) ),
'topic_title' => $lastPost['last_title'],
'date' => ( $lastPost['last_post'] ?? (int) ( substr( $lastPostTime, 0, strpos( $lastPostTime, '.' ) ) ) ),
'last_poster_anon' => $lastPost['last_poster_anon'],
$results[$lastPostTime] = [
'author' => null,
'_author' => $author,
'topic_url' => Url::internal( "app=forums&module=forums&controller=topic&id={$lastPost['last_id']}", 'front', 'forums_topic', [$lastPost['seo_last_title']] ),
'topic_title' => $lastPost['last_title'],
'date' => ( $lastPost['last_post'] ?? (int)( substr( $lastPostTime, 0, strpos( $lastPostTime, '.' ) ) ) ),
'last_poster_anon' => $lastPost['last_poster_anon'],
'last_post_snippet' => $lastPost['last_post_snippet'] ?? null,
'posts' => $lastPost['posts'] ?? 0
);
'posts' => $lastPost['posts'] ?? 0
];
}
}
foreach( $this->children() as $child )
foreach ( $this->children() as $child )
{
/* @var Forum $child */
/* We need to merge all children and pick the top 5 */
if ( $childLastPost = $child->lastPost( $count, true ) )
{
if( is_array( $childLastPost ) )
if ( is_array( $childLastPost ) )
{
if( isset( $childLastPost['date'] ) )
if ( isset( $childLastPost['date'] ) )
{
$results[$childLastPost['date']] = $childLastPost;
}
@@ -864,75 +853,76 @@ class Forum extends Model implements Permissions
}
}
}
}
if ( count( $results ) )
if ( count( $results ) )
{
/* Don't process the author details if we're not going to use them */
if ( ! $isChild )
{
/* Don't process the author details if we're not going to use them */
if ( ! $isChild )
{
$membersToLoad = [];
$membersToLoad = [];
/* Let's get the author details */
foreach ( $results as $timestamp => $data )
/* Let's get the author details */
foreach ( $results as $timestamp => $data )
{
if ( $data['_author'] and is_int( $data['_author'] ) )
{
if ( $data['_author'] and is_int( $data['_author'] ) )
$membersToLoad[ $timestamp ] = $data['_author'];
}
else
{
/* Default to a guest account so we can be sure the author is never null */
$results[ $timestamp ]['author'] = new Member;
if ( $data['_author'] and is_string( $data['_author'] ) )
{
$membersToLoad[ $timestamp ] = $data['_author'];
$results[ $timestamp ]['author']->name = $data['_author'];
}
}
}
$idsToLoad = array_unique( array_values( $membersToLoad ) );
/* Load the members not in static::$lastPostLoadedMembers */
$idsToLoad = array_diff( $idsToLoad, array_keys( static::$lastPostLoadedMembers ) );
if ( count( $idsToLoad ) )
{
foreach( Db::i()->select( '*', 'core_members', [ Db::i()->in( 'member_id', $idsToLoad ) ] ) as $lastPostMember )
{
static::$lastPostLoadedMembers[ $lastPostMember['member_id'] ] = Member::constructFromData( $lastPostMember );
}
}
if ( count( $membersToLoad ) )
{
foreach ( $membersToLoad as $timestamp => $memberId )
{
if ( isset( static::$lastPostLoadedMembers[ $memberId ] ) )
{
$results[$timestamp]['author'] = static::$lastPostLoadedMembers[ $memberId ];
}
else
{
/* Default to a guest account so we can be sure the author is never null */
$results[ $timestamp ]['author'] = new Member;
if ( $data['_author'] and is_string( $data['_author'] ) )
{
$results[ $timestamp ]['author']->name = $data['_author'];
}
}
}
$idsToLoad = array_unique( array_values( $membersToLoad ) );
/* Load the members not in static::$lastPostLoadedMembers */
$idsToLoad = array_diff( $idsToLoad, array_keys( static::$lastPostLoadedMembers ) );
if ( count( $idsToLoad ) )
{
foreach( Db::i()->select( '*', 'core_members', [ Db::i()->in( 'member_id', $idsToLoad ) ] ) as $lastPostMember )
{
static::$lastPostLoadedMembers[ $lastPostMember['member_id'] ] = Member::constructFromData( $lastPostMember );
}
}
if ( count( $membersToLoad ) )
{
foreach ( $membersToLoad as $timestamp => $memberId )
{
if ( isset( static::$lastPostLoadedMembers[ $memberId ] ) )
{
$results[$timestamp]['author'] = static::$lastPostLoadedMembers[ $memberId ];
}
else
{
/* Technically we shouldn't ever get here, but let's not throw an exception */
$results[$timestamp]['author'] = Member::load( $memberId );
}
/* Technically we shouldn't ever get here, but let's not throw an exception */
$results[$timestamp]['author'] = Member::load( $memberId );
}
}
}
krsort( $results );
if ( $count === 1 )
{
/* return the first from the array */
return array_shift( $results );
}
/* array_slice re-indexes, and we'd lose the krsort timestamp key */
return array_intersect_key( $results, array_flip( array_slice( array_keys( $results ), 0, $count ) ) );
}
else
krsort( $results );
if ( $count === 1 )
{
return null;
/* return the first from the array */
return array_shift( $results );
}
/* array_slice re-indexes, and we'd lose the krsort timestamp key */
return array_intersect_key( $results, array_flip( array_slice( array_keys( $results ), 0, $count ) ) );
}
else
{
return null;
}
}
@@ -2091,10 +2081,8 @@ class Forum extends Model implements Permissions
/* Do the move */
Db::i()->update( 'forums_topics', array( 'forum_id' => $node->_id ), array( 'forum_id=?', $this->_id ) );
Db::i()->update( 'forums_question_ratings', array( 'forum' => $node->_id ), array( 'forum=?', $this->_id ) );
/* Rebuild tags */
if ( in_array( 'IPS\Content\Taggable', class_implements( $contentItemClass ) ) )
if( IPS::classUsesTrait( $contentItemClass, Taggable::class ) )
{
Db::i()->update( 'core_tags', array(
'tag_aap_lookup' => md5( static::$permApp . ';' . static::$permType . ';' . $node->_id ),
@@ -2214,11 +2202,14 @@ class Forum extends Model implements Permissions
* @return array
* @apiresponse int id ID number
* @apiresponse string name Forum name
* @apiresponse string description Forum description
* @apiresponse string cardImage Forum card image
* @apiresponse string path Forum name including parents (e.g. "Example Category > Example Forum")
* @apiresponse string type The type of forum: "discussions", "questions", "category", or "redirect"
* @apiresponse int topics Number of topics in forum
* @apiresponse string url URL
* @apiresponse int|null parentId Parent Node ID
* @apiresponse int followerCount Total members following this forum
* @clientapiresponse object|null permissions Node permissions
*/
public function apiOutput( Member $authorizedMember = NULL ): array
@@ -2246,11 +2237,14 @@ class Forum extends Model implements Permissions
$return = array(
'id' => $this->id,
'name' => $this->_title,
'description' => $this->description,
'cardImage' => null,
'path' => implode( ' > ', $path ),
'type' => $type,
'topics' => $this->topics,
'url' => (string) $this->url(),
'parentId' => static::$databaseColumnParent ? $this->{static::$databaseColumnParent} : NULL
'parentId' => static::$databaseColumnParent ? $this->{static::$databaseColumnParent} : NULL,
'followerCount' => Topic::containerFollowerCount( $this )
);
if( $authorizedMember === NULL )
@@ -2271,6 +2265,12 @@ class Forum extends Model implements Permissions
}
}
if ( $this->card_image )
{
$file = File::get( 'forums_Cards', $this->card_image );
$return['card_image'] = $file->fullyQualifiedUrl( $this->card_image );
}
return $return;
}