Version 4.6.0

This commit is contained in:
Neo committed 2025-12-19 05:55:31 -08:00
1 parent f79dcf067a
commit 517a5e1f70
2036 files changed
+110041 -26162

No files matched your search

@@ -109,12 +109,21 @@ class _ArchivedPost extends Post
* @param \IPS\Member $member The memner
* @return int
*/
public static function memberPostCount( \IPS\Member $member )
public static function memberPostCount( \IPS\Member $member, bool $includeNonPostCountIncreasing = FALSE, bool $includeHiddenAndPendingApproval = TRUE )
{
return static::db()->select( 'COUNT(*)', 'forums_archive_posts', array(
array( 'archive_author_id=?', $member->member_id ),
array( \IPS\Db::i()->in( 'archive_forum_id', iterator_to_array( \IPS\Db::i()->select( 'id', 'forums_forums', 'inc_postcount=0' ) ), TRUE ) )
) )->first();
$where = [];
$where[] = [ 'archive_author_id=?', $member->member_id ];
if ( !$includeNonPostCountIncreasing )
{
$where[] = [ \IPS\Db::i()->in( 'archive_forum_id', iterator_to_array( \IPS\Db::i()->select( 'id', 'forums_forums', 'inc_postcount=0' ) ) ) ];
}
if ( !$includeHiddenAndPendingApproval )
{
$where[] = [ 'archive_queued=0' ];
}
return \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', $where )->first();
}
/**
+44 -24
View File
@@ -21,9 +21,9 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Post Model
*/
class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable, \IPS\Content\Anonymous
{
use \IPS\Content\Reactable, \IPS\Content\Reportable;
use \IPS\Content\Reactable, \IPS\Content\Reportable, \IPS\Content\Recognizable;
/**
* @brief [ActiveRecord] Multiton Store
@@ -75,7 +75,8 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \I
'edit_member_name' => 'edit_name',
'edit_reason' => 'post_edit_reason',
'hidden' => 'queued',
'first' => 'new_topic'
'first' => 'new_topic',
'is_anon' => 'post_field_t2'
);
/**
@@ -178,25 +179,27 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \I
* @param \IPS\Member $member The memner
* @return int
*/
public static function memberPostCount( \IPS\Member $member )
public static function memberPostCount( \IPS\Member $member, bool $includeNonPostCountIncreasing = FALSE, bool $includeHiddenAndPendingApproval = TRUE )
{
return \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', array(
'author_id=? AND forums_topics.forum_id IN(?)',
$member->member_id,
\IPS\Db::i()->select( 'id', 'forums_forums', 'inc_postcount=1' )
) )->join( 'forums_topics', 'tid=topic_id' )->first() ;
}
/**
* Post count for member
*
* @param \IPS\Member $member The memner
* @return int
*/
public static function rawMemberPostCount( \IPS\Member $member )
{
/* Explicitly calling to the parent so we don't filter by forum ID */
return parent::memberPostCount( $member );
$where = [];
$where[] = [ 'author_id=?', $member->member_id ];
if ( !$includeNonPostCountIncreasing )
{
$where[] = [ 'forums_topics.forum_id IN(?)', \IPS\Db::i()->select( 'id', 'forums_forums', 'inc_postcount=1' ) ];
}
if ( !$includeHiddenAndPendingApproval )
{
$where[] = [ 'queued=0' ];
}
$query = \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', $where );
if ( !$includeNonPostCountIncreasing )
{
$query = $query->join( 'forums_topics', 'tid=topic_id' );
}
return $query->first();
}
/**
@@ -240,7 +243,7 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \I
* @param array $reactions Reaction Data
* @return string
*/
public static function searchResult( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments=FALSE, $template=NULL, $reactions=array() )
public static function searchResult( array $indexData, array $authorData, array $itemData, ?array $containerData, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments=FALSE, $template=NULL, $reactions=array() )
{
/* Password protected */
if (
@@ -405,6 +408,11 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \I
*/
public static function _indefiniteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
{
if ( !$containerData )
{
return parent::_indefiniteArticle( $containerData, $lang );
}
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
if ( $bitOptions['bw_enable_answers'] )
@@ -424,20 +432,32 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \I
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param \IPS\Lang|NULL $lang The language to use, or NULL for the language of the currently logged in member
* @param array $options Options to pass to \IPS\Lang::addToStack
* @param integer|boolean $count Count of things; if int > 1, uses pluralized version of definite article
* @return string
*/
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL, $options = array() )
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL, $options = array(), $count = FALSE )
{
if ( !$containerData )
{
return parent::_definiteArticle( $containerData, $lang, $options );
}
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
if ( $bitOptions['bw_enable_answers'] )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
if( \is_int( $count ) )
{
$options['pluralize'] = array( $count );
return $lang->addToStack( '__defart_answer_plural', FALSE, $options );
}
return $lang->addToStack( '__defart_answer', FALSE, $options );
}
else
{
return parent::_definiteArticle( $containerData, $lang, $options );
return parent::_definiteArticle( $containerData, $lang, $options, $count );
}
}
+109 -41
View File
@@ -33,9 +33,10 @@ class _Topic extends \IPS\Content\Item implements
\IPS\Content\Ratings,
\IPS\Content\Searchable,
\IPS\Content\Embeddable,
\IPS\Content\MetaData
\IPS\Content\MetaData,
\IPS\Content\Anonymous
{
use \IPS\Content\Reactable, \IPS\Content\Reportable, \IPS\Content\Statistics, \IPS\Content\Solvable;
use \IPS\Content\Reactable, \IPS\Content\Reportable, \IPS\Content\Statistics, \IPS\Content\Solvable { toggleSolveComment as protected _toggleSolveComment; }
/**
* @brief Not archived
@@ -119,7 +120,9 @@ class _Topic extends \IPS\Content\Item implements
'state' => 'state',
'updated' => 'last_post',
'meta_data' => 'topic_meta_data',
'solved_comment_id' => 'topic_answered_pid'
'solved_comment_id' => 'topic_answered_pid',
'is_anon' => 'is_anon',
'last_comment_anon' => 'last_poster_anon',
);
/**
@@ -332,23 +335,27 @@ class _Topic extends \IPS\Content\Item implements
{
$joinContainer = TRUE;
$member = $member ?: \IPS\Member::loggedIn();
$whereString = 'forums_forums.password=? OR ' . \IPS\Db::i()->findInSet( 'forums_forums.password_override', $member->groups );
$whereParams = array( NULL );
if ( \IPS\Dispatcher::hasInstance() AND $member->member_id === \IPS\Member::loggedIn()->member_id )
{
foreach ( \IPS\Request::i()->cookie as $k => $v )
$containerClass = static::$containerNodeClass;
if ( $containerClass::hasPasswordForums() )
{
$whereString = 'forums_forums.password=? OR ' . \IPS\Db::i()->findInSet( 'forums_forums.password_override', $member->groups );
$whereParams = array( NULL );
if ( \IPS\Dispatcher::hasInstance() AND $member->member_id === \IPS\Member::loggedIn()->member_id )
{
if ( mb_substr( $k, 0, 13 ) === 'ipbforumpass_' )
foreach ( \IPS\Request::i()->cookie as $k => $v )
{
$whereString .= ' OR ( forums_forums.id=? AND MD5(forums_forums.password)=? )';
$whereParams[] = (int) mb_substr( $k, 13 );
$whereParams[] = $v;
if ( mb_substr( $k, 0, 13 ) === 'ipbforumpass_' )
{
$whereString .= ' OR ( forums_forums.id=? AND MD5(forums_forums.password)=? )';
$whereParams[] = (int) mb_substr( $k, 13 );
$whereParams[] = $v;
}
}
}
$where['container'][] = array_merge( array( '( ' . $whereString . ' )' ), $whereParams );
}
$where['container'][] = array_merge( array( '( ' . $whereString . ' )' ), $whereParams );
}
/* Don't show topics from forums in which topics only show to the poster */
@@ -370,7 +377,7 @@ class _Topic extends \IPS\Content\Item implements
$where['item'][] = array( 'forums_topics.starter_id=?', $member->member_id );
}
}
elseif ( !$member->modPermission('can_read_all_topics') or ( $member->modPermission('forums') !== TRUE and !\in_array( $skipPermission->_id, $member->modPermission('forums') ) ) )
elseif ( !$member->modPermission('can_read_all_topics') or ( \is_array( $member->modPermission('forums') ) and !\in_array( $skipPermission->_id, $member->modPermission('forums') ) ) )
{
$where['item'][] = array( 'forums_topics.starter_id=?', $member->member_id );
}
@@ -674,17 +681,16 @@ class _Topic extends \IPS\Content\Item implements
/* Moderator actions */
if ( isset( $values['topic_create_state'] ) )
{
if ( $this->canHide() )
if( \in_array( 'hide', $values['topic_create_state'] ) )
{
if( \in_array( 'hide', $values['topic_create_state'] ) )
if ( $this->canHide() )
{
$this->hide( NULL );
}
/* Only unhide if the topic is not pending approval */
elseif( $this->hidden() !== 1 )
{
$this->unhide( NULL );
}
}
elseif( $this->hidden() and $this->hidden() !== 1 and $this->canUnhide() )
{
$this->unhide( NULL );
}
}
}
@@ -1040,12 +1046,15 @@ class _Topic extends \IPS\Content\Item implements
{
parent::delete();
try
if( \in_array( $this->archive_status, array( static::ARCHIVE_DONE, static::ARCHIVE_WORKING, static::ARCHIVE_RESTORE ) ) )
{
\IPS\forums\Topic\ArchivedPost::db()->delete( 'forums_archive_posts', array( 'archive_topic_id=?', $this->tid ) );
try
{
\IPS\forums\Topic\ArchivedPost::db()->delete( 'forums_archive_posts', array( 'archive_topic_id=?', $this->tid ) );
}
/* catch db exceptions if e.g. if the connection credentials didn't work or if the database doesn't exist anymore */
catch ( \IPS\Db\Exception $e ){}
}
/* catch db exceptions if e.g. if the connection credentials didn't work or if the database doesn't exist anymore */
catch ( \IPS\Db\Exception $e ){}
\IPS\Db::i()->delete( 'forums_question_ratings', array( 'topic=?', $this->tid ) );
\IPS\Db::i()->delete( 'forums_answer_ratings', array( 'topic=?', $this->tid ) );
@@ -1314,7 +1323,25 @@ class _Topic extends \IPS\Content\Item implements
*/
public function containerAllowsMemberSolvable()
{
return $this->container()->forums_bitoptions['bw_enable_answers_member'];
return ( $this->containerAllowsSolvable() AND $this->container()->forums_bitoptions['bw_enable_answers_member'] );
}
/**
* Toggle the solve value of a comment
*
* @param int $commentId The comment ID
* @param boolean $value TRUE/FALSE value
* @param \IPS\Member $member The member (null for currently logged in member)
*/
public function toggleSolveComment( $commentId, $value, \IPS\Member $member = NULL )
{
if ( $value )
{
$post = \IPS\forums\Topic\Post::load( $commentId );
$post->author()->achievementAction( 'forums', 'AnswerMarkedBest', $post );
}
return $this->_toggleSolveComment( $commentId, $value, $member );
}
/**
@@ -1533,21 +1560,34 @@ class _Topic extends \IPS\Content\Item implements
* @param array $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param \IPS\Lang|NULL $lang The language to use, or NULL for the language of the currently logged in member
* @param array $options Options to pass to \IPS\Lang::addToStack
* @param integer|boolean $count Number of items. If not false, pluralized version of phrase will be used.
* @return string
*/
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL, $options = array() )
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL, $options = array(), $count = FALSE )
{
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
if( $containerData !== NULL )
{
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
if ( $bitOptions['bw_enable_answers'] )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
if( $count === TRUE || \is_int( $count ) )
{
if( \is_int( $count ) )
{
$options['pluralize'] = array( $count );
}
return $lang->addToStack( '__defart_question_plural', FALSE, $options );
}
return $lang->addToStack( '__defart_question', FALSE, $options );
}
}
if ( $bitOptions['bw_enable_answers'] )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( '__defart_question', FALSE, $options );
}
else
{
return parent::_definiteArticle( $containerData, $lang, $options );
}
return parent::_definiteArticle( $containerData, $lang, $options, $count );
}
/* !Sitemap */
@@ -2149,8 +2189,6 @@ class _Topic extends \IPS\Content\Item implements
/* ! Reactions */
public $reputation = array();
/**
* Reaction type
*
@@ -2265,4 +2303,34 @@ class _Topic extends \IPS\Content\Item implements
return FALSE;
}
/**
* We need to force an index so that super long topics load when fetching IDs before running the main query
*
* @return string|null
*/
/**
* We need to force an index so that super long topics load when fetching IDs before running the main query
*
* @return string
*/
protected function forceIndexForPaginatedIds()
{
if ( ! $this->isArchived() )
{
return 'first_post';
}
return NULL;
}
/**
* WHERE clause for getting items for ACP overview statistics
*
* @return array
*/
public static function overviewStatisticsWhere()
{
return array( array( \IPS\Db::i()->in( 'state', array( 'link', 'merged' ), TRUE ) ) );
}
}