Version 4.7.6

This commit is contained in:
Neo committed 2025-12-19 16:05:19 -08:00
1 parent 8ba7d43898
commit 7b7404e741
1085 files changed
+30590 -7837

No files matched your search

+151 -22
View File
@@ -223,14 +223,15 @@ abstract class _Item extends \IPS\Content
* @param \IPS\DateTime $time The time
* @param \IPS\Node\Model|NULL $container Container (e.g. forum), if appropriate
* @param bool|NULL $hidden Hidden? (NULL to work our automatically)
* @param \IPS\DateTime|NULL $futureDate Publish date for future items
* @return static
*/
public static function createItem( \IPS\Member $author, $ipAddress, \IPS\DateTime $time, \IPS\Node\Model $container = NULL, $hidden=NULL )
public static function createItem(\IPS\Member $author, $ipAddress, \IPS\DateTime $time, \IPS\Node\Model $container = NULL, $hidden=NULL)
{
/* Create the object */
$obj = new static;
foreach ( array( 'date', 'updated', 'author', 'author_name', 'ip_address', 'last_comment', 'last_comment_by', 'last_comment_name', 'last_review', 'container', 'approved', 'hidden', 'locked', 'status', 'views', 'pinned', 'featured', 'is_future_entry', 'num_comments', 'num_reviews', 'unapproved_comments', 'hidden_comments', 'unapproved_reviews', 'hidden_reviews' ) as $k )
foreach ( array( 'date', 'updated', 'author', 'author_name', 'ip_address', 'last_comment', 'last_comment_by', 'last_comment_name', 'last_review', 'container', 'approved', 'hidden', 'locked', 'status', 'views', 'pinned', 'featured', 'is_future_entry', 'num_comments', 'num_reviews', 'unapproved_comments', 'hidden_comments', 'unapproved_reviews', 'hidden_reviews', 'future_date' ) as $k )
{
if ( isset( static::$databaseColumnMap[ $k ] ) )
{
@@ -244,6 +245,8 @@ abstract class _Item extends \IPS\Content
case 'last_comment':
case 'last_review':
case 'date':
$val = $time->getTimestamp();
break;
case 'updated':
$val = $time->getTimestamp();
break;
@@ -321,6 +324,9 @@ abstract class _Item extends \IPS\Content
case 'is_future_entry':
$val = ( $time->getTimestamp() > time() ) ? 1 : 0;
break;
case 'future_date':
$val = ( $time->getTimestamp() > time() ) ? $time->getTimestamp() : time();
break;
}
foreach ( \is_array( static::$databaseColumnMap[ $k ] ) ? static::$databaseColumnMap[ $k ] : array( static::$databaseColumnMap[ $k ] ) as $column )
@@ -329,7 +335,7 @@ abstract class _Item extends \IPS\Content
}
}
}
/* Update the container */
if ( $container )
{
@@ -399,10 +405,10 @@ abstract class _Item extends \IPS\Content
}
/* Create the item */
$time = ( static::canFuturePublish( NULL, $container ) and isset( static::$databaseColumnMap['date'] ) and isset( $values[ static::$formLangPrefix . 'date' ] ) and $values[ static::$formLangPrefix . 'date' ] instanceof \IPS\DateTime ) ? $values[ static::$formLangPrefix . 'date' ] : new \IPS\DateTime;
$time = ( static::canFuturePublish( NULL, $container ) and isset( static::$databaseColumnMap['future_date'] ) and isset( $values[ static::$formLangPrefix . 'date' ] ) and $values[ static::$formLangPrefix . 'date' ] instanceof \IPS\DateTime ) ? $values[ static::$formLangPrefix . 'date' ] : new \IPS\DateTime;
/* Create the item */
$obj = static::createItem( $member, \IPS\Request::i()->ipAddress(), $time, $container );
$obj = static::createItem( $member, \IPS\Request::i()->ipAddress(), $time, $container, NULL );
$obj->processBeforeCreate( $values );
$obj->processForm( $values );
$obj->save();
@@ -423,9 +429,6 @@ abstract class _Item extends \IPS\Content
$idColumn = static::$databaseColumnId;
$commentIdColumn = $commentClass::$databaseColumnId;
$parameters = array_merge( array( 'newContentItem-' . static::$application . '/' . static::$module . '-' . ( $container ? $container->_id : 0 ) ), $comment->attachmentIds() );
\IPS\File::claimAttachments( ...$parameters );
if ( isset( static::$databaseColumnMap['first_comment_id'] ) )
{
@@ -858,9 +861,9 @@ abstract class _Item extends \IPS\Content
}
/* Future date */
if ( \in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) and static::canFuturePublish( NULL, $container ) and isset( static::$databaseColumnMap['date'] ) )
if ( \in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) and static::canFuturePublish( NULL, $container ) and isset( static::$databaseColumnMap['future_date'] ) )
{
$column = static::$databaseColumnMap['date'];
$column = static::$databaseColumnMap['future_date'];
$return['date'] = new \IPS\Helpers\Form\Date( static::$formLangPrefix . 'date', ( $item and $item->$column ) ? \IPS\DateTime::ts( $item->$column ) : 0, FALSE, array( 'time' => TRUE, 'unlimited' => 0, 'unlimitedLang' => 'immediately'), NULL, NULL, NULL, static::$formLangPrefix . 'date' );
}
@@ -1071,6 +1074,58 @@ abstract class _Item extends \IPS\Content
{
\IPS\core\IndexNow::addUrlToQueue( $this->url() );
}
/* Was it moderated? Let's see why. */
if ( $this->hidden() === 1 )
{
$idColumn = static::$databaseColumnId;
/* Check we don't already have a reason from profanity / url / email filters */
try
{
\IPS\core\Approval::loadFromContent( \get_called_class(), $this->$idColumn );
}
catch( \OutOfRangeException $e )
{
/* If the user is mod-queued - that's why. These will cascade, so check in that order. */
$foundReason = FALSE;
$log = new \IPS\core\Approval;
$log->content_class = \get_called_class();
$log->content_id = $this->$idColumn;
if ( $this->author()->mod_posts )
{
$log->held_reason = 'user';
$foundReason = TRUE;
}
/* If the user isn't mod queued, but is in a group that is, that's why. */
if ( $foundReason === FALSE AND $this->author()->group['g_mod_preview'] )
{
$log->held_reason = 'group';
$foundReason = TRUE;
}
/* If the user isn't on mod queue, but the container requires approval, that's why. */
if ( $foundReason === FALSE )
{
try
{
if ( $this->container() AND $this->container()->contentHeldForApprovalByNode( 'item', $this->author() ) === TRUE )
{
$log->held_reason = 'node';
$foundReason = TRUE;
}
}
catch( \BadMethodCallException $e ) { }
}
if ( $foundReason )
{
$log->save();
}
}
}
}
/**
@@ -1179,7 +1234,6 @@ abstract class _Item extends \IPS\Content
if ( $this instanceof \IPS\Content\FuturePublishing AND isset( $values[ static::$formLangPrefix . 'date' ] ) )
{
$column = static::$databaseColumnMap['is_future_entry'];
if ( $container AND $this->$column )
@@ -1195,6 +1249,8 @@ abstract class _Item extends \IPS\Content
if ( $values[ static::$formLangPrefix . 'date' ] instanceof \IPS\DateTime AND $values[ static::$formLangPrefix . 'date' ]->getTimestamp() > time() )
{
/* Was not future, but now is */
$dateColumn = static::$databaseColumnMap['future_date'];
$this->$dateColumn = $values[ static::$formLangPrefix . 'date' ]->getTimestamp();
$this->unPublish();
}
}
@@ -1980,6 +2036,9 @@ abstract class _Item extends \IPS\Content
}
}
/* Update reports */
\IPS\Db::i()->update( 'core_rc_index', array( 'node_id' => $container->_id ), array( 'class=? and content_id=?', \get_class( $this ), $oldContainer->_id ) );
/* Update caches */
$this->expireWidgetCaches();
@@ -2153,6 +2212,13 @@ abstract class _Item extends \IPS\Content
/* Update notifications */
\IPS\Db::i()->update( 'core_notifications', array( 'item_id' => $this->$idColumn ), array( 'item_class=? and item_id=?', (string) \get_class( $item ), $item->$idColumn ) );
/* Follows */
if ( $this instanceof \IPS\Content\Followable )
{
\IPS\Db::i()->update( 'core_follow', "`follow_id` = MD5( CONCAT( `follow_app`, ';', `follow_area`, ';', {$this->$idColumn}, ';', `follow_member_id` ) ), `follow_rel_id` = {$this->$idColumn}", array( "follow_id=MD5( CONCAT( `follow_app`, ';', `follow_area`, ';', {$item->$idColumn}, ';', `follow_member_id` ) )" ), array(), NULL, \IPS\Db::IGNORE );
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'class=? AND id=?', \get_called_class(), (int) $this->$idColumn ) );
}
/* Update moderation history */
\IPS\Db::i()->update( 'core_moderator_logs', array( 'item_id' => $this->$idColumn ), array( 'item_id=? AND class=?', $item->$idColumn, (string) \get_class( $this ) ) );
\IPS\Session::i()->modLog( 'modlog__action_merge', array( $item->mapped('title') => FALSE, $this->url()->__toString() => FALSE, $this->mapped('title') => FALSE ), $this );
@@ -2927,13 +2993,26 @@ abstract class _Item extends \IPS\Content
* @param bool $joinAuthor If true, will join the members table for the author
* @param bool $joinLastCommenter If true, will join the members table for the last commenter
* @param bool $showMovedLinks If true, moved item links are included in the results
* @param array|null $location Array of item lat and long
* @return \IPS\Patterns\ActiveRecordIterator|int
*/
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=\IPS\Content\Hideable::FILTER_AUTOMATIC, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL, $skipPermission=FALSE, $joinTags=TRUE, $joinAuthor=TRUE, $joinLastCommenter=TRUE, $showMovedLinks=FALSE )
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=\IPS\Content\Hideable::FILTER_AUTOMATIC, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL, $skipPermission=FALSE, $joinTags=TRUE, $joinAuthor=TRUE, $joinLastCommenter=TRUE, $showMovedLinks=FALSE, $location=NULL )
{
/* Are we trying to improve count performance? */
$countShortcut = FALSE;
$having = NULL;
if ( isset( $location['lat'] ) and isset( $location['lon'] ) )
{
/* Make sure co-ordinates are in a valid format regardless of locale */
$location['lat'] = number_format( $location['lat'], 6, '.', '' );
$location['lon'] = number_format( $location['lon'], 6, '.', '' );
$where[] = array( static::$databasePrefix . 'latitude' . ' IS NOT NULL AND ' . static::$databasePrefix . 'longitude' . ' IS NOT NULL' );
$having = array( 'distance < 500' );
$order = 'distance ASC';
}
/* Do we really need tags? */
if ( $joinTags and ! \IPS\Settings::i()->tags_enabled )
{
@@ -3135,6 +3214,12 @@ abstract class _Item extends \IPS\Content
{
static::$permissionSelect[ $lookupKey ] = array();
$permQuery = \IPS\Db::i()->select( 'perm_type_id', 'core_permission_index', array( "core_permission_index.app='" . $containerClass::$permApp . "' AND core_permission_index.perm_type='" . $containerClass::$permType . "' AND (" . \IPS\Db::i()->findInSet( 'perm_' . $containerClass::$permissionMap[ $permissionKey ], $member->permissionArray() ) . ' OR ' . 'perm_' . $containerClass::$permissionMap[ $permissionKey ] . "='*' )" ) );
/* If we cannot access clubs, skip them */
if ( \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) AND !$member->canAccessModule( \IPS\Application\Module::get( 'core', 'clubs', 'front' ) ) )
{
$containerWhere[] = array( $containerClass::$databaseTable . '.' . $containerClass::$databasePrefix . $containerClass::clubIdColumn() . ' IS NULL' );
}
if ( \count( $containerWhere ) )
{
@@ -3287,6 +3372,11 @@ abstract class _Item extends \IPS\Content
$selectClause = static::$databaseTable . '.*';
if ( isset( $location['lat'] ) and isset( $location['lon'] ) and is_numeric( $location['lat'] ) and is_numeric( $location['lon'] ) )
{
$selectClause .= ', ( 3959 * acos( cos( radians(' . $location['lat'] . ') ) * cos( radians( ' . static::$databasePrefix . 'latitude' . ' ) ) * cos( radians( ' . static::$databasePrefix . 'longitude' . ' ) - radians( ' . $location['lon'] . ' ) ) + sin( radians( ' . $location['lat'] . ' ) ) * sin( radians( ' . static::$databasePrefix . 'latitude' . ') ) ) ) AS distance';
}
if( $joinAuthor and isset( static::$databaseColumnMap['author'] ) )
{
$selectClause .= ', author.*';
@@ -3318,7 +3408,7 @@ abstract class _Item extends \IPS\Content
$selectClause .= ', core_tags_cache.tag_cache_text';
}
$select = \IPS\Db::i()->select( $selectClause, static::$databaseTable, $where, $order, $limit, $groupBy, NULL, $queryFlags );
$select = \IPS\Db::i()->select( $selectClause, static::$databaseTable, $where, $order, $limit, $groupBy, $having, $queryFlags );
}
/* Join stuff */
@@ -3410,15 +3500,15 @@ abstract class _Item extends \IPS\Content
throw new \BadMethodCallException;
}
$where = array( array( static::$databasePrefix . static::$databaseColumnMap['featured'] . '=?', 1 ) );
$where = array( array( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['featured'] . '=?', 1 ) );
if ( $container )
{
$where[] = array( static::$databasePrefix . static::$databaseColumnMap['container'] . '=?', $container->_id );
$where[] = array( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['container'] . '=?', $container->_id );
}
if ( \in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) )
{
$where[] = array( static::$databasePrefix . static::$databaseColumnMap['is_future_entry'] . '=?', 0 );
$where[] = array( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['is_future_entry'] . '=?', 0 );
}
return static::getItemsWithPermission( $where, $order, $limit );
@@ -4876,7 +4966,9 @@ abstract class _Item extends \IPS\Content
'app' => static::$application,
'key' => mb_ucfirst( static::$module ),
'autoSaveKey' => 'reply-' . static::$application . '/' . static::$module . '-' . $this->$idColumn,
'minimize' => isset( \IPS\Request::i()->$submitted ) ? NULL : static::$formLangPrefix . '_comment_placeholder'
'minimize' => isset( \IPS\Request::i()->$submitted ) ? NULL : static::$formLangPrefix . '_comment_placeholder',
'contentClass' => \get_called_class(),
'contentId' => $this->$idColumn
), function() use( $self ) {
if ( !$self->mergeConcurrentComment() )
{
@@ -8405,7 +8497,7 @@ abstract class _Item extends \IPS\Content
public function unpublish( $member=NULL )
{
/* Now do the actual stuff */
if ( isset( static::$databaseColumnMap['is_future_entry'] ) AND isset( static::$databaseColumnMap['date'] ) )
if ( isset( static::$databaseColumnMap['is_future_entry'] ) AND isset( static::$databaseColumnMap['future_date'] ) )
{
$future = static::$databaseColumnMap['is_future_entry'];
@@ -8440,15 +8532,21 @@ abstract class _Item extends \IPS\Content
public function publish( $member=NULL )
{
/* Now do the actual stuff */
if ( isset( static::$databaseColumnMap['is_future_entry'] ) AND isset( static::$databaseColumnMap['date'] ) )
if ( isset( static::$databaseColumnMap['is_future_entry'] ) AND isset( static::$databaseColumnMap['future_date'] ) )
{
$date = static::$databaseColumnMap['date'];
$date = static::$databaseColumnMap['future_date'];
$future = static::$databaseColumnMap['is_future_entry'];
$this->$date = time();
$this->$future = 0;
}
if ( isset( static::$databaseColumnMap['date'] ) )
{
$dateField = \is_array( static::$databaseColumnMap['date'] ) ? static::$databaseColumnMap['date'][0] : static::$databaseColumnMap['date'];
$this->$dateField = time();
}
$this->save();
$this->onPublish( $member );
@@ -8458,10 +8556,41 @@ abstract class _Item extends \IPS\Content
\IPS\Db::i()->update( 'core_tags_perms', array( 'tag_perm_visible' => 1 ), array( 'tag_perm_aai_lookup=?', $this->tagAAIKey() ) );
}
/* Update the first comment */
if ( static::$firstCommentRequired )
{
$comment = $this->firstComment();
$date = $comment::$databaseColumnMap['date'];
$comment->$date = time();
$comment->save();
if ( isset( static::$databaseColumnMap['last_comment'] ) )
{
$lastCommentField = static::$databaseColumnMap['last_comment'];
if ( \is_array( $lastCommentField ) )
{
foreach ( $lastCommentField as $column )
{
$this->$column = time();
}
}
else
{
$this->$lastCommentField = time();
}
$this->save();
}
}
/* Mark this item as read for the author */
$this->markRead( $this->author() );
/* Update search index */
if ( $this instanceof \IPS\Content\Searchable )
{
\IPS\Content\Search\Index::i()->index( $this );
\IPS\Content\Search\Index::i()->index( ( static::$firstCommentRequired ) ? $this->firstComment() : $this );
}
/* Send notifications if necessary */