Version 4.6.0
This commit is contained in:
1 parent
f79dcf067a
commit
517a5e1f70
2036 files changed
+110041
-26162
No files matched your search
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Anonymous Interface for Content Models/Comments
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 22 Jun 2020
|
||||
*/
|
||||
|
||||
namespace IPS\Content;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymous Interface for Content Models/Comments
|
||||
*
|
||||
* @note Content classes will gain special functionality by implementing this interface
|
||||
*/
|
||||
interface Anonymous
|
||||
{
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class _CommentController extends \IPS\Api\Controller
|
||||
/* Containers */
|
||||
if ( isset( \IPS\Request::i()->$containerParam ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['container'], array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->$containerParam ) ) ) ) );
|
||||
$where[] = array( \IPS\Db::i()->in( $itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['container'], array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->$containerParam ) ) ) ) );
|
||||
}
|
||||
|
||||
/* Authors */
|
||||
|
||||
@@ -69,7 +69,7 @@ abstract class _ContentMutator
|
||||
}
|
||||
else
|
||||
{
|
||||
$fileAttachments[] = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedFile( \IPS\Http\Url::baseUrl() . "applications/core/interface/file/attachment.php?id=" . $attachment['attach_id'], $attachment['attach_file'], FALSE, $attachment['attach_ext'], $attachment['attach_id'] );
|
||||
$fileAttachments[] = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedFile( \IPS\Http\Url::baseUrl() . "applications/core/interface/file/attachment.php?id=" . $attachment['attach_id'] . ( $attachment['attach_security_key'] ? "&key={$attachment['attach_security_key']}" : '' ), $attachment['attach_file'], FALSE, $attachment['attach_ext'], $attachment['attach_id'], $attachment['attach_security_key'] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,10 +99,11 @@ abstract class _ItemMutator extends ContentMutator
|
||||
$item->markRead();
|
||||
}
|
||||
|
||||
/* Send notifications */
|
||||
/* Send notifications and dish out points */
|
||||
if ( !$item->hidden() )
|
||||
{
|
||||
$item->sendNotifications();
|
||||
\IPS\Member::loggedIn()->achievementAction( 'core', 'NewContentItem', $item );
|
||||
}
|
||||
elseif( $item->hidden() !== -1 )
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ class _ItemController extends \IPS\Api\Controller
|
||||
/* Containers */
|
||||
if ( $containerParam and isset( \IPS\Request::i()->$containerParam ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'], array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->$containerParam ) ) ) ) );
|
||||
$where[] = array( \IPS\Db::i()->in( $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnMap['container'], array_map( 'intval', array_filter( explode( ',', \IPS\Request::i()->$containerParam ) ) ) ) );
|
||||
}
|
||||
|
||||
/* Authors */
|
||||
@@ -383,7 +383,7 @@ class _ItemController extends \IPS\Api\Controller
|
||||
* @param string $firstPostParam The parameter which contains the body for the first comment
|
||||
* @return \IPS\Content\Item
|
||||
*/
|
||||
protected function _create( \IPS\Node\Model $container = NULL, \IPS\Member $author, $firstPostParam = 'post' )
|
||||
protected function _create( ?\IPS\Node\Model $container, \IPS\Member $author, $firstPostParam = 'post' )
|
||||
{
|
||||
$class = $this->class;
|
||||
|
||||
@@ -423,10 +423,17 @@ class _ItemController extends \IPS\Api\Controller
|
||||
\IPS\Content\Search\Index::i()->index( $item );
|
||||
}
|
||||
|
||||
/* Send notifications */
|
||||
/* Send webhooks */
|
||||
if ( \in_array( $item->hidden(), array( -1, 0, 1 ) ) ) // i.e. not post before register or pending deletion
|
||||
{
|
||||
\IPS\Api\Webhook::fire( str_replace( '\\', '', \substr( \get_class( $item ), 3 ) ) . '_create', $item, $item->webhookFilters() );
|
||||
}
|
||||
|
||||
/* Send notifications and dish out points */
|
||||
if ( !$item->hidden() )
|
||||
{
|
||||
$item->sendNotifications();
|
||||
$author->achievementAction( 'core', 'NewContentItem', $item );
|
||||
}
|
||||
elseif( !\in_array( $item->hidden(), array( -1, -3 ) ) )
|
||||
{
|
||||
@@ -482,6 +489,8 @@ class _ItemController extends \IPS\Api\Controller
|
||||
|
||||
$poll->setDataFromForm( $formatted, TRUE );
|
||||
$poll->save();
|
||||
|
||||
$item->author()->achievementAction( 'core', 'NewPoll', $poll );
|
||||
|
||||
$item->poll_state = $poll->pid;
|
||||
}
|
||||
@@ -554,4 +563,4 @@ class _ItemController extends \IPS\Api\Controller
|
||||
isset( \IPS\Request::i()->perPage ) ? \IPS\Request::i()->perPage : NULL
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,7 +192,7 @@ abstract class _Comment extends \IPS\Content
|
||||
/* Increment post count */
|
||||
try
|
||||
{
|
||||
if ( !$obj->hidden() and ( $incrementPostCount === TRUE or ( $incrementPostCount === NULL and static::incrementPostCount( $item->container() ) ) ) )
|
||||
if ( !$obj->isAnonymous() and !$obj->hidden() and ( $incrementPostCount === TRUE or ( $incrementPostCount === NULL and static::incrementPostCount( $item->container() ) ) ) )
|
||||
{
|
||||
$obj->author()->member_posts++;
|
||||
}
|
||||
@@ -222,12 +222,13 @@ abstract class _Comment extends \IPS\Content
|
||||
$obj->author()->save();
|
||||
}
|
||||
|
||||
/* Send notifications */
|
||||
/* Send notifications and dish out points */
|
||||
if ( !\in_array( 'IPS\Content\Review', class_parents( \get_called_class() ) ) )
|
||||
{
|
||||
if ( !$obj->hidden() and ( !$first or !$item::$firstCommentRequired ) )
|
||||
{
|
||||
$obj->sendNotifications();
|
||||
$obj->author()->achievementAction( 'core', 'Comment', $obj );
|
||||
}
|
||||
else if( $obj->hidden() === 1 )
|
||||
{
|
||||
@@ -298,7 +299,8 @@ abstract class _Comment extends \IPS\Content
|
||||
public function postCreate()
|
||||
{
|
||||
$item = $this->item();
|
||||
|
||||
$itemIdColumn = $item::$databaseColumnId;
|
||||
|
||||
$item->resyncCommentCounts();
|
||||
|
||||
if( isset( static::$databaseColumnMap['date'] ) )
|
||||
@@ -368,6 +370,12 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
$item->clearCachedStatistics();
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( $item->containerWrapper() and \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
$item->container()->rebuildPostedIn( array( $item->$itemIdColumn ), array( $this->author() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,7 +450,7 @@ abstract class _Comment extends \IPS\Content
|
||||
$member = \IPS\Member::loggedIn();
|
||||
}
|
||||
|
||||
if ( $this instanceof \IPS\Content\Hideable and $this->hidden() and !$this->item()->canViewHiddenComments( $member ) and ( $this->hidden() !== 1 or $this->author() !== $member ) )
|
||||
if ( $this instanceof \IPS\Content\Hideable and $this->hidden() and !$this->item()->canViewHiddenComments( $member ) and ( $this->hidden() !== 1 or ( $this->author()->member_id AND $this->author() !== $member ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -731,7 +739,8 @@ abstract class _Comment extends \IPS\Content
|
||||
public function onHide( $member )
|
||||
{
|
||||
$item = $this->item();
|
||||
|
||||
$itemIdColumn = $item::$databaseColumnId;
|
||||
|
||||
/* Remove any notifications */
|
||||
$idColumn = static::$databaseColumnId;
|
||||
\IPS\Db::i()->delete( 'core_notifications', array( 'item_sub_class=? AND item_sub_id=?', (string) \get_called_class(), (int) $this->$idColumn ) );
|
||||
@@ -749,6 +758,12 @@ abstract class _Comment extends \IPS\Content
|
||||
$item->container()->resetCommentCounts();
|
||||
$item->container()->save();
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
$item->container()->rebuildPostedIn( array( $item->$itemIdColumn ), array( $this->author() ) );
|
||||
}
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
|
||||
if ( \IPS\IPS::classUsesTrait( $item, 'IPS\Content\Statistics' ) )
|
||||
@@ -767,6 +782,7 @@ abstract class _Comment extends \IPS\Content
|
||||
public function onUnhide( $approving, $member )
|
||||
{
|
||||
$item = $this->item();
|
||||
$itemIdColumn = $item::$databaseColumnId;
|
||||
|
||||
if ( $approving )
|
||||
{
|
||||
@@ -799,6 +815,12 @@ abstract class _Comment extends \IPS\Content
|
||||
$item->container()->resetCommentCounts();
|
||||
$item->container()->save();
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
$item->container()->rebuildPostedIn( array( $item->$itemIdColumn ), array( $this->author() ) );
|
||||
}
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
|
||||
if ( \IPS\IPS::classUsesTrait( $item, 'IPS\Content\Statistics' ) )
|
||||
@@ -841,6 +863,9 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_solved_index', array( 'item_id' => $item->$idColumn ), array( 'comment_class=? and comment_id=?', \get_class( $this ), $oldItem->$idColumn ) );
|
||||
}
|
||||
|
||||
/* Update member map */
|
||||
\IPS\Db::i()->update( 'core_item_member_map', array( 'map_item_id' => $item->$idColumn ), array( 'map_class=? and map_item_id=?', \get_class( $oldItem ), $oldItem->$idColumn ) );
|
||||
|
||||
if( $skip === FALSE )
|
||||
{
|
||||
@@ -1004,6 +1029,9 @@ abstract class _Comment extends \IPS\Content
|
||||
/* Actually delete */
|
||||
parent::delete();
|
||||
|
||||
/* Deletions can occur via cron - shut off joining of profile fields as templates and current logged in member object may be referenced. */
|
||||
static::$joinProfileFields = FALSE;
|
||||
|
||||
/* Update last comment/review data for container and item */
|
||||
try
|
||||
{
|
||||
@@ -1041,6 +1069,12 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
$item->container()->save();
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
$item->container()->rebuildPostedIn( array( $item->$itemIdColumn ), array( $this->author() ) );
|
||||
}
|
||||
}
|
||||
catch ( \BadMethodCallException $e ) {}
|
||||
}
|
||||
@@ -1509,6 +1543,20 @@ abstract class _Comment extends \IPS\Content
|
||||
|
||||
return $this->sharelinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Web Share Data
|
||||
*
|
||||
* @return array|NULL
|
||||
*/
|
||||
public function webShareData(): ?array
|
||||
{
|
||||
return array(
|
||||
'title' => \IPS\Text\Parser::truncate( $this->item()->mapped('title'), TRUE ),
|
||||
'text' => $this->truncated( TRUE, NULL ),
|
||||
'url' => (string) $this->url()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition where needed for fetching comments
|
||||
@@ -1605,4 +1653,26 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->embedComment( $this->item(), $this, $this->url()->setQueryString( $params ), $this->item()->embedImage() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an anonymous entry?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAnonymous()
|
||||
{
|
||||
if ( $this instanceof \IPS\Content\Anonymous )
|
||||
{
|
||||
if( $this->isFirst() )
|
||||
{
|
||||
return $this->item()->isAnonymous();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->mapped('is_anon');
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
+253
-36
@@ -66,23 +66,52 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Post count for member
|
||||
*
|
||||
* @param \IPS\Member $member The memner
|
||||
* @param \IPS\Member $member The member
|
||||
* @param bool $includeNonPostCountIncreasing If FALSE, will skip any posts which would not cause the user's post count to increase
|
||||
* @param bool $includeHiddenAndPendingApproval If FALSE, will skip any hidden posts, or posts pending approval
|
||||
* @return int
|
||||
*/
|
||||
public static function memberPostCount( \IPS\Member $member )
|
||||
public static function memberPostCount( \IPS\Member $member, bool $includeNonPostCountIncreasing = FALSE, bool $includeHiddenAndPendingApproval = TRUE )
|
||||
{
|
||||
return ( isset( static::$databaseColumnMap['author'] ) and static::incrementPostCount() ) ? \IPS\Db::i()->select( 'COUNT(*)', static::$databaseTable, array( static::$databasePrefix . static::$databaseColumnMap['author'] . '=?', $member->member_id ) )->first() : 0;
|
||||
if ( !isset( static::$databaseColumnMap['author'] ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !$includeNonPostCountIncreasing and !static::incrementPostCount() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$where[] = [ static::$databasePrefix . static::$databaseColumnMap['author'] . '=?', $member->member_id ];
|
||||
|
||||
if ( !$includeHiddenAndPendingApproval )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$where[] = [ static::$databasePrefix . static::$databaseColumnMap['hidden'] . '=0' ];
|
||||
}
|
||||
if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$where[] = [ static::$databasePrefix . static::$databaseColumnMap['approved'] . '=1' ];
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', static::$databaseTable, $where )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Post count for member
|
||||
*
|
||||
* @param \IPS\Member $member The memner
|
||||
* @deprecated Use options provided to memberPostCount()
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @return int
|
||||
*/
|
||||
public static function rawMemberPostCount( \IPS\Member $member )
|
||||
{
|
||||
return static::memberPostCount( $member );
|
||||
return static::memberPostCount( $member, TRUE );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,10 +323,16 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
*/
|
||||
public function author()
|
||||
{
|
||||
if ( $this->mapped('author') or !isset( static::$databaseColumnMap['author_name'] ) or !$this->mapped('author_name') )
|
||||
if( $this->isAnonymous() )
|
||||
{
|
||||
$guest = new \IPS\Member;
|
||||
$guest->name = \IPS\Member::loggedIn()->language()->addToStack( "post_anonymously_placename" );
|
||||
return $guest;
|
||||
}
|
||||
elseif ( $this->mapped('author') or !isset( static::$databaseColumnMap['author_name'] ) or !$this->mapped('author_name') )
|
||||
{
|
||||
return \IPS\Member::load( $this->mapped('author') );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$guest = new \IPS\Member;
|
||||
@@ -344,6 +379,16 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array( 'app=? AND type=? AND type_id=?', static::$application, $this->reactionType(), $this->$idColumn ) );
|
||||
}
|
||||
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\Recognizable' ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_member_recognize', array( 'r_content_class=? AND r_content_id=?', \get_class( $this ), $this->$idColumn ) );
|
||||
}
|
||||
|
||||
if( $this instanceof \IPS\Content\Anonymous )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_anonymous_posts', array( 'anonymous_object_class=? AND anonymous_object_id=?', \get_class( $this ), $this->$idColumn ) );
|
||||
}
|
||||
|
||||
/* Remove any entries in the promotions table */
|
||||
\IPS\Db::i()->delete( 'core_social_promote', array( 'promote_class=? AND promote_class_id=?', \get_class( $this ), $this->$idColumn ) );
|
||||
|
||||
@@ -355,6 +400,8 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
$idColumn = static::$databaseColumnId;
|
||||
\IPS\Db::i()->delete('core_soft_delete_log', array('sdl_obj_id=? AND sdl_obj_key=?', $this->$idColumn, static::$hideLogKey));
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_content_featured', [ 'feature_content_id=? and feature_content_class=?', $this->$idColumn, \get_class( $this ) ] );
|
||||
|
||||
parent::delete();
|
||||
|
||||
@@ -428,6 +475,12 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
$title = $title ?: $this->mapped('title');
|
||||
}
|
||||
}
|
||||
|
||||
/* If this content is "post before register", skip this check (we'll do it after registration is complete) */
|
||||
if ( $this->hidden() === -3 or ( $item::$firstCommentRequired and $first and $item->hidden() === -3 ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* And the author */
|
||||
$member = $this->author();
|
||||
@@ -444,21 +497,21 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/* If this is a content item that doesn't require a first comment, or a comment that isn't the first comment, this just pass the content as it stands. */
|
||||
if ( !$this->hidden() AND ( ( $this instanceof \IPS\Content\Item ) OR ( $this instanceof \IPS\Content\Comment AND ( !$item::$firstCommentRequired OR ( $item::$firstCommentRequired AND !$first ) ) ) ) AND !$member->group['g_bypass_badwords'] )
|
||||
{
|
||||
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $content );
|
||||
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $content, $member );
|
||||
|
||||
if ( $title AND !$hiddenByFilter )
|
||||
{
|
||||
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $title );
|
||||
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $title, $member );
|
||||
}
|
||||
}
|
||||
/* If the comment is hidden (probably requires moderator approval) and this is the first post in the item that requires a comment (i.e. a post in a topic), then we need to set the item as requiring approval instead. */
|
||||
elseif ( $item instanceof \IPS\Content\Hideable AND !$member->group['g_bypass_badwords'] AND ( $item::$firstCommentRequired and $first ) )
|
||||
{
|
||||
$itemHiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $content );
|
||||
$itemHiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $content, $member );
|
||||
|
||||
if ( $title AND !$itemHiddenByFilter )
|
||||
{
|
||||
$itemHiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $title );
|
||||
$itemHiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $title, $member );
|
||||
}
|
||||
|
||||
if ( isset( $item::$databaseColumnMap['approved'] ) and $itemHiddenByFilter )
|
||||
@@ -682,6 +735,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flag to skip rebuilding container data (because it will be rebuilt in one batch later)
|
||||
*/
|
||||
public $skipContainerRebuild = FALSE;
|
||||
|
||||
/**
|
||||
* Do Moderator Action
|
||||
@@ -721,7 +779,9 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
|
||||
/* Log */
|
||||
\IPS\Session::i()->modLog( 'modlog__action_' . $action, array( static::$title => TRUE, $this->url()->__toString() => FALSE, $this->mapped('title') ?: ( method_exists( $this, 'item' ) ? $this->item()->mapped('title') : NULL ) => FALSE ), ( $this instanceof \IPS\Content\Item ) ? $this : $this->item() );
|
||||
|
||||
|
||||
$idColumn = static::$databaseColumnId;
|
||||
|
||||
/* These ones just need a property setting */
|
||||
if ( \in_array( $action, array( 'pin', 'unpin', 'feature', 'unfeature', 'lock', 'unlock' ) ) )
|
||||
{
|
||||
@@ -736,6 +796,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
|
||||
case 'unfeature':
|
||||
$val = FALSE;
|
||||
\IPS\Db::i()->delete( 'core_content_featured', [ 'feature_content_id=? and feature_content_class=?', $this->$idColumn, \get_class( $this ) ] );
|
||||
case 'feature':
|
||||
$column = static::$databaseColumnMap['featured'];
|
||||
break;
|
||||
@@ -757,6 +818,22 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
$this->$column = $val;
|
||||
$this->save();
|
||||
|
||||
if ( $action == 'feature' )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_content_featured', [
|
||||
'feature_content_id' => $this->$idColumn,
|
||||
'feature_content_class' => \get_class( $this ),
|
||||
'feature_content_author' => $this->author()->member_id,
|
||||
'feature_date' => time()
|
||||
] );
|
||||
|
||||
/* Points */
|
||||
$this->author()->achievementAction( 'core', 'ContentPromotion', [
|
||||
'content' => $this,
|
||||
'promotype' => 'feature'
|
||||
] );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -874,13 +951,27 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
|
||||
try
|
||||
{
|
||||
if ( $this->container() )
|
||||
if ( $this->container() AND !$this->skipContainerRebuild )
|
||||
{
|
||||
$this->container()->resetCommentCounts();
|
||||
$this->container()->setLastComment();
|
||||
$this->container()->setLastReview();
|
||||
$this->container()->save();
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( $this->container() and \IPS\IPS::classUsesTrait( $this->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
if ( $this instanceof \IPS\Content\Comment )
|
||||
{
|
||||
$this->container()->rebuildPostedIn( array( $this->mapped('item') ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$this->container()->rebuildPostedIn( array($this->$idColumn) );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
catch( \OutOfRangeException $e ) {}
|
||||
@@ -959,7 +1050,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Recount the container counters */
|
||||
if( $this->container() )
|
||||
if( $this->container() AND !$this->skipContainerRebuild )
|
||||
{
|
||||
$this->container()->resetCommentCounts();
|
||||
$this->container()->setLastComment();
|
||||
@@ -1145,12 +1236,26 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
$this->sendApprovedNotification();
|
||||
}
|
||||
|
||||
/* Award points */
|
||||
$itemClass = \in_array( 'IPS\Content\Comment', class_parents( \get_called_class() ) ) ? static::$itemClass : \get_called_class();
|
||||
if ( $this instanceof \IPS\Content\Item )
|
||||
{
|
||||
$this->author()->achievementAction( 'core', 'NewContentItem', $this );
|
||||
}
|
||||
elseif ( $this instanceof \IPS\Content\Review )
|
||||
{
|
||||
$this->author()->achievementAction( 'core', 'Review', $this );
|
||||
}
|
||||
elseif ( $this instanceof \IPS\Content\Comment and ( !$itemClass::$firstCommentRequired or $this->isFirst() ) )
|
||||
{
|
||||
$this->author()->achievementAction( 'core', 'Comment', $this );
|
||||
}
|
||||
|
||||
/* Send webhook if necessary */
|
||||
if ( $approving )
|
||||
{
|
||||
\IPS\Api\Webhook::fire( str_replace( '\\', '', \substr( \get_called_class(), 3 ) ) . '_create', $this, $this->webhookFilters() );
|
||||
|
||||
$itemClass = \in_array( 'IPS\Content\Comment', class_parents( \get_called_class() ) ) ? static::$itemClass : \get_called_class();
|
||||
|
||||
if ( $this instanceof \IPS\Content\Item and $itemClass::$firstCommentRequired === TRUE and $firstComment = $this->firstComment() )
|
||||
{
|
||||
\IPS\Api\Webhook::fire( str_replace( '\\', '', \substr( \get_class( $firstComment ), 3 ) ) . '_create', $firstComment, $firstComment->webhookFilters() );
|
||||
@@ -1270,7 +1375,9 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Can the member report content? */
|
||||
if ( $member->group['g_can_report'] != '1' AND !\in_array( \get_class( $this ), explode( ',', $member->group['g_can_report'] ) ) )
|
||||
$classToCheck = ( $this instanceof \IPS\Content\Comment or $this instanceof \IPS\Content\Review ) ? \get_class( $this->item() ) : \get_class( $this );
|
||||
|
||||
if ( $member->group['g_can_report'] != '1' AND !\in_array( $classToCheck, explode( ',', $member->group['g_can_report'] ) ) )
|
||||
{
|
||||
return 'no_module_permission';
|
||||
}
|
||||
@@ -1479,7 +1586,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( array( 'author', 'author_name', 'edit_member_name' ) as $k )
|
||||
foreach ( array( 'author', 'author_name', 'edit_member_name', 'is_anon' ) as $k )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap[ $k ] ) )
|
||||
{
|
||||
@@ -1489,15 +1596,23 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
case 'author':
|
||||
$this->$col = $newAuthor->member_id ? $newAuthor->member_id : 0;
|
||||
break;
|
||||
|
||||
|
||||
case 'author_name':
|
||||
case 'edit_member_name':
|
||||
/* Real name will contain the custom guest name if available or '' if not */
|
||||
$this->$col = $newAuthor->member_id ? $newAuthor->name : $newAuthor->real_name;
|
||||
break;
|
||||
case 'is_anon':
|
||||
/* We are specifying an author so turn off is_anon column */
|
||||
if ( $newAuthor->member_id )
|
||||
{
|
||||
$this->$col = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->save();
|
||||
|
||||
if ( \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation == 'front' and $log )
|
||||
@@ -1523,7 +1638,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* @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() )
|
||||
{
|
||||
/* Item details */
|
||||
$itemClass = $indexData['index_class'];
|
||||
@@ -1623,7 +1738,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
* @return callable
|
||||
*/
|
||||
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
|
||||
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, ?array $containerData, array $reputationData, $reviewRating, $view )
|
||||
{
|
||||
return $view == 'expanded' ? \IPS\Theme::i()->getTemplate( 'system', 'core', 'front' )->searchResultSnippet( $indexData ) : '';
|
||||
}
|
||||
@@ -1641,7 +1756,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
*/
|
||||
public static function searchResultSummaryLanguage( $authorData, $articles, $indexData, $itemData )
|
||||
{
|
||||
$authorTemplate = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->userLinkFromData( $authorData['member_id'], $authorData['name'], $authorData['members_seo_name'], $authorData['member_group_id'] ?? \IPS\Settings::i()->guest_group );
|
||||
$authorTemplate = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->userLinkFromData( $authorData['member_id'], $authorData['name'], $authorData['members_seo_name'], $authorData['member_group_id'] ?? \IPS\Settings::i()->guest_group, NULL, $indexData['index_is_anon'] );
|
||||
|
||||
if( \in_array( 'IPS\Content\Comment', class_parents( $indexData['index_class'] ) ) )
|
||||
{
|
||||
@@ -1771,7 +1886,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
if ( $days and isset( static::$databaseColumnMap['ip_address'] ) and isset( static::$databaseColumnMap['date'] ) )
|
||||
{
|
||||
$time = time() - ( 86400 * $days );
|
||||
\IPS\Db::i()->update( static::$databaseTable, array( static::$databasePrefix . static::$databaseColumnMap['ip_address'] => '' ), array( static::$databasePrefix . static::$databaseColumnMap['date'] . ' <= ' . $time ) );
|
||||
\IPS\Db::i()->update( static::$databaseTable, array( static::$databasePrefix . static::$databaseColumnMap['ip_address'] => '' ), array( static::$databasePrefix . static::$databaseColumnMap['ip_address'] . "!='' AND " . static::$databasePrefix . static::$databaseColumnMap['date'] . ' <= ' . $time ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1819,11 +1934,12 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Get a count of the database table
|
||||
*
|
||||
* @return int
|
||||
* @param bool $approximate Accept an approximate result if the table is large (approximate results are faster on large tables)
|
||||
* @return int
|
||||
*/
|
||||
public static function databaseTableCount()
|
||||
public static function databaseTableCount( bool $approximate=FALSE ): int
|
||||
{
|
||||
$key = 'tbl_cnt_' . static::$databaseTable;
|
||||
$key = 'tbl_cnt_' . ( $approximate ? 'approx_' : 'accurate_' ) . static::$databaseTable;
|
||||
$fetchAgain = FALSE;
|
||||
|
||||
if ( ! isset( \IPS\Data\Store::i()->$key ) )
|
||||
@@ -1840,12 +1956,25 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
$fetchAgain = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( $fetchAgain )
|
||||
{
|
||||
\IPS\Data\Store::i()->$key = array( 'time' => time(), 'count' => \IPS\Db::i()->select( 'COUNT(*)', static::$databaseTable )->first() );
|
||||
$count = 0;
|
||||
/* Accept approximate result? */
|
||||
if ( $approximate )
|
||||
{
|
||||
$approxRows = \IPS\Db::i()->query( "SHOW TABLE STATUS LIKE '" . \IPS\Db::i()->prefix . static::$databaseTable . "';" )->fetch_assoc();
|
||||
$count = (int) $approxRows['Rows'];
|
||||
}
|
||||
|
||||
/* If the table is a reasonable size, we'll get the real value instead */
|
||||
if ( $count < 1000000 )
|
||||
{
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', static::$databaseTable )->first();
|
||||
}
|
||||
\IPS\Data\Store::i()->$key = array( 'time' => time(), 'count' => $count );
|
||||
}
|
||||
|
||||
|
||||
$data = \IPS\Data\Store::i()->$key;
|
||||
return $data['count'];
|
||||
}
|
||||
@@ -1957,6 +2086,21 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
public function sendApprovedNotification()
|
||||
{
|
||||
$this->sendNotifications();
|
||||
$this->sendAuthorApprovalNotification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Author Approval Notification
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sendAuthorApprovalNotification()
|
||||
{
|
||||
/* Tell the author their content has been approved */
|
||||
$member = \IPS\Member::load( $this->mapped('author') );
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'approved_content', $this, array( $this ), array(), FALSE );
|
||||
$notification->recipients->attach( $member );
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2044,7 +2188,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
public function sendAfterEditNotifications( $oldContent )
|
||||
{
|
||||
$existingData = static::_getQuoteAndMentionIdsFromContent( $oldContent );
|
||||
$this->sendQuoteAndMentionNotifications( array_unique( array_merge( $existingData['quotes'], $existingData['mentions'] ) ) );
|
||||
$this->sendQuoteAndMentionNotifications( array_unique( array_merge( $existingData['quotes'], $existingData['mentions'], $existingData['embeds'] ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2316,7 +2460,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* @param string $title Title
|
||||
* @return callable
|
||||
*/
|
||||
public function approvalQueueHtml( $ref=NULL, $container, $title )
|
||||
public function approvalQueueHtml( $ref, $container, $title )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'modcp', 'core', 'front' )->approvalQueueItem( $this, $ref, $container, $title );
|
||||
}
|
||||
@@ -2349,13 +2493,14 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Definite Article
|
||||
*
|
||||
* @param \IPS\Lang|NULL $lang The language to use, or NULL for the language of the currently logged in member
|
||||
* @param \IPS\Lang|NULL $lang The language to use, or NULL for the language of the currently logged in member
|
||||
* @param integer|boolean $count Number of items. If not FALSE, pluralized version of phrase will be used
|
||||
* @return string
|
||||
*/
|
||||
public function definiteArticle( \IPS\Lang $lang = NULL )
|
||||
public function definiteArticle( \IPS\Lang $lang = NULL, $count = FALSE )
|
||||
{
|
||||
$container = ( $this instanceof \IPS\Content\Comment ) ? $this->item()->containerWrapper() : $this->containerWrapper();
|
||||
return static::_definiteArticle( $container ? $container->_data : array(), $lang );
|
||||
return static::_definiteArticle( $container ? $container->_data : array(), $lang, array(), $count );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2364,11 +2509,24 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* @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 )
|
||||
{
|
||||
$lang = $lang ?: \IPS\Member::loggedIn()->language();
|
||||
|
||||
if( ( \is_int( $count ) || $count === TRUE ) && $lang->checkKeyExists('__defart_' . static::$title . '_plural') )
|
||||
{
|
||||
/* If $count is TRUE, use the pluralized form but don't pluralize here - useful if we're passing to JS for example */
|
||||
if( \is_int( $count ) )
|
||||
{
|
||||
$options['pluralize'] = array( $count );
|
||||
}
|
||||
|
||||
return $lang->addToStack( '__defart_' . static::$title . '_plural', FALSE, $options );
|
||||
}
|
||||
|
||||
return $lang->addToStack( '__defart_' . static::$title, FALSE, $options );
|
||||
}
|
||||
|
||||
@@ -2386,7 +2544,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
try
|
||||
{
|
||||
return (string) \IPS\File::get( 'core_Icons', $shareLogos[0] )->url->setScheme( ( \IPS\Request::i()->isSecure() ) ? 'https' : 'http' );
|
||||
return (string) \IPS\File::get( 'core_Icons', array_shift($shareLogos) )->url->setScheme( ( \IPS\Request::i()->isSecure() ) ? 'https' : 'http' );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
@@ -2553,4 +2711,63 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
$filters['author'] = $this->author()->member_id;
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set anonymous state
|
||||
*
|
||||
* @param bool $state The state, TRUE for anonymous FALSE for not
|
||||
* @param \IPS\Member|NULL $member The member posting anonymously or NULL for logged in member
|
||||
* @return void
|
||||
*/
|
||||
public function setAnonymous( $state = TRUE, $member = NULL )
|
||||
{
|
||||
if( !$this instanceof \IPS\Content\Anonymous or !$this->container()->canPostAnonymously() )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
$class = \get_class( $this );
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$anonColumn = static::$databaseColumnMap['is_anon'];
|
||||
if( $state )
|
||||
{
|
||||
/* Insert the anonymous map */
|
||||
$save = array(
|
||||
'anonymous_member_id' => $member->member_id,
|
||||
'anonymous_object_class' => $class,
|
||||
'anonymous_object_id' => $this->$idColumn
|
||||
);
|
||||
|
||||
\IPS\Db::i()->replace( 'core_anonymous_posts', $save );
|
||||
|
||||
$member = new \IPS\Member;
|
||||
$this->$anonColumn = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_anonymous_posts', array( 'anonymous_member_id=? and anonymous_object_class=? and anonymous_object_id=?', $member->member_id, $class, $this->$idColumn ) );
|
||||
$this->$anonColumn = 0;
|
||||
}
|
||||
|
||||
$this->save();
|
||||
$this->changeAuthor( $member, FALSE );
|
||||
|
||||
if ( \in_array( 'IPS\Content\Comment', class_parents( $this ) ) )
|
||||
{
|
||||
$this->item()->rebuildFirstAndLastCommentData();
|
||||
}
|
||||
|
||||
$this->expireWidgetCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an anonymous entry?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAnonymous()
|
||||
{
|
||||
return $this->mapped('is_anon');
|
||||
}
|
||||
}
|
||||
+141
-132
@@ -104,7 +104,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if ( \in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
{
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and \IPS\CACHE_CONFIG )
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -206,7 +206,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if ( \in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
||||
{
|
||||
$countUpdated = false;
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and \IPS\CACHE_CONFIG )
|
||||
if ( \IPS\REDIS_ENABLED and \IPS\CACHE_METHOD == 'Redis' and ( \IPS\CACHE_CONFIG or \IPS\REDIS_CONFIG ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -243,7 +243,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Set meta tags */
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) ( \IPS\Request::i()->page > 1 ) ? $item->url()->setPage( 'page', \IPS\Request::i()->page ) : $item->url() ;
|
||||
\IPS\Output::i()->metaTags['og:title'] = $item->mapped( 'title' );
|
||||
\IPS\Output::i()->metaTags['og:type'] = 'object';
|
||||
\IPS\Output::i()->metaTags['og:type'] = 'website';
|
||||
\IPS\Output::i()->metaTags['og:url'] = (string) $item->url();
|
||||
|
||||
/* Do not set description tags for page 2+ as you end up with duplicate tags */
|
||||
@@ -300,10 +300,15 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Return */
|
||||
return $item;
|
||||
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Output::i()->redirect( $class::getRedirectFrom( \IPS\Request::i()->id )->url(), '', 301 );
|
||||
}
|
||||
catch( \OutOfRangeException $e ) { }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -378,6 +383,13 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* We will fetch up to 200 comments - anything over this is excessive */
|
||||
$newComments = $item->comments( 200, 0, 'date', 'asc', NULL, NULL, \IPS\DateTime::ts( $lastComment->$commentDateColumn ), array_merge( $where, array( "{$authorColumn} != " . \IPS\Member::loggedIn()->member_id ) ) );
|
||||
|
||||
/* Get the next to last comment for the spillover link as PMs do not support read markers */
|
||||
$nextLastComment = NULL;
|
||||
if( \count( $newComments ) )
|
||||
{
|
||||
$nextLastComment = reset( $newComments );
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->type === 'count' )
|
||||
{
|
||||
$data = array(
|
||||
@@ -386,7 +398,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'perPage' => $class::getCommentsPerPage(),
|
||||
'totalCount' => $item->mapped( 'num_comments' ),
|
||||
'title' => $item->mapped( 'title' ) ,
|
||||
'spillOverUrl' => $item->url( 'getNewComment' )
|
||||
'spillOverUrl' => ( $nextLastComment ) ? $nextLastComment->url() : $item->url(),
|
||||
);
|
||||
|
||||
if( $data['count'] === 1 ){
|
||||
@@ -423,7 +435,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'totalCount' => $item->mapped( 'num_comments' ),
|
||||
'totalNewCount' => (int) \count( $newComments ),
|
||||
'perPage' => $class::getCommentsPerPage(),
|
||||
'spillOverUrl' => $item->url( 'getNewComment' )
|
||||
'spillOverUrl' => ( $nextLastComment ) ? $nextLastComment->url() : $item->url()
|
||||
) );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
@@ -545,7 +557,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
*/
|
||||
protected function getEditForm( $form )
|
||||
{
|
||||
return $form;
|
||||
return $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1032,7 +1044,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Mark it as read */
|
||||
if( $item instanceof \IPS\Content\ReadMarkers and $unread == 0 )
|
||||
{
|
||||
$item->markRead();
|
||||
$item->markRead( NULL, NULL, NULL, TRUE );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->modLog( 'modlog__action_move', array( $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) ?: ( method_exists( $item, 'item' ) ? $item->item()->mapped( 'title' ) : NULL ) => FALSE ), $item );
|
||||
@@ -1217,7 +1229,11 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'report_type', NULL, FALSE, array( 'options' => $options ) ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'report_message', NULL, FALSE, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$idColumn}", 'minimize' => 'report_message_placeholder' ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'report_message', NULL, FALSE, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$idColumn}", 'minimize' => \IPS\Request::i()->isAjax() ? 'report_message_placeholder' : NULL ) ) );
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['report_message'] = \IPS\Member::loggedIn()->language()->addToStack('report_message_fallback');
|
||||
}
|
||||
|
||||
if( !\IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
@@ -1242,7 +1258,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Even if guests can report something, we don't want the report form indexed in Google */
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
|
||||
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
\IPS\Output::i()->output = \IPS\Request::i()->isAjax() ? $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) : \IPS\Theme::i()->getTemplate( 'system', 'core' )->reportForm( $form );
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
@@ -1308,7 +1324,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->redirect( $item->url() );
|
||||
}
|
||||
}
|
||||
catch( \DomainException $e )
|
||||
catch( \OutOfRangeException | \DomainException $e )
|
||||
{
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -2011,14 +2027,6 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
$item->toggleSolveComment( \IPS\Request::i()->answer, TRUE );
|
||||
|
||||
if( $comment->author()->member_id != \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'best_answer', $item, array( $comment ), array( $comment->author()->member_id ) );
|
||||
$notification->recipients->attach( $comment->author() );
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
|
||||
/* Log */
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_set_best_answer') )
|
||||
{
|
||||
@@ -2106,17 +2114,19 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if ( $item->itemModerationEnabled() )
|
||||
{
|
||||
$action = 'disable';
|
||||
$actionLang = 'disabled';
|
||||
}
|
||||
else
|
||||
{
|
||||
$action = 'enable';
|
||||
$actionLang = 'enabled';
|
||||
}
|
||||
|
||||
$item->toggleItemModeration( $action );
|
||||
|
||||
\IPS\Session::i()->modLog( 'modlog__item_moderation_toggled', [$action => FALSE], $item );
|
||||
\IPS\Session::i()->modLog( 'modlog__item_moderation_toggled', [$actionLang => TRUE], $item );
|
||||
|
||||
\IPS\Output::i()->redirect( $item->url(), ( $item->itemModerationEnabled() ) ? 'enabled' : 'disabled' );
|
||||
\IPS\Output::i()->redirect( $item->url(), $actionLang );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
@@ -2296,11 +2306,11 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
*/
|
||||
public function _hide( $commentClass, $comment, $item )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
/* If this is an AJAX request, and we're coming from the approval queue, just do it. */
|
||||
if ( \IPS\Request::i()->isAjax() AND isset( \IPS\Request::i()->_fromApproval ) )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
$comment->modAction( 'hide' );
|
||||
\IPS\Output::i()->json( 'OK' );
|
||||
}
|
||||
@@ -2322,6 +2332,8 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
$comment->modAction( 'hide' );
|
||||
}
|
||||
|
||||
@@ -2368,10 +2380,20 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
if ( isset( \IPS\Request::i()->restoreAsHidden ) )
|
||||
{
|
||||
\IPS\Session::i()->modLog( 'modlog__action_restore_hidden', array(
|
||||
$comment::$title => FALSE,
|
||||
$comment->url()->__toString() => FALSE
|
||||
) );
|
||||
|
||||
$comment->modAction( 'restoreAsHidden' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Session::i()->modLog( 'modlog__action_restore', array(
|
||||
$comment::$title => FALSE,
|
||||
$comment->url()->__toString() => FALSE
|
||||
) );
|
||||
|
||||
$comment->modAction( 'restore' );
|
||||
}
|
||||
|
||||
@@ -2427,6 +2449,13 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'autoSaveKey' => 'editComment-' . $class::$application . '/' . $class::$module . '-' . $comment->$idField,
|
||||
'attachIds' => $comment->attachmentIds()
|
||||
) ) );
|
||||
|
||||
/* Post Anonymously */
|
||||
$container = $item->containerWrapper();
|
||||
if ( $container and $container->canPostAnonymously( $container::ANON_COMMENTS ) and $comment instanceof \IPS\Content\Anonymous and \IPS\Member::loggedIn()->member_id and \IPS\Member::loggedIn()->group['gbw_can_post_anonymously'] )
|
||||
{
|
||||
$form->add ( new \IPS\Helpers\Form\YesNo( 'post_anonymously', $comment->isAnonymous(), FALSE, array( 'label' => \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_suffix' ) ), NULL, NULL, NULL, 'post_anonymously' ) );
|
||||
}
|
||||
|
||||
$form->addButton( 'save', 'submit', null, 'ipsButton ipsButton_medium ipsButton_primary ipsButton_fullWidth', array( 'tabindex' => '2', 'accesskey' => 's' ) );
|
||||
|
||||
@@ -2516,6 +2545,12 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
$comment->editRating( $values['rating_value'] );
|
||||
}
|
||||
|
||||
/* Anonymous posting */
|
||||
if( isset( $values[ 'post_anonymously' ] ) )
|
||||
{
|
||||
$comment->setAnonymous( $values[ 'post_anonymously' ] );
|
||||
}
|
||||
|
||||
/* Moderator log */
|
||||
\IPS\Session::i()->modLog( 'modlog__comment_edit', array( $comment->url()->__toString() => FALSE, $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) => FALSE ), $item );
|
||||
@@ -2567,57 +2602,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* If we are retaining content for a period of time, we need to just hide it instead for deleting later - this only works, though, with items that implement \IPS\Content\Hideable */
|
||||
if ( \IPS\Settings::i()->dellog_retention_period AND ( $item instanceof \IPS\Content\Hideable ) AND !isset( \IPS\Request::i()->immediately ) )
|
||||
{
|
||||
$log = new \IPS\core\DeletionLog;
|
||||
$log->setContentAndMember( $item, \IPS\Member::loggedIn() );
|
||||
$log->save();
|
||||
|
||||
if ( isset( $item::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = $item::$databaseColumnMap['hidden'];
|
||||
}
|
||||
else if ( isset( $item::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = $item::$databaseColumnMap['approved'];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( $item->container() )
|
||||
{
|
||||
if ( $item->container()->_comments !== NULL )
|
||||
{
|
||||
/* Hidden content already decrements */
|
||||
if ( !$item->hidden() )
|
||||
{
|
||||
$item->container()->_comments = ( $item->container()->_comments - $item->mapped('num_comments') );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $item->container()->_unapprovedComments !== NULL )
|
||||
{
|
||||
$item->container()->_unapprovedComments = ( $item->container()->_unapprovedComments - $item->mapped( 'unapproved_comments' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
|
||||
$item->$column = -2;
|
||||
$item->save();
|
||||
|
||||
try
|
||||
{
|
||||
if ( $item->container() )
|
||||
{
|
||||
$item->container()->setLastComment();
|
||||
$this->container()->setLastReview();
|
||||
$item->container()->save();
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
$item->delete();
|
||||
$item->logDelete();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2632,61 +2617,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* If we are retaining content for a period of time, we need to just hide it instead for deleting later - this only works, though, with items that implement \IPS\Content\Hideable */
|
||||
if ( \IPS\Settings::i()->dellog_retention_period AND ( $item instanceof \IPS\Content\Hideable ) AND !isset( \IPS\Request::i()->immediately ) )
|
||||
{
|
||||
$log = new \IPS\core\DeletionLog;
|
||||
$log->setContentAndMember( $comment, \IPS\Member::loggedIn() );
|
||||
$log->save();
|
||||
|
||||
if ( isset( $comment::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = $comment::$databaseColumnMap['hidden'];
|
||||
}
|
||||
else if ( isset( $comment::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = $comment::$databaseColumnMap['approved'];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( $comment->container() )
|
||||
{
|
||||
if ( $comment->container()->_comments !== NULL )
|
||||
{
|
||||
/* Hidden content already decrements */
|
||||
if ( !$comment->hidden() )
|
||||
{
|
||||
$comment->container()->_comments = $comment->container()->_comments - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
|
||||
$comment->$column = -2;
|
||||
$comment->save();
|
||||
|
||||
try
|
||||
{
|
||||
$comment->item()->rebuildFirstAndLastCommentData();
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
|
||||
/* Remove featured comment associations */
|
||||
if( $comment->isFeatured() )
|
||||
{
|
||||
\IPS\Application::load('core')->extensions( 'core', 'MetaData' )['FeaturedComments']->unfeatureComment( $comment->item(), $comment );
|
||||
}
|
||||
|
||||
/* Update solved status */
|
||||
if ( \IPS\IPS::classUsesTrait( $item, 'IPS\Content\Solvable' ) and isset( $item::$databaseColumnMap['solved_comment_id'] ) )
|
||||
{
|
||||
/* Reset item */
|
||||
$idColumn = $commentClass::$databaseColumnId;
|
||||
$itemIdColumn = $item::$databaseColumnId;
|
||||
if ( $item->mapped('solved_post_id') and $item->mapped('solved_post_id') == $comment->$idColumn )
|
||||
{
|
||||
\IPS\Db::i()->update( $item::$databaseTable, array( $item::$databaseColumnMap['solved_comment_id'] => 0 ), array( $itemIdColumn . '=?', $item->$itemIdColumn ) );
|
||||
}
|
||||
}
|
||||
$comment->logDelete();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2952,6 +2883,11 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'report_message', NULL, FALSE, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$itemIdColumn}-{$comment->$idColumn}", 'minimize' => 'report_message_placeholder' ) ) );
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['report_message'] = \IPS\Member::loggedIn()->language()->addToStack('report_message_fallback');
|
||||
}
|
||||
|
||||
if( !\IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Captcha );
|
||||
@@ -2975,7 +2911,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* Even if guests can report something, we don't want the report form indexed in Google */
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
|
||||
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
\IPS\Output::i()->output = \IPS\Request::i()->isAjax() ? $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) : \IPS\Theme::i()->getTemplate( 'system', 'core' )->reportForm( $form );
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
@@ -3038,7 +2974,6 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
*/
|
||||
protected function _feature( $commentClass, $comment, $item )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
if ( !$item->canFeatureComment() )
|
||||
{
|
||||
throw new \DomainException;
|
||||
@@ -3611,6 +3546,15 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
|
||||
$url = $item->url();
|
||||
|
||||
if ( isset( \IPS\Request::i()->page ) )
|
||||
{
|
||||
$url = $url->setPage( 'page', (int) \IPS\Request::i()->page );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3836,7 +3780,8 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'core_tags',
|
||||
$where,
|
||||
'tag_added DESC',
|
||||
array( 0, $limit )
|
||||
array( 0, $limit ),
|
||||
array( 'tag_meta_app', 'tag_meta_area', 'tag_meta_id', 'tag_added' )
|
||||
)->join(
|
||||
'core_tags_perms',
|
||||
array( 'tag_perm_aai_lookup=tag_aai_lookup' )
|
||||
@@ -3926,4 +3871,68 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
||||
return new \IPS\Helpers\CoverPhoto;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reveal
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function reveal()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
if( !\IPS\Member::loggedIn()->modPermission( 'can_view_anonymous_posters' ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2S136/1V', 403, '' );
|
||||
}
|
||||
|
||||
$class = static::$contentModel;
|
||||
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
|
||||
if( isset( \IPS\Request::i()->comment ) )
|
||||
{
|
||||
$class = $class::$commentClass;
|
||||
$id = \IPS\Request::i()->comment;
|
||||
}
|
||||
else
|
||||
{
|
||||
$id = \IPS\Request::i()->id;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$anonymousAuthor = \IPS\Db::i()->select( 'anonymous_member_id', 'core_anonymous_posts', array( 'anonymous_object_class=? and anonymous_object_id=?', $class, $id ) )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2S136/1W', 403, '' );
|
||||
}
|
||||
|
||||
$author = \IPS\Member::load( $anonymousAuthor );
|
||||
|
||||
$addWarningUrl = \IPS\Http\Url::internal( "app=core&module=system&controller=warnings&do=warn&id={$author->member_id}", 'front', 'warn_add', array( $author->members_seo_name ) );
|
||||
if ( isset( \IPS\Request::i()->wr ) )
|
||||
{
|
||||
$addWarningUrl = $addWarningUrl->setQueryString( 'ref', \IPS\Request::i()->wr );
|
||||
}
|
||||
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile', 'core' )->hovercard( $author, $addWarningUrl );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $author->url() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reveal Comment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function revealComment()
|
||||
{
|
||||
$this->reveal();
|
||||
}
|
||||
}
|
||||
+360
-115
@@ -346,13 +346,13 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Increment post count */
|
||||
if ( !$obj->hidden() and static::incrementPostCount( $container ) )
|
||||
if ( !$obj->hidden() and static::incrementPostCount( $container ) and ! $obj->isAnonymous() )
|
||||
{
|
||||
$obj->author()->member_posts++;
|
||||
}
|
||||
|
||||
/* Update member's last post */
|
||||
if( $obj->author()->member_id AND $obj::incrementPostCount() )
|
||||
if( $obj->author()->member_id AND $obj::incrementPostCount() AND ! $obj->isAnonymous() )
|
||||
{
|
||||
$obj->author()->member_last_post = time();
|
||||
$obj->author()->save();
|
||||
@@ -434,9 +434,16 @@ abstract class _Item extends \IPS\Content
|
||||
$member->save();
|
||||
}
|
||||
|
||||
|
||||
/* Post anonymously */
|
||||
if( isset( $values[ 'post_anonymously' ] ) )
|
||||
{
|
||||
$obj->setAnonymous( $values[ 'post_anonymously' ] );
|
||||
}
|
||||
|
||||
/* Do any processing */
|
||||
$obj->processAfterCreate( $comment, $values );
|
||||
|
||||
|
||||
/* Auto-follow */
|
||||
if( isset( $values[ static::$formLangPrefix . 'auto_follow'] ) AND $values[ static::$formLangPrefix . 'auto_follow'] )
|
||||
{
|
||||
@@ -494,6 +501,12 @@ abstract class _Item extends \IPS\Content
|
||||
$obj->sendUnapprovedNotification();
|
||||
}
|
||||
}
|
||||
|
||||
/* Dish out points */
|
||||
if ( !$obj->isFutureDate() and !$obj->hidden() )
|
||||
{
|
||||
$member->achievementAction( 'core', 'NewContentItem', $obj );
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $obj;
|
||||
@@ -756,6 +769,12 @@ abstract class _Item extends \IPS\Content
|
||||
$return['auto_follow'] = new \IPS\Helpers\Form\YesNo( static::$formLangPrefix . 'auto_follow', (bool) \IPS\Member::loggedIn()->auto_follow['content'], FALSE, array( 'label' => \IPS\Member::loggedIn()->language()->addToStack( static::$formLangPrefix . 'auto_follow_suffix' ) ), NULL, NULL, NULL, static::$formLangPrefix . 'auto_follow' );
|
||||
}
|
||||
|
||||
/* Post Anonymously */
|
||||
if ( $container and $container->canPostAnonymously( $container::ANON_ITEMS ) )
|
||||
{
|
||||
$return['post_anonymously'] = new \IPS\Helpers\Form\YesNo( 'post_anonymously', ( $item ) ? $item->isAnonymous() : FALSE , FALSE, array( 'label' => \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_suffix' ) ), NULL, NULL, NULL, 'post_anonymously' );
|
||||
}
|
||||
|
||||
/* Share Links */
|
||||
if ( $item === NULL and \in_array( 'IPS\Content\Shareable', class_implements( \get_called_class() ) ) )
|
||||
{
|
||||
@@ -1080,7 +1099,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Check if profanity filters should mod-queue this comment */
|
||||
$sendNotifications = $commentObj->checkProfanityFilters( TRUE, TRUE );
|
||||
$sendNotifications = $commentObj->checkProfanityFilters( TRUE, TRUE, $values[ static::$formLangPrefix . 'content'] );
|
||||
|
||||
/* Send notifications */
|
||||
if ( $sendNotifications AND !\in_array( 'IPS\Content\Review', class_parents( \get_called_class() ) ) )
|
||||
@@ -1093,7 +1112,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
$oldValue = $commentObj->$column;
|
||||
$commentObj->$column = $values[static::$formLangPrefix . 'content'];
|
||||
$commentObj->$column = $values[ static::$formLangPrefix . 'content'];
|
||||
$commentObj->save();
|
||||
$commentObj->sendAfterEditNotifications( $oldValue );
|
||||
|
||||
@@ -1129,6 +1148,12 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Post anonymously */
|
||||
if( isset( $values[ 'post_anonymously' ] ) and ( isset( $container ) and $container->canPostAnonymously( $container::ANON_ITEMS ) ) )
|
||||
{
|
||||
$this->setAnonymous( $values[ 'post_anonymously' ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Holds the old content for edit logging */
|
||||
@@ -1336,7 +1361,7 @@ abstract class _Item extends \IPS\Content
|
||||
switch( $pref )
|
||||
{
|
||||
case 'unread':
|
||||
$action = 'getNewComment';
|
||||
$action = \IPS\Member::loggedIn()->member_id ? 'getNewComment' : NULL;
|
||||
break;
|
||||
|
||||
case 'last':
|
||||
@@ -1348,6 +1373,10 @@ abstract class _Item extends \IPS\Content
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif( !\IPS\Member::loggedIn()->member_id AND $action == 'getNewComment' )
|
||||
{
|
||||
$action = NULL;
|
||||
}
|
||||
|
||||
if ( isset( static::$urlBase ) and isset( static::$urlTemplate ) and isset( static::$seoTitleColumn ) )
|
||||
{
|
||||
@@ -1407,7 +1436,7 @@ abstract class _Item extends \IPS\Content
|
||||
switch( $pref )
|
||||
{
|
||||
case 'unread':
|
||||
$action = 'getNewComment';
|
||||
$action = \IPS\Member::loggedIn()->member_id ? 'getNewComment' : NULL;
|
||||
break;
|
||||
|
||||
case 'last':
|
||||
@@ -1419,6 +1448,10 @@ abstract class _Item extends \IPS\Content
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif( !\IPS\Member::loggedIn()->member_id AND $action == 'getNewComment' )
|
||||
{
|
||||
$action = NULL;
|
||||
}
|
||||
|
||||
$url = \IPS\Http\Url::internal( static::$urlBase . $indexData['index_item_id'], 'front', static::$urlTemplate, \IPS\Http\Url\Friendly::seoTitle( $indexData['index_title'] ?: $itemData[ static::$databasePrefix . static::$databaseColumnMap['title'] ] ) );
|
||||
|
||||
@@ -1641,7 +1674,7 @@ abstract class _Item extends \IPS\Content
|
||||
|
||||
if ( $return )
|
||||
{
|
||||
$return = trim( str_replace( array( '"', "'", '>', '<' ), '', preg_replace( "/\s+/um", " ", str_replace( ' ', ' ', strip_tags( preg_replace('#(<(script|style)\b[^>]*>).*?(</\2>)#is', "$1$3", $return ) ) ) ) ) );
|
||||
$return = trim( preg_replace( "/\s+/um", " ", str_replace( ' ', ' ', strip_tags( preg_replace('#(<(script|style)\b[^>]*>).*?(</\2>)#is', "$1$3", $return ) ) ) ) );
|
||||
if ( mb_strlen( $return ) > 300 )
|
||||
{
|
||||
$return = mb_substr( $return, 0, 297 ) . '...';
|
||||
@@ -1864,12 +1897,15 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Rebuild node data */
|
||||
$oldContainer->setLastComment();
|
||||
$oldContainer->setLastReview();
|
||||
$oldContainer->save();
|
||||
$container->setLastComment();
|
||||
$container->setLastReview();
|
||||
$container->save();
|
||||
if( !$this->skipContainerRebuild )
|
||||
{
|
||||
$oldContainer->setLastComment();
|
||||
$oldContainer->setLastReview();
|
||||
$oldContainer->save();
|
||||
$container->setLastComment();
|
||||
$container->setLastReview();
|
||||
$container->save();
|
||||
}
|
||||
|
||||
/* Add to search index */
|
||||
if ( $this instanceof \IPS\Content\Searchable )
|
||||
@@ -2063,6 +2099,9 @@ abstract class _Item extends \IPS\Content
|
||||
\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 );
|
||||
|
||||
/* Add to the redirect table */
|
||||
$item->setRedirectTo( $this );
|
||||
|
||||
/* If we are adding redirects to the merged items, then we need to change these to link items. */
|
||||
if ( $keepLinks AND isset( $item::$databaseColumnMap['moved_to'] ) )
|
||||
{
|
||||
@@ -2264,6 +2303,12 @@ abstract class _Item extends \IPS\Content
|
||||
$this->hide( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Update mappings */
|
||||
if ( isset( static::$databaseColumnMap['container'] ) and \IPS\IPS::classUsesTrait( $this->container(), 'IPS\Node\Statistics' ) )
|
||||
{
|
||||
$this->container()->rebuildPostedIn( array( $this->$idColumn ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Update last comment stuff */
|
||||
@@ -2290,6 +2335,12 @@ abstract class _Item extends \IPS\Content
|
||||
$this->container()->setLastReview();
|
||||
$this->container()->save();
|
||||
}
|
||||
|
||||
/* Clear cached statistics */
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\Statistics' ) )
|
||||
{
|
||||
$this->clearCachedStatistics();
|
||||
}
|
||||
|
||||
/* Add to search index */
|
||||
if ( $this instanceof \IPS\Content\Searchable )
|
||||
@@ -2487,6 +2538,8 @@ abstract class _Item extends \IPS\Content
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_item_member_map', array( 'map_class=? and map_item_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
/* Remove any meta data */
|
||||
if ( ( $this instanceof \IPS\Content\MetaData ) AND isset( static::$databaseColumnMap['meta_data'] ) )
|
||||
@@ -2539,34 +2592,34 @@ abstract class _Item extends \IPS\Content
|
||||
$commentIds[] = $commentId;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_deletion_log', array( "dellog_content_class=? AND " . \IPS\Db::i()->in( 'dellog_content_id', $commentIds ), $commentClass ) );
|
||||
\IPS\Db::i()->delete( 'core_social_promote', array( "promote_class=? AND " . \IPS\Db::i()->in( 'promote_class_id', $commentIds ), $commentClass ) );
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array( "rep_class=? AND " . \IPS\Db::i()->in( 'type_id', $commentIds ), $commentClass ) );
|
||||
\IPS\Db::i()->delete( 'core_solved_index', array( "comment_class=? AND " . \IPS\Db::i()->in( 'comment_id', $commentIds ), $commentClass ) );
|
||||
$this->deleteCommentOrReviewData( $commentIds, $commentClass );
|
||||
|
||||
if ( \is_array( $where ) and \count( $where ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( $commentClass::$databaseTable, $where );
|
||||
}
|
||||
|
||||
try
|
||||
if( !$this->skipContainerRebuild )
|
||||
{
|
||||
if ( $this->container()->_comments !== NULL )
|
||||
try
|
||||
{
|
||||
/* We decrement the comment count onHide() */
|
||||
if ( ! $this->hidden() )
|
||||
if ( $this->container()->_comments !== NULL )
|
||||
{
|
||||
$this->container()->_comments = ( $this->container()->_comments - $this->mapped('num_comments') );
|
||||
/* We decrement the comment count onHide() */
|
||||
if ( ! $this->hidden() )
|
||||
{
|
||||
$this->container()->_comments = ( $this->container()->_comments - $this->mapped('num_comments') );
|
||||
}
|
||||
|
||||
$this->container()->setLastComment();
|
||||
}
|
||||
|
||||
$this->container()->setLastComment();
|
||||
}
|
||||
if ( $this->container()->_unapprovedComments !== NULL )
|
||||
{
|
||||
$this->container()->_unapprovedComments = ( $this->container()->_unapprovedComments - $this->mapped('unapproved_comments') );
|
||||
}
|
||||
$this->container()->save();
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
if ( $this->container()->_unapprovedComments !== NULL )
|
||||
{
|
||||
$this->container()->_unapprovedComments = ( $this->container()->_unapprovedComments - $this->mapped('unapproved_comments') );
|
||||
}
|
||||
$this->container()->save();
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete reviews */
|
||||
@@ -2587,32 +2640,32 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$reviewIds[] = $reviewId;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_deletion_log', array( "dellog_content_class=? AND " . \IPS\Db::i()->in( 'dellog_content_id', $reviewIds ), $reviewClass ) );
|
||||
\IPS\Db::i()->delete( 'core_social_promote', array( "promote_class=? AND " . \IPS\Db::i()->in( 'promote_class_id', $reviewIds ), $reviewClass ) );
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array( "rep_class=? AND " . \IPS\Db::i()->in( 'type_id', $reviewIds ), $reviewClass ) );
|
||||
\IPS\Db::i()->delete( 'core_solved_index', array( "comment_class=? AND " . \IPS\Db::i()->in( 'comment_id', $reviewIds ), $reviewClass ) );
|
||||
|
||||
$this->deleteCommentOrReviewData( $reviewIds, $reviewClass );
|
||||
|
||||
\IPS\Db::i()->delete( $reviewClass::$databaseTable, $where );
|
||||
|
||||
try
|
||||
if( !$this->skipContainerRebuild )
|
||||
{
|
||||
if ( $this->container()->_reviews !== NULL )
|
||||
try
|
||||
{
|
||||
/* We decrement the review count onHide() */
|
||||
if ( ! $this->hidden() )
|
||||
if ( $this->container()->_reviews !== NULL )
|
||||
{
|
||||
$this->container()->_reviews = ( $this->container()->_reviews - $this->mapped('num_reviews') );
|
||||
/* We decrement the review count onHide() */
|
||||
if ( ! $this->hidden() )
|
||||
{
|
||||
$this->container()->_reviews = ( $this->container()->_reviews - $this->mapped('num_reviews') );
|
||||
}
|
||||
|
||||
$this->container()->setLastReview();
|
||||
}
|
||||
|
||||
$this->container()->setLastReview();
|
||||
}
|
||||
if ( $this->container()->_unapprovedReviews !== NULL )
|
||||
{
|
||||
$this->container()->_unapprovedReviews = ( $this->container()->_unapprovedReviews - $this->mapped('unapproved_reviews') );
|
||||
}
|
||||
$this->container()->save();
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
if ( $this->container()->_unapprovedReviews !== NULL )
|
||||
{
|
||||
$this->container()->_unapprovedReviews = ( $this->container()->_unapprovedReviews - $this->mapped('unapproved_reviews') );
|
||||
}
|
||||
$this->container()->save();
|
||||
} catch ( \BadMethodCallException $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete tags */
|
||||
@@ -2645,6 +2698,9 @@ abstract class _Item extends \IPS\Content
|
||||
/* Delete from Our Picks */
|
||||
\IPS\Db::i()->delete( 'core_social_promote', array( 'promote_class=? AND promote_class_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
/* Delete from redirect links */
|
||||
\IPS\Db::i()->delete( 'core_item_redirect', array( 'redirect_class=? AND redirect_new_item_id=?', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
/* Delete Polls */
|
||||
if ( $this instanceof \IPS\Content\Polls and $this->getPoll() )
|
||||
{
|
||||
@@ -2662,6 +2718,20 @@ abstract class _Item extends \IPS\Content
|
||||
\IPS\Member::load( $member )->recountNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any additional comment Related data
|
||||
*
|
||||
* @param array $ids comment or review ids which are going to be deleted
|
||||
* @param string $class comment or review class name
|
||||
*/
|
||||
protected function deleteCommentOrReviewData( array $ids, string $class )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_deletion_log', array('dellog_content_class=? AND ' . \IPS\Db::i()->in( 'dellog_content_id', $ids ), $class) );
|
||||
\IPS\Db::i()->delete( 'core_social_promote', array('promote_class=? AND ' . \IPS\Db::i()->in( 'promote_class_id', $ids ), $class) );
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array('rep_class=? AND ' . \IPS\Db::i()->in( 'type_id', $ids ), $class) );
|
||||
\IPS\Db::i()->delete( 'core_solved_index', array('comment_class=? AND ' . \IPS\Db::i()->in( 'comment_id', $ids ), $class) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Change IP Address
|
||||
@@ -2707,7 +2777,7 @@ abstract class _Item extends \IPS\Content
|
||||
parent::changeAuthor( $newAuthor, $log );
|
||||
|
||||
/* Adjust post counts, but only if this is a visible post or the previous user was not a guest */
|
||||
if ( static::incrementPostCount( $this->containerWrapper() ) AND ( $oldAuthor->member_id OR $this->hidden() === 0 ) )
|
||||
if ( static::incrementPostCount( $this->containerWrapper() ) AND ( $oldAuthor->member_id OR $this->hidden() === 0 ) and ! $this->isAnonymous() )
|
||||
{
|
||||
if( $oldAuthor->member_id )
|
||||
{
|
||||
@@ -2885,8 +2955,8 @@ abstract class _Item extends \IPS\Content
|
||||
$col = static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['approved'];
|
||||
if ( $member->member_id and $includeHiddenItems !== \IPS\Content\Hideable::FILTER_PUBLIC_ONLY )
|
||||
{
|
||||
/* Only fetching a count, for a single container, no future publishing, and there is only one where clause (the container limitation) */
|
||||
if( $countOnly === TRUE AND $skipPermission instanceof \IPS\Node\Model AND !\in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) AND \count( $where ) === 1 )
|
||||
/* Only fetching a count, for a single container with a item cache count, no future publishing, and there is only one where clause (the container limitation) */
|
||||
if( $countOnly === TRUE AND $skipPermission instanceof \IPS\Node\Model AND $skipPermission->_items !== NULL AND !\in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) AND \count( $where ) === 1 )
|
||||
{
|
||||
$countShortcut = TRUE;
|
||||
$where[] = array( "({$col}=0 AND ( {$authorCol}={$member->member_id}{$extra} ) )" );
|
||||
@@ -2906,8 +2976,8 @@ abstract class _Item extends \IPS\Content
|
||||
$col = static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['hidden'];
|
||||
if ( $member->member_id and $includeHiddenItems !== \IPS\Content\Hideable::FILTER_PUBLIC_ONLY )
|
||||
{
|
||||
/* Only fetching a count, for a single container, no future publishing, and there is only one where clause (the container limitation) */
|
||||
if( $countOnly === TRUE AND $skipPermission instanceof \IPS\Node\Model AND !\in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) AND \count( $where ) === 1 )
|
||||
/* Only fetching a count, for a single container with a item cache count, no future publishing, and there is only one where clause (the container limitation) */
|
||||
if( $countOnly === TRUE AND $skipPermission instanceof \IPS\Node\Model AND $skipPermission->_items !== NULL AND !\in_array( 'IPS\Content\FuturePublishing', class_implements( \get_called_class() ) ) AND \count( $where ) === 1 )
|
||||
{
|
||||
$countShortcut = TRUE;
|
||||
$where[] = array( "({$col}=1 AND ( {$authorCol}={$member->member_id}{$extra} ) )" );
|
||||
@@ -3086,7 +3156,7 @@ abstract class _Item extends \IPS\Content
|
||||
/* Are we doing a pseudo-rand ordering? */
|
||||
if( $order == '_rand' )
|
||||
{
|
||||
$subSelectClause .= static::_getRandomizationSql( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['date'] );
|
||||
$subSelectClause .= static::_getRandomizationSql( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnId, static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['title'] );
|
||||
}
|
||||
|
||||
$select = \IPS\Db::i()->select( $subSelectClause, static::$databaseTable, array_merge( $where, $containerWhere ), $order, $limit, ( $joinComments ? static::$databasePrefix . static::$databaseColumnId : NULL ), NULL, $queryFlags );
|
||||
@@ -3163,7 +3233,7 @@ abstract class _Item extends \IPS\Content
|
||||
/* Are we doing a pseudo-rand ordering? */
|
||||
if( $order == '_rand' )
|
||||
{
|
||||
$selectClause .= static::_getRandomizationSql( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['date'] );
|
||||
$selectClause .= static::_getRandomizationSql( static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnId, static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['title'] );
|
||||
}
|
||||
|
||||
if ( $joins !== NULL AND \count( $joins ) )
|
||||
@@ -3237,12 +3307,13 @@ abstract class _Item extends \IPS\Content
|
||||
/**
|
||||
* Get randomization SQL query clause
|
||||
*
|
||||
* @param string $column Column to use for randomization
|
||||
* @param string $id ID column to use
|
||||
* @param string $title Text column to use
|
||||
* @return string
|
||||
*/
|
||||
protected static function _getRandomizationSql( $column )
|
||||
protected static function _getRandomizationSql( $id, $title )
|
||||
{
|
||||
return ', CONCAT( SUBSTR(' . $column . ', ' . '10, 10 ), SUBSTR(' . $column . ', ' . '9, 10 ), SUBSTR( ' . $column . ', ' . rand( 1, 9 ) . ', 10 ), SUBSTR( ' . $column . ', ' . rand( 4, 7 ) . ', 9 ) ) as _rand';
|
||||
return ", SUBSTR( MD5( CONCAT( {$id}, {$title} ) ), " . rand( 2, 25 ) . " ) as _rand";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3979,7 +4050,15 @@ abstract class _Item extends \IPS\Content
|
||||
elseif ( $this->mapped('num_comments') >= 500 )
|
||||
{
|
||||
/* Its more efficient to just get the primary ids first without joins and then we can fetch all the data on the second query once the offset gets larger */
|
||||
$ids = iterator_to_array( $class::db()->select( $class::$databasePrefix . $class::$databaseColumnId, $class::$databaseTable, $where, $order, array( $offset, $limit ) )->setKeyField( $class::$databasePrefix . $class::$databaseColumnId ) );
|
||||
if( method_exists( $this, 'forceIndexForPaginatedIds' ) and $this->forceIndexForPaginatedIds() and $offset < 20000 )
|
||||
{
|
||||
/* Only use the index if we're not at a massive offset */
|
||||
$ids = iterator_to_array( $class::db()->select( $class::$databasePrefix . $class::$databaseColumnId, $class::$databaseTable, $where, $order, array($offset, $limit) )->forceIndex( $this->forceIndexForPaginatedIds() )->setKeyField( $class::$databasePrefix . $class::$databaseColumnId ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$ids = iterator_to_array( $class::db()->select( $class::$databasePrefix . $class::$databaseColumnId, $class::$databaseTable, $where, $order, array($offset, $limit) )->setKeyField( $class::$databasePrefix . $class::$databaseColumnId ) );
|
||||
}
|
||||
|
||||
$where = array( array( $class::db()->in( $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnId, array_keys( $ids ) ) ) );
|
||||
$offset = 0;
|
||||
@@ -4263,13 +4342,13 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Solved count */
|
||||
$commentClass = static::$commentClass;
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\Solvable' ) )
|
||||
{
|
||||
if ( $this->containerAllowsMemberSolvable() OR $this->containerAllowsSolvable() )
|
||||
{
|
||||
$memberIds = array();
|
||||
$solvedCounts = array();
|
||||
$commentClass = static::$commentClass;
|
||||
$authorField = $commentClass::$databaseColumnMap['author'];
|
||||
|
||||
foreach( $results as $id => $data )
|
||||
@@ -4295,6 +4374,18 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
}
|
||||
|
||||
/* Recognized content */
|
||||
if ( \IPS\IPS::classUsesTrait( $commentClass, 'IPS\Content\Recognizable' ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_member_recognize', [ [ 'r_content_class=?', $commentClass ], [ \IPS\Db::i()->in('r_content_id', array_keys( $results ) ) ] ] ) as $row )
|
||||
{
|
||||
if ( isset( $results[ $row['r_content_id'] ] ) )
|
||||
{
|
||||
$results[ $row['r_content_id'] ]->recognized = \IPS\core\Achievements\Recognize::constructFromData( $row );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return ( $limit === 1 ) ? NULL : $results;
|
||||
}
|
||||
@@ -4357,6 +4448,21 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
public static $checkPostsPerDay = TRUE;
|
||||
|
||||
/**
|
||||
* Return the comment form object
|
||||
*
|
||||
* @return \IPS\Helpers\Form
|
||||
*/
|
||||
protected function _commentForm()
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$form = new \IPS\Helpers\Form( 'commentform' . '_' . $this->$idColumn, static::$formLangPrefix . 'submit_comment' );
|
||||
$form->class = 'ipsForm_vertical';
|
||||
$form->hiddenValues['_contentReply'] = TRUE;
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build comment form
|
||||
*
|
||||
@@ -4379,9 +4485,7 @@ abstract class _Item extends \IPS\Content
|
||||
$commentIdColumn = $commentClass::$databaseColumnId;
|
||||
$commentDateColumn = $commentClass::$databaseColumnMap['date'];
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'commentform' . '_' . $this->$idColumn, static::$formLangPrefix . 'submit_comment' );
|
||||
$form->class = 'ipsForm_vertical';
|
||||
$form->hiddenValues['_contentReply'] = TRUE;
|
||||
$form = $this->_commentForm();
|
||||
|
||||
$elements = $this->commentFormElements();
|
||||
|
||||
@@ -4457,15 +4561,21 @@ abstract class _Item extends \IPS\Content
|
||||
/* Or post? */
|
||||
$comment = $this->processCommentForm( $values );
|
||||
unset( $this->commentPageCount );
|
||||
|
||||
$newPageCount = $this->commentPageCount();
|
||||
|
||||
if ( $comment->hidden() === -3 )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register', 'front', 'register' ) );
|
||||
}
|
||||
elseif( $comment->hidden() AND !\IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'type' => 'add', 'id' => $comment->$commentIdColumn, 'page' => $newPageCount, 'total' => $this->mapped('num_comments'), 'content' => '', 'message' => \IPS\Member::loggedIn()->language()->addToStack( 'mod_queue_message' ) ) );
|
||||
}
|
||||
elseif ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
$this->markRead( NULL, NULL, NULL, TRUE );
|
||||
|
||||
$newPageCount = $this->commentPageCount();
|
||||
if ( $currentPageCount != $newPageCount )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'type' => 'redirect', 'page' => $newPageCount, 'total' => $this->mapped('num_comments'), 'content' => \IPS\Output::i()->replaceEmojiWithImages( $comment->html() ), 'url' => (string) $comment->url('find') ) );
|
||||
@@ -4618,6 +4728,12 @@ abstract class _Item extends \IPS\Content
|
||||
$return['hide'] = new \IPS\Helpers\Form\YesNo( 'hide', FALSE , FALSE, array( 'label' => 'hide' ) );
|
||||
}
|
||||
|
||||
/* Post Anonymously */
|
||||
if ( $container and $container->canPostAnonymously( $container::ANON_COMMENTS ) )
|
||||
{
|
||||
$return['post_anonymously'] = new \IPS\Helpers\Form\YesNo( 'post_anonymously', FALSE, FALSE, array( 'label' => \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_suffix' ) ), NULL, NULL, NULL, 'post_anonymously' );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -4649,7 +4765,13 @@ abstract class _Item extends \IPS\Content
|
||||
$parameters = array_merge( array( 'reply-' . static::$application . '/' . static::$module . '-' . $this->$idColumn ), $comment->attachmentIds() );
|
||||
\IPS\File::claimAttachments( ...$parameters );
|
||||
|
||||
/* Auto-follow */
|
||||
/* Post anonymously */
|
||||
if( isset( $values[ 'post_anonymously' ] ) )
|
||||
{
|
||||
$comment->setAnonymous( $values[ 'post_anonymously' ] );
|
||||
}
|
||||
|
||||
/* Auto-follow - If posted anonymously we should set follow to anonymous as well */
|
||||
if( isset( $values[ static::$formLangPrefix . 'auto_follow' ] ) )
|
||||
{
|
||||
if ( $values[ static::$formLangPrefix . 'auto_follow' ] and !\IPS\Member::loggedIn()->following( static::$application, $followArea, $this->$idColumn ) )
|
||||
@@ -5133,12 +5255,6 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
protected $_averageReviewRating = NULL;
|
||||
|
||||
/**
|
||||
* @brief Have we output the average review rating?
|
||||
* @note Structured data only allows this to be output once, so we need to track if we've output it
|
||||
*/
|
||||
public $printedAverageReviewRating = FALSE;
|
||||
|
||||
/**
|
||||
* Get average review rating
|
||||
*
|
||||
@@ -5199,7 +5315,15 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$this->_lastCommenter = \IPS\Member::load( $this->mapped('last_comment_by') );
|
||||
|
||||
if ( ! $this->_lastCommenter->member_id and isset( static::$databaseColumnMap['last_comment_name'] ) )
|
||||
if ( ! $this->_lastCommenter->member_id and isset( static::$databaseColumnMap['is_anon'] ) )
|
||||
{
|
||||
$_lastComment = $this->comments( 1, 0, 'date', 'desc' );
|
||||
if ( $_lastComment !== NULL AND $_lastComment->isAnonymous() )
|
||||
{
|
||||
$this->_lastCommenter->name = \IPS\Member::loggedIn()->language()->addToStack( "post_anonymously_placename" );
|
||||
}
|
||||
}
|
||||
else if ( ! $this->_lastCommenter->member_id and isset( static::$databaseColumnMap['last_comment_name'] ) )
|
||||
{
|
||||
if ( $this->mapped('last_comment_name') )
|
||||
{
|
||||
@@ -5217,7 +5341,15 @@ abstract class _Item extends \IPS\Content
|
||||
|
||||
if( $_lastComment !== NULL )
|
||||
{
|
||||
$this->_lastCommenter = $this->comments( 1, 0, 'date', 'desc' )->author();
|
||||
if ( $_lastComment->isAnonymous() )
|
||||
{
|
||||
$this->_lastCommenter = new \IPS\Member;
|
||||
$this->_lastCommenter->name = \IPS\Member::loggedIn()->language()->addToStack( "post_anonymously_placename" );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_lastCommenter = $this->comments( 1, 0, 'date', 'desc' )->author();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5416,7 +5548,7 @@ abstract class _Item extends \IPS\Content
|
||||
return;
|
||||
}
|
||||
|
||||
$columns = array( 'last_comment', 'last_comment_by', 'last_comment_name' );
|
||||
$columns = array( 'last_comment', 'last_comment_by', 'last_comment_name', 'last_comment_anon' );
|
||||
$resync = FALSE;
|
||||
foreach ( $columns as $k )
|
||||
{
|
||||
@@ -5471,6 +5603,11 @@ abstract class _Item extends \IPS\Content
|
||||
$lastCommentNameField = static::$databaseColumnMap['last_comment_name'];
|
||||
$this->$lastCommentNameField = ( !$comment->author()->member_id and isset( $comment::$databaseColumnMap['author_name'] ) ) ? $comment->mapped('author_name') : $comment->author()->name;
|
||||
}
|
||||
if ( isset( static::$databaseColumnMap['last_comment_anon'] ) )
|
||||
{
|
||||
$lastCommentAnonField = static::$databaseColumnMap['last_comment_anon'];
|
||||
$this->$lastCommentAnonField = $comment->isAnonymous();
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
@@ -5846,15 +5983,45 @@ abstract class _Item extends \IPS\Content
|
||||
/**
|
||||
* Generate meta data between comments. It is assumed they all belong to the same topic
|
||||
*
|
||||
* @param array $comments Array of $comment objects
|
||||
* @param array $comments Array of $comment objects
|
||||
* @param bool $anonymous Anonymize the moderator actions
|
||||
* @return array
|
||||
*/
|
||||
public function generateCommentMetaData( array $comments ) : array
|
||||
public function generateCommentMetaData( array $comments, $anonymous = FALSE ) : array
|
||||
{
|
||||
if ( ! $this->showCommentMeta('time') and ! $this->showCommentMeta('moderation') )
|
||||
{
|
||||
return $comments;
|
||||
}
|
||||
|
||||
$showAnonymous = FALSE;
|
||||
|
||||
if( $anonymous )
|
||||
{
|
||||
$containerClass = static::$containerNodeClass;
|
||||
|
||||
if( isset( $containerClass::$modPerm ) AND $containerClass::$modPerm )
|
||||
{
|
||||
$showAnonymous = !(
|
||||
\IPS\Member::loggedIn()->modPermission( $containerClass::$modPerm ) === TRUE
|
||||
or
|
||||
\IPS\Member::loggedIn()->modPermission( $containerClass::$modPerm ) === -1
|
||||
or
|
||||
(
|
||||
\is_array( \IPS\Member::loggedIn()->modPermission( $containerClass::$modPerm ) )
|
||||
and
|
||||
\in_array( $this->container()->_id, \IPS\Member::loggedIn()->modPermission( $containerClass::$modPerm ) )
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$showAnonymous = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$anonymous ? (bool) \IPS\Member::loggedIn()->modPermissions() : FALSE;
|
||||
|
||||
$lastDate = NULL;
|
||||
|
||||
@@ -5892,9 +6059,9 @@ abstract class _Item extends \IPS\Content
|
||||
|
||||
if ( ( $modActionDate > $commentDate and $modActionDate < $nextCommentDate ) or ( $modActionDate > $commentDate and !$next ) )
|
||||
{
|
||||
|
||||
$commentDate = $modActionDate;
|
||||
$blurb = NULL;
|
||||
$langKey = 'comment_meta_moderation_' . $data['lang_key'];
|
||||
$langKey = 'comment_meta_moderation_' . ( $showAnonymous ? 'anon_' : '' ) . $data['lang_key'];
|
||||
|
||||
/* Edits always get their own meta action bubble, so handle those individually */
|
||||
if ( \in_array( $data['lang_key'], array( 'modlog__item_edit', 'modlog__comment_edit_title' ) ) )
|
||||
@@ -5964,7 +6131,7 @@ abstract class _Item extends \IPS\Content
|
||||
/* If this is just one action, generate a full bubble */
|
||||
$comment->_data['metaData']['comment']['moderation'][$actions[0]['action']] = array(
|
||||
'row' => $actions[0]['row'],
|
||||
'blurb' => \IPS\Member::loggedIn()->language()->addToStack( $actions[0]['lang_key'], FALSE, array('htmlsprintf' => array($this->definiteArticle(), \IPS\Member::load( $data['member_id'] )->link())) ),
|
||||
'blurb' => \IPS\Member::loggedIn()->language()->addToStack( $actions[0]['lang_key'], FALSE, array('htmlsprintf' => array($this->definiteArticle(), \IPS\Member::load( $actions[0]['row']['member_id'] )->link())) ),
|
||||
'action' => $actions[0]['lang_key']
|
||||
);
|
||||
}
|
||||
@@ -5979,7 +6146,7 @@ abstract class _Item extends \IPS\Content
|
||||
|
||||
$comment->_data['metaData']['comment']['moderation'][$groupIdx] = array(
|
||||
'row' => $actions[0]['row'], // Use the first action in this group as the 'row', to provide the time etc. for all items in this bubble
|
||||
'blurb' => \IPS\Member::loggedIn()->language()->addToStack( 'comment_meta_moderation_modlog__action_group', FALSE, array('htmlsprintf' => array($this->definiteArticle(), \IPS\Member::load( $data['member_id'] )->link(), \IPS\Member::loggedIn()->language()->formatList( $actionPhrases ) ) ) ),
|
||||
'blurb' => \IPS\Member::loggedIn()->language()->addToStack( 'comment_meta_moderation_' . ( $showAnonymous ? 'anon_' : '' ) . 'modlog__action_group', FALSE, array('htmlsprintf' => array($this->definiteArticle(), \IPS\Member::load( $lastActionMember )->link(), \IPS\Member::loggedIn()->language()->formatList( $actionPhrases ) ) ) ),
|
||||
'action' => $actions[0]['lang_key']
|
||||
);
|
||||
}
|
||||
@@ -6034,6 +6201,11 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
public function showCommentMeta( $key )
|
||||
{
|
||||
if( $key == 'moderation' AND \IPS\Member::loggedIn()->group['gbw_hide_inline_modevents'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$metaKey = static::$showMetaSettingKey;
|
||||
|
||||
if ( isset( \IPS\Settings::i()->$metaKey ) and \IPS\Settings::i()->$metaKey )
|
||||
@@ -6200,7 +6372,7 @@ abstract class _Item extends \IPS\Content
|
||||
// OK
|
||||
}
|
||||
/* If it's pending approval, and we're the author it's fine */
|
||||
elseif ( $this->hidden() === 1 and $this->author()->member_id == $member->member_id )
|
||||
elseif ( $this->hidden() === 1 and $this->author()->member_id and $this->author()->member_id == $member->member_id )
|
||||
{
|
||||
// OK
|
||||
}
|
||||
@@ -6722,8 +6894,7 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
public function onHide( $member )
|
||||
{
|
||||
$container = NULL;
|
||||
if ( method_exists( $this, 'container' ) )
|
||||
if ( method_exists( $this, 'container' ) AND !$this->skipContainerRebuild )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -6759,13 +6930,11 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
public function onUnhide( $approving, $member )
|
||||
{
|
||||
$container = NULL;
|
||||
|
||||
/* If approving, we may need to increase the post count */
|
||||
if ( $approving AND isset( static::$commentClass ) )
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
if ( ( static::$firstCommentRequired and $commentClass::incrementPostCount( $this->containerWrapper() ) ) or static::incrementPostCount( $this->containerWrapper() ) )
|
||||
if ( !$this->isAnonymous() and ( static::$firstCommentRequired and $commentClass::incrementPostCount( $this->containerWrapper() ) ) or static::incrementPostCount( $this->containerWrapper() ) )
|
||||
{
|
||||
$this->author()->member_posts++;
|
||||
$this->author()->save();
|
||||
@@ -6773,7 +6942,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Update container */
|
||||
if ( method_exists( $this, 'container' ) )
|
||||
if ( method_exists( $this, 'container' ) AND !$this->skipContainerRebuild )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -6800,7 +6969,6 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Warning Reference Key
|
||||
*
|
||||
@@ -6865,6 +7033,20 @@ abstract class _Item extends \IPS\Content
|
||||
return $this->sharelinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Web Share Data
|
||||
*
|
||||
* @return array|NULL
|
||||
*/
|
||||
public function webShareData(): ?array
|
||||
{
|
||||
return array(
|
||||
'title' => \IPS\Text\Parser::truncate( $this->mapped('title'), TRUE ),
|
||||
'text' => \IPS\Text\Parser::truncate( $this->mapped('title'), TRUE ),
|
||||
'url' => (string) $this->url()
|
||||
);
|
||||
}
|
||||
|
||||
/* !ReadMarkers */
|
||||
|
||||
/**
|
||||
@@ -6974,7 +7156,7 @@ abstract class _Item extends \IPS\Content
|
||||
$latestThing = 0;
|
||||
foreach ( array( 'updated', 'last_comment', 'last_review' ) as $k )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap[ $k ] ) and ( $this->mapped( $k ) < time() AND $this->mapped( $k ) > $latestThing ) )
|
||||
if ( isset( static::$databaseColumnMap[ $k ] ) and ( $this->mapped( $k ) <= time() AND $this->mapped( $k ) > $latestThing ) )
|
||||
{
|
||||
$latestThing = $this->mapped( $k );
|
||||
}
|
||||
@@ -7001,7 +7183,7 @@ abstract class _Item extends \IPS\Content
|
||||
* @return int|NULL 0 = read. -1 = never read. 1 = updated since last read. NULL = unsupported
|
||||
* @note When a node is marked read, we stop noting which individual content items have been read. Therefore, -1 vs 1 is not always accurate but rather goes on if the item was created
|
||||
*/
|
||||
public static function unreadFromData( \IPS\Member $member = NULL, $updateDate, $createDate, $itemId, $containerId, $limitToApp = TRUE )
|
||||
public static function unreadFromData( ?\IPS\Member $member, $updateDate, $createDate, $itemId, $containerId, $limitToApp = TRUE )
|
||||
{
|
||||
/* Get the member */
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
@@ -7034,7 +7216,7 @@ abstract class _Item extends \IPS\Content
|
||||
}
|
||||
else
|
||||
{
|
||||
$resetTime = ( $resetTimes > $member->marked_site_read ) ? $resetTimes : $member->marked_site_read;
|
||||
$resetTime = ( !\is_array( $resetTimes ) AND $resetTimes > $member->marked_site_read ) ? $resetTimes : $member->marked_site_read;
|
||||
}
|
||||
|
||||
/* If the reset time is after when this item was updated, it's read */
|
||||
@@ -7251,8 +7433,14 @@ abstract class _Item extends \IPS\Content
|
||||
{
|
||||
$subWhere = array();
|
||||
$checked = array();
|
||||
foreach ( array( 'updated', 'last_comment', 'last_review' ) as $k )
|
||||
foreach ( array( 'last_comment', 'last_review', 'updated' ) as $k )
|
||||
{
|
||||
/* If we already hit last_comment and/or last_review, skip updated since we don't mark as unread when stuff is updated */
|
||||
if( \count( $checked ) AND $k == 'updated' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ( isset( static::$databaseColumnMap[ $k ] ) )
|
||||
{
|
||||
if ( \is_array( static::$databaseColumnMap[ $k ] ) )
|
||||
@@ -8091,6 +8279,9 @@ abstract class _Item extends \IPS\Content
|
||||
|
||||
/* Send notifications if necessary */
|
||||
$this->sendNotifications();
|
||||
|
||||
/* Give out points */
|
||||
$this->author()->achievementAction( 'core', 'NewContentItem', $this );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8101,7 +8292,6 @@ abstract class _Item extends \IPS\Content
|
||||
*/
|
||||
public function onPublish( $member )
|
||||
{
|
||||
$container = NULL;
|
||||
if ( method_exists( $this, 'container' ) )
|
||||
{
|
||||
try
|
||||
@@ -8113,20 +8303,23 @@ abstract class _Item extends \IPS\Content
|
||||
$container->_futureItems = ( $container->_futureItems > 0 ) ? $container->_futureItems - 1 : 0;
|
||||
}
|
||||
|
||||
$container->_items = $container->_items + 1;
|
||||
|
||||
if ( isset( static::$commentClass ) )
|
||||
if( !$this->skipContainerRebuild )
|
||||
{
|
||||
$container->_comments = $container->_comments + $this->mapped('num_comments');
|
||||
$container->setLastComment();
|
||||
}
|
||||
if ( isset( static::$reviewClass ) )
|
||||
{
|
||||
$container->_reviews = $container->_reviews + $this->mapped('num_reviews');
|
||||
$container->setLastReview();
|
||||
}
|
||||
$container->_items = $container->_items + 1;
|
||||
|
||||
$container->save();
|
||||
if ( isset( static::$commentClass ) )
|
||||
{
|
||||
$container->_comments = $container->_comments + $this->mapped('num_comments');
|
||||
$container->setLastComment();
|
||||
}
|
||||
if ( isset( static::$reviewClass ) )
|
||||
{
|
||||
$container->_reviews = $container->_reviews + $this->mapped('num_reviews');
|
||||
$container->setLastReview();
|
||||
}
|
||||
|
||||
$container->save();
|
||||
}
|
||||
}
|
||||
catch ( \BadMethodCallException $e ) { }
|
||||
}
|
||||
@@ -8318,11 +8511,12 @@ abstract class _Item extends \IPS\Content
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_ratings', array(
|
||||
'class' => \get_called_class(),
|
||||
'item_id' => $this->$idColumn,
|
||||
'member' => (int) \IPS\Member::loggedIn()->member_id,
|
||||
'rating' => $values['rating'],
|
||||
'ip' => \IPS\Request::i()->ipAddress()
|
||||
'class' => \get_called_class(),
|
||||
'item_id' => $this->$idColumn,
|
||||
'member' => (int) \IPS\Member::loggedIn()->member_id,
|
||||
'rating' => $values['rating'],
|
||||
'ip' => \IPS\Request::i()->ipAddress(),
|
||||
'rating_date' => time()
|
||||
), TRUE );
|
||||
|
||||
if ( isset( static::$databaseColumnMap['rating_average'] ) )
|
||||
@@ -8560,7 +8754,9 @@ abstract class _Item extends \IPS\Content
|
||||
'meta_class' => \get_class( $this ),
|
||||
'meta_item_id' => $this->$idColumn,
|
||||
'meta_type' => $type,
|
||||
'meta_data' => $data
|
||||
'meta_data' => $data,
|
||||
'meta_item_author' => $this->author()->member_id,
|
||||
'meta_added' => time()
|
||||
) );
|
||||
|
||||
$column = static::$databaseColumnMap['meta_data'];
|
||||
@@ -8644,6 +8840,49 @@ abstract class _Item extends \IPS\Content
|
||||
\IPS\Db::i()->delete( 'core_content_meta', array( "meta_class=? AND meta_item_id=?", \get_class( $this ), $this->$idColumn ) );
|
||||
}
|
||||
|
||||
/* ! Redirect links */
|
||||
|
||||
/**
|
||||
* Store a redirect
|
||||
*
|
||||
* Saves a redirect so when this class:item_id is attempted to be loaded in the future, it 301 redirects to the new item
|
||||
*
|
||||
* @param \IPS\Content\Item $item The item to redirect to
|
||||
*/
|
||||
public function setRedirectTo( \IPS\Content\Item $item )
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
\IPS\Db::i()->insert( 'core_item_redirect', array(
|
||||
'redirect_class' => \get_class( $item ),
|
||||
'redirect_item_id' => $this->$idColumn,
|
||||
'redirect_new_item_id' => $item->$idColumn
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the redirect to data
|
||||
*
|
||||
* Fetches the \IPS\Content\Item we want to redirect to
|
||||
*
|
||||
* @param object $class Class to look up
|
||||
* @param int $id The ID to look up
|
||||
* @param bool $checkPerms Check permissions when loading
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
public static function getRedirectFrom( $id, $checkPerms=TRUE )
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
try
|
||||
{
|
||||
$method = ( $checkPerms ) ? 'loadAndCheckPerms' : 'load';
|
||||
return static::$method( \IPS\Db::i()->select( 'redirect_new_item_id', 'core_item_redirect', array( 'redirect_class=? and redirect_item_id=?', \get_called_class(), $id ) )->first() );
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can perform an action on a message
|
||||
*
|
||||
@@ -8747,6 +8986,12 @@ abstract class _Item extends \IPS\Content
|
||||
public function featureComment( \IPS\Content\Comment $comment, $note = NULL, \IPS\Member $member = NULL )
|
||||
{
|
||||
\IPS\Application::load('core')->extensions( 'core', 'MetaData' )['FeaturedComments']->featureComment( $this, $comment, $note, $member );
|
||||
|
||||
/* Give points */
|
||||
$comment->author()->achievementAction( 'core', 'ContentPromotion', [
|
||||
'content' => $comment,
|
||||
'promotype' => 'recommend' //Yeah it says feature, but it's really recommend
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8815,7 +9060,7 @@ abstract class _Item extends \IPS\Content
|
||||
* @param \IPS\Member|NULL $member
|
||||
* @return void
|
||||
*/
|
||||
public function toggleItemModeration( $action, ?\IPS\Member $member = NULL ): void
|
||||
public function toggleItemModeration( $action, ?\IPS\Member $member = NULL )
|
||||
{
|
||||
if ( !\in_array( $action, array( 'enable', 'disable' ) ) )
|
||||
{
|
||||
|
||||
@@ -122,8 +122,14 @@ trait ItemTopic
|
||||
$title = $this->getTopicTitle();
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $title );
|
||||
$topic->title = $title;
|
||||
$topic->topic_archive_status = \IPS\forums\Topic::ARCHIVE_EXCLUDE;
|
||||
$topic->topic_archive_status = \IPS\forums\Topic::ARCHIVE_EXCLUDE;
|
||||
$topic->save();
|
||||
|
||||
if( $this->isAnonymous() )
|
||||
{
|
||||
$topic->setAnonymous( TRUE, $this->author );
|
||||
}
|
||||
|
||||
$topic->markRead( $this->author() );
|
||||
if ( \IPS\Settings::i()->tags_enabled )
|
||||
{
|
||||
@@ -134,10 +140,22 @@ trait ItemTopic
|
||||
$content = $this->getTopicContent();
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $content );
|
||||
$post = \IPS\forums\Topic\Post::create( $topic, $content, TRUE, NULL, NULL, $this->author() );
|
||||
|
||||
if( $this->isAnonymous() )
|
||||
{
|
||||
$post->setAnonymous( TRUE, $this->author );
|
||||
}
|
||||
|
||||
$topic->topic_firstpost = $post->pid;
|
||||
$topic->save();
|
||||
\IPS\Content\Search\Index::i()->index( $post );
|
||||
|
||||
/* Send notifications */
|
||||
if ( !$topic->isFutureDate() AND !$topic->hidden() )
|
||||
{
|
||||
$topic->sendNotifications();
|
||||
}
|
||||
|
||||
/* Update file */
|
||||
$this->$column = $topic->tid;
|
||||
$this->save();
|
||||
|
||||
@@ -107,9 +107,16 @@ trait Reactable
|
||||
/* Remove the initial reaction, if we have reacted */
|
||||
if ( $reacted )
|
||||
{
|
||||
$this->removeReaction( $member );
|
||||
$this->removeReaction( $member, FALSE );
|
||||
}
|
||||
|
||||
/* Give points */
|
||||
$owner->achievementAction( 'core', 'Reaction', [
|
||||
'giver' => $member,
|
||||
'content' => $this,
|
||||
'reaction' => $reaction
|
||||
] );
|
||||
|
||||
/* Actually insert it */
|
||||
$idColumn = static::$databaseColumnId;
|
||||
\IPS\Db::i()->insert( 'core_reputation_index', array(
|
||||
@@ -150,10 +157,11 @@ trait Reactable
|
||||
/**
|
||||
* Remove Reaction
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member, or NULL for currently logged in member
|
||||
* @param \IPS\Member|NULL $member The member, or NULL for currently logged in member
|
||||
* @param bool $removeNotifications Whether to remove notifications or not
|
||||
* @return void
|
||||
*/
|
||||
public function removeReaction( \IPS\Member $member = NULL )
|
||||
public function removeReaction( \IPS\Member $member = NULL, $removeNotifications = TRUE )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
@@ -189,18 +197,21 @@ trait Reactable
|
||||
}
|
||||
|
||||
/* Remove Notifications */
|
||||
$memberIds = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '`member`', 'core_notifications', array( 'notification_key=? AND item_class=? AND item_id=?', 'new_likes', (string) \get_class( $this ), (int) $this->$idColumn ) ) as $memberToRecount )
|
||||
if( $removeNotifications === TRUE )
|
||||
{
|
||||
$memberIds[ $memberToRecount ] = $memberToRecount;
|
||||
}
|
||||
$memberIds = array();
|
||||
|
||||
\IPS\Db::i()->delete( 'core_notifications', array( 'notification_key=? AND item_class=? AND item_id=?', 'new_likes', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
foreach( \IPS\Db::i()->select( '`member`', 'core_notifications', array( 'notification_key=? AND item_class=? AND item_id=?', 'new_likes', (string) \get_class( $this ), (int) $this->$idColumn ) ) as $memberToRecount )
|
||||
{
|
||||
$memberIds[ $memberToRecount ] = $memberToRecount;
|
||||
}
|
||||
|
||||
foreach( $memberIds as $memberToRecount )
|
||||
{
|
||||
\IPS\Member::load( $memberToRecount )->recountNotifications();
|
||||
\IPS\Db::i()->delete( 'core_notifications', array( 'notification_key=? AND item_class=? AND item_id=?', 'new_likes', (string) \get_class( $this ), (int) $this->$idColumn ) );
|
||||
|
||||
foreach( $memberIds as $memberToRecount )
|
||||
{
|
||||
\IPS\Member::load( $memberToRecount )->recountNotifications();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,17 +215,6 @@ class _Reaction extends \IPS\Node\Model
|
||||
return parent::get__enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reaction Store
|
||||
*
|
||||
* @return array
|
||||
* @deprecated
|
||||
*/
|
||||
public static function reactionStore()
|
||||
{
|
||||
return static::getStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reaction Store
|
||||
*
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Recognizable Trait
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 25 March 2021
|
||||
*/
|
||||
|
||||
namespace IPS\Content;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solvable Trait
|
||||
*/
|
||||
trait Recognizable
|
||||
{
|
||||
|
||||
/**
|
||||
* Can this member "unrecognize" the content author?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return boolean
|
||||
*/
|
||||
public function canRemoveRecognize( ?\IPS\Member $member=NULL ): bool
|
||||
{
|
||||
/* Already recognized? (First quick check when built from item::comments() */
|
||||
$isRecognized = FALSE;
|
||||
if ( isset( $this->recognized ) and $this->recognized )
|
||||
{
|
||||
$isRecognized = TRUE;
|
||||
}
|
||||
|
||||
/* Not there, try loading from content */
|
||||
if ( ! $isRecognized )
|
||||
{
|
||||
try
|
||||
{
|
||||
$recognize = \IPS\core\Achievements\Recognize::loadFromContent( $this );
|
||||
$isRecognized = TRUE;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
/* An error, or it doesn't exist */
|
||||
$isRecognized = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $isRecognized )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Moderator check */
|
||||
return $this->canModerateRecognized( $member );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this member "recognize" the content author?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return boolean
|
||||
*/
|
||||
public function canRecognize( ?\IPS\Member $member=NULL ): bool
|
||||
{
|
||||
/* Already recognized? */
|
||||
if ( isset( $this->recognized ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Moderator check */
|
||||
if ( ! $this->canModerateRecognized( $member ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! $this->author()->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Can not recognize yourself */
|
||||
if ( $member->member_id === $this->author()->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if we have moderator permissions
|
||||
*
|
||||
* @param $member
|
||||
* @return bool
|
||||
*/
|
||||
protected function canModerateRecognized( $member )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Moderator check */
|
||||
if ( ! $member->modPermission('can_recognize_content') )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( $member->modPermission('can_recognize_content') != '*' AND ! \count( $member->modPermission('can_recognize_content_options') ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we show this recognized data?
|
||||
*
|
||||
* @param \IPS\Member|null $viewing
|
||||
* @return bool
|
||||
*/
|
||||
public function showRecognized( ?\IPS\Member $viewing=NULL ): bool
|
||||
{
|
||||
$viewing = $viewing ?: \IPS\Member::loggedIn();
|
||||
if ( isset( $this->recognized ) )
|
||||
{
|
||||
if ( $this->recognized->public or ( ( $viewing->member_id == $this->recognized->member_id ) OR ( $viewing->modPermission('can_recognize_content') ) ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove recognition given to this content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeRecognize()
|
||||
{
|
||||
\IPS\core\Achievements\Recognize::loadFromContent( $this )->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a blurb about this
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function recognizedBlurb(): array
|
||||
{
|
||||
$return = [ 'message' => NULL ];
|
||||
$return['main'] = \IPS\Member::loggedIn()->language()->addToStack('recognize_blurb_main', NULL, [ 'htmlsprintf' => [ $this::$title, $this->recognized->_given_by->link() ] ] );
|
||||
if ( $this->recognized->badge and $this->recognized->points )
|
||||
{
|
||||
if ( $this->author()->member_id === \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$return['awards'] = \IPS\Member::loggedIn()->language()->addToStack( 'recognize_blurb_awarded_points_and_badge', NULL, ['htmlsprintf' => [$this->recognized->badge()->_title, $this->recognized->points]] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['awards'] = \IPS\Member::loggedIn()->language()->addToStack( 'recognize_blurb_awarded_points_and_badge_third', NULL, ['htmlsprintf' => [$this->author()->name, $this->recognized->badge()->_title, $this->recognized->points]] );
|
||||
}
|
||||
}
|
||||
else if ( $this->recognized->points )
|
||||
{
|
||||
if ( $this->author()->member_id === \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$return['awards'] = \IPS\Member::loggedIn()->language()->addToStack('recognize_blurb_awarded_points', NULL, [ 'sprintf' => [ $this->recognized->points ] ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['awards'] = \IPS\Member::loggedIn()->language()->addToStack('recognize_blurb_awarded_points_third', NULL, [ 'sprintf' => [ $this->author()->name, $this->recognized->points ] ] );
|
||||
}
|
||||
}
|
||||
else if ( $this->recognized->badge )
|
||||
{
|
||||
if ( $this->author()->member_id === \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$return['awards'] = \IPS\Member::loggedIn()->language()->addToStack('recognize_blurb_awarded_badge', NULL, [ 'htmlsprintf' => [ $this->recognized->badge()->_title ] ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$return['awards'] = \IPS\Member::loggedIn()->language()->addToStack('recognize_blurb_awarded_badge_third', NULL, [ 'htmlsprintf' => [ $this->author()->name, $this->recognized->badge()->_title ] ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->recognized->message )
|
||||
{
|
||||
$return['message'] = $this->recognized->message;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
@@ -94,10 +94,11 @@ abstract class _Review extends \IPS\Content\Comment
|
||||
$obj->item()->$ratingField = $obj->item()->averageReviewRating() ?: 0;
|
||||
$obj->item()->save();
|
||||
|
||||
/* Send notifications */
|
||||
/* Send notifications and dish out points */
|
||||
if ( !$obj->hidden() and ( !$first or !$item::$firstCommentRequired ) )
|
||||
{
|
||||
$obj->sendNotifications();
|
||||
$obj->author()->achievementAction( 'core', 'Review', $obj );
|
||||
}
|
||||
else if( $obj->hidden() === 1 )
|
||||
{
|
||||
@@ -394,6 +395,40 @@ abstract class _Review extends \IPS\Content\Comment
|
||||
public function delete()
|
||||
{
|
||||
parent::delete();
|
||||
$this->_recalculateRating();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log for deletion later
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member, NULL for currently logged in, or FALSE for no member
|
||||
* @return void
|
||||
*/
|
||||
public function logDelete( $member = NULL )
|
||||
{
|
||||
parent::logDelete( $member );
|
||||
$this->_recalculateRating();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore Content
|
||||
*
|
||||
* @param bool $hidden Restore as hidden?
|
||||
* @return void
|
||||
*/
|
||||
public function restore( $hidden = FALSE )
|
||||
{
|
||||
parent::restore( $hidden );
|
||||
$this->_recalculateRating();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate rating after review action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _recalculateRating()
|
||||
{
|
||||
$itemClass = static::$itemClass;
|
||||
$ratingField = $itemClass::$databaseColumnMap['rating'];
|
||||
$this->item()->$ratingField = $this->item()->averageReviewRating() ?: 0;
|
||||
|
||||
@@ -26,7 +26,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
* @brief Elasticsearch version requirements
|
||||
*/
|
||||
const MINIMUM_VERSION = '6.0.0';
|
||||
const UNSUPPORTED_VERSION = '8.0.0';
|
||||
const UNSUPPORTED_VERSION = '7.7.0';
|
||||
|
||||
/**
|
||||
* @brief The server URL
|
||||
@@ -212,7 +212,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
|
||||
if( $error = $this->getResponseError( $r ) )
|
||||
{
|
||||
throw new \IPS\Content\Search\Elastic\Exception( $error['type'] . ' ' . $error['type'] );
|
||||
throw new \IPS\Content\Search\Elastic\Exception( $error['type'] . ': ' . $error['reason'] );
|
||||
}
|
||||
|
||||
/* Views / Comments / Reviews */
|
||||
@@ -910,7 +910,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
$item = $itemClass::load( $indexItemId );
|
||||
|
||||
$where = NULL;
|
||||
if( $ignoreId !== NULL )
|
||||
if( $ignoreId !== NULL AND isset( $itemClass::$commentClass ) )
|
||||
{
|
||||
$commentClass = $itemClass::$commentClass;
|
||||
$commentIdColumn = $commentClass::$databaseColumnId;
|
||||
|
||||
@@ -411,8 +411,8 @@ abstract class _Index extends \IPS\Patterns\Singleton
|
||||
'index_item_author' => \intval( ( $object instanceof \IPS\Content\Item ) ? $object->mapped('author') : $object->item()->mapped('author') ),
|
||||
'index_is_last_comment' => $isLastComment,
|
||||
'index_club_id' => $clubId,
|
||||
'index_class_type_id_hash' => md5( $class . ':' . $object->$idColumn )
|
||||
|
||||
'index_class_type_id_hash' => md5( $class . ':' . $object->$idColumn ),
|
||||
'index_is_anon' => $object->isAnonymous()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=?', $indexData['index_item_id'] ) );
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexData['index_item_id'] ) );
|
||||
}
|
||||
|
||||
if ( $existingData !== NULL and ( $indexData['index_class'] == $existingData['index_class'] and $indexData['index_object_id'] == $existingData['index_object_id'] ) )
|
||||
@@ -589,7 +589,7 @@ class _Index extends \IPS\Content\Search\Index
|
||||
*/
|
||||
public function resetLastComment( $classes, $indexItemId, $ignoreId = NULL )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=?', $indexItemId ) );
|
||||
\IPS\Db::i()->update( 'core_search_index', array( 'index_is_last_comment' => 0 ), array( \IPS\Db::i()->in( 'index_class', $classes ) . ' AND index_item_id=? AND index_is_last_comment=1', $indexItemId ) );
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -78,6 +78,11 @@ class _Query extends \IPS\Content\Search\Query
|
||||
* @see filterByUnread()
|
||||
*/
|
||||
protected $filterByUnread = FALSE;
|
||||
|
||||
/**
|
||||
* @brief InnoDb Stop words
|
||||
*/
|
||||
protected static $innoDBStopWords = array( 'a','about','an','are','as','at','be','by','com','de','en','for','from','how','i','in','is','it','la','of','on','or','that','the','this','to','was','what','when','where','who','will','with','und','the','www' );
|
||||
|
||||
/**
|
||||
* Filter by multiple content types
|
||||
@@ -692,7 +697,7 @@ class _Query extends \IPS\Content\Search\Query
|
||||
{
|
||||
/* Avoid packet issues */
|
||||
krsort( $markers );
|
||||
$useIds = array_flip( \array_slice( $markers, 0, 500, TRUE ) );
|
||||
$useIds = array_flip( \array_slice( $markers, 0, 1000, TRUE ) );
|
||||
$select = '';
|
||||
$from = '';
|
||||
$notIn = array();
|
||||
@@ -1096,7 +1101,8 @@ class _Query extends \IPS\Content\Search\Query
|
||||
/* Operators are not allowed */
|
||||
$word = preg_replace( '/[+\-><\(\)~*\"@%]+/', '', $word );
|
||||
|
||||
if ( $word )
|
||||
/* If any words are stop words the lookup will fail */
|
||||
if ( $word and !\in_array( $word, static::$innoDBStopWords ) )
|
||||
{
|
||||
$words[] = $word;
|
||||
}
|
||||
@@ -1250,10 +1256,15 @@ class _Query extends \IPS\Content\Search\Query
|
||||
$order = $this->order;
|
||||
|
||||
/* This forces MySQL to strongly hint a better index to the optimiser for MySQL 5.7+, even though sorting will not be affected */
|
||||
if ( $this->filterByUnread and ( ! mb_stristr( \IPS\Db::i()->server_info, '-MariaDB' ) and \IPS\Db::i()->server_version >= 50700 ) )
|
||||
if ( $this->filterByUnread !== FALSE and ( ! mb_stristr( \IPS\Db::i()->server_info, '-MariaDB' ) and \IPS\Db::i()->server_version >= 50700 ) )
|
||||
{
|
||||
$order .= ", index_date_updated";
|
||||
}
|
||||
|
||||
if( $this->filterByUnread === TRUE )
|
||||
{
|
||||
$this->forceIndex = 'index_date_updated';
|
||||
}
|
||||
|
||||
/* But we're sorting by relevancy, we need to actually select that value with our fancy algorithm */
|
||||
if ( mb_substr( $this->order, 0, 9 ) === 'calcscore' )
|
||||
@@ -1452,4 +1463,4 @@ class _Query extends \IPS\Content\Search\Query
|
||||
/* And then pass up */
|
||||
return parent::termAsWordsArray( $term, $ignorePhrase, $minLength, $maxLength );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class _Content extends \IPS\Content\Search\Result
|
||||
* @param array $reactions Reaction Data
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating = NULL, $iPostedIn = FALSE, $reactions=array() )
|
||||
public function __construct( array $indexData, array $authorData, array $itemData, ?array $containerData, array $reputationData, $reviewRating = NULL, $iPostedIn = FALSE, $reactions=array() )
|
||||
{
|
||||
$this->createdDate = \IPS\DateTime::ts( $indexData['index_date_created'] );
|
||||
$this->lastUpdatedDate = \IPS\DateTime::ts( $indexData['index_date_updated'] );
|
||||
|
||||
@@ -36,9 +36,6 @@ abstract class _Result
|
||||
with one of the alternative Emoji style images though because that re-introduces images, so we
|
||||
just strip them out (making them behave like emoticons) */
|
||||
|
||||
/* Trim content down to a sensible length for display */
|
||||
$content = mb_substr( $content, 0, 600 );
|
||||
|
||||
if ( \IPS\Settings::i()->emoji_style == 'twemoji' )
|
||||
{
|
||||
return preg_replace( '/(?:' . \IPS\Text\Parser::EMOJI_REGEX . '|\x{200d})+/u', '', $content );
|
||||
|
||||
@@ -29,6 +29,6 @@ class _Email extends \IPS\Content\ShareServices
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'sharelinks', 'core' )->email( urlencode( $this->url ), $this->title );
|
||||
return \IPS\Theme::i()->getTemplate( 'sharelinks', 'core' )->email( rawurlencode( $this->url ), rawurlencode( $this->title ) );
|
||||
}
|
||||
}
|
||||
@@ -23,19 +23,6 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _Facebook extends \IPS\Content\ShareServices
|
||||
{
|
||||
/**
|
||||
* Publish text or a URL to this service
|
||||
* @deprecated 4.3.3: Facebook have removed access to permission this method needs. Retaining method for 3rd party compatibility
|
||||
*
|
||||
* @param string $content Text to publish
|
||||
* @param string $url [URL to publish]
|
||||
* @return void
|
||||
*/
|
||||
public static function publish( $content, $url=null )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any additional form elements to the configuration form. These must be setting keys that the service configuration form can save as a setting.
|
||||
*
|
||||
|
||||
@@ -74,12 +74,13 @@ trait Solvable
|
||||
|
||||
if ( $value )
|
||||
{
|
||||
if ( $this->mapped('solved_comment_id') )
|
||||
if ( $this->$solvedField )
|
||||
{
|
||||
try
|
||||
{
|
||||
$oldComment = $commentClass::load( $this->mapped('solved_comment_id') );
|
||||
$oldComment = $commentClass::load( $this->$solvedField );
|
||||
$oldComment->setSolved( FALSE );
|
||||
$oldComment->save();
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
@@ -95,6 +96,22 @@ trait Solvable
|
||||
'item_id' => $this->$idField,
|
||||
'solved_date' => time()
|
||||
) );
|
||||
|
||||
/* Send the "solution to your topic" notification but only if we didn't post the solution, we're not marking the solution, we can view the content, and the user isn't ignored */
|
||||
if ( $this->author()->member_id AND $comment->author() != $this->author() AND $this->author() != $member AND $this->canView( $this->author() ) AND !$this->author()->isIgnoring( $comment->author(), 'posts' ) )
|
||||
{
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'mine_solved', $this, array( $this, $comment, $member ), array(), TRUE, NULL );
|
||||
$notification->recipients->attach( $this->author() );
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
/* Send the "you solved the topic" notification but only if we didn't mark the solution */
|
||||
if ( $comment->author()->member_id AND $comment->author() != $member )
|
||||
{
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'my_solution', $this, array( $this, $comment, $member ), array(), TRUE, NULL );
|
||||
$notification->recipients->attach( $comment->author() );
|
||||
$notification->send();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -102,6 +119,20 @@ trait Solvable
|
||||
$this->save();
|
||||
|
||||
\IPS\Db::i()->delete( 'core_solved_index', array( 'comment_class=? and comment_id=?', $commentClass, $comment->$commentIdField ) );
|
||||
|
||||
$memberIds = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '`member`', 'core_notifications', array( \IPS\Db::i()->in( 'notification_key', array( 'mine_solved', 'my_solution' ) ) . ' AND item_class=? AND item_id=?', (string) \get_class( $this ), (int) $this->$idField ) ) as $memberToRecount )
|
||||
{
|
||||
$memberIds[ $memberToRecount ] = $memberToRecount;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_notifications', array( \IPS\Db::i()->in( 'notification_key', array( 'mine_solved', 'my_solution' ) ) . ' AND item_class=? AND item_id=?', (string) \get_class( $this ), (int) $this->$idField ) );
|
||||
|
||||
foreach( $memberIds as $memberToRecount )
|
||||
{
|
||||
\IPS\Member::load( $memberToRecount )->recountNotifications();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,4 +231,23 @@ trait Solvable
|
||||
/* Otherwise no */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the solution
|
||||
*
|
||||
* @return \IPS\Content\Comment|NULL
|
||||
*/
|
||||
public function getSolution()
|
||||
{
|
||||
try
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
|
||||
return $commentClass::load( $this->mapped('solved_comment_id') );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
+127
-40
@@ -34,11 +34,7 @@ trait Statistics
|
||||
*/
|
||||
public function topAttachments( $count = 5 ): array
|
||||
{
|
||||
$attachments = $this->_getAllAttachments();
|
||||
|
||||
uasort( $attachments, function ( $a, $b ) {
|
||||
return $a['attach_hits'] < $b['attach_hits'];
|
||||
} );
|
||||
$attachments = $this->_getAllAttachments( array(), $count, 'attach_hits DESC' );
|
||||
|
||||
$attachments = \array_slice( $attachments, 0, $count );
|
||||
|
||||
@@ -54,7 +50,7 @@ trait Statistics
|
||||
*/
|
||||
public function imageAttachments( $count = 10 ): array
|
||||
{
|
||||
$attachments = $this->_getAllAttachments( array( 'attach_is_image=1' ) );
|
||||
$attachments = $this->_getAllAttachments( array( 'attach_is_image=1' ), $count, 'attach_date DESC' );
|
||||
$attachments = \array_slice( $attachments, 0, $count );
|
||||
|
||||
return $attachments;
|
||||
@@ -77,9 +73,7 @@ trait Statistics
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
$commentItemField = $commentClass::$databaseColumnMap['item'];
|
||||
$authorColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'];
|
||||
$idField = static::$databaseColumnId;
|
||||
$cacheKey = 'topPosters_' . $count;
|
||||
|
||||
try
|
||||
@@ -89,11 +83,10 @@ trait Statistics
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$where = $this->_getVisibleWhere();
|
||||
array_push( $where, array( $commentItemField . '=?', $this->$idField ) );
|
||||
|
||||
$members = \IPS\Db::i()->select( "count(*) as sum, {$authorColumn}", $commentClass::$databaseTable, $where, 'sum DESC', array(0, $count), array($commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author']) );
|
||||
$members = iterator_to_array( \IPS\Db::i()->select( "count(*) as sum, {$authorColumn}", $commentClass::$databaseTable, $where, 'sum DESC', array( 0, $count ), array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'] ) ) );
|
||||
|
||||
$this->_storeCached( $cacheKey, iterator_to_array( $members ) );
|
||||
$this->_storeCached( $cacheKey, $members );
|
||||
}
|
||||
|
||||
$contributors = array();
|
||||
@@ -110,7 +103,7 @@ trait Statistics
|
||||
}
|
||||
|
||||
$return = array();
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array(\IPS\Db::i()->in( 'member_id', $contributors )), "FIND_IN_SET( member_id, '" . implode( ",", $contributors ) . "' )" ), 'IPS\Member' ) as $member )
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( \IPS\Db::i()->in( 'member_id', $contributors ) ) ), 'IPS\Member' ) as $member )
|
||||
{
|
||||
$return[] = array( 'member' => $member, 'count' => $counts[ $member->member_id ] );
|
||||
}
|
||||
@@ -121,7 +114,7 @@ trait Statistics
|
||||
/**
|
||||
* Members with most posts
|
||||
*
|
||||
* @param int $count The number of results to return
|
||||
* @param int $count The number of results to return, max 100
|
||||
* @return array
|
||||
* @throw BadMethodCallException
|
||||
* @throws \Exception
|
||||
@@ -129,13 +122,18 @@ trait Statistics
|
||||
public function topReactedPosts( $count = 5 ): array
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
$commentIdField = $commentClass::$databaseColumnId;
|
||||
$commentIdField = $commentClass::$databasePrefix . $commentClass::$databaseColumnId;
|
||||
$idField = static::$databaseColumnId;
|
||||
|
||||
if ( !\IPS\IPS::classUsesTrait( $commentClass, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
if ( $count > 100 )
|
||||
{
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
$cacheKey = 'topReactedPosts_' . $count;
|
||||
|
||||
@@ -145,16 +143,18 @@ trait Statistics
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$where = array('app=? and type=? and item_id=?', $commentClass::$application, $commentClass::reactionType(), $this->$idField);
|
||||
$posts = \IPS\Db::i()->select( "count(*) as sum, type_id", 'core_reputation_index', $where, NULL, NULL, array('type_id') );
|
||||
$where = array( 'app=? and type=? and item_id=?', $commentClass::$application, $commentClass::reactionType(), $this->$idField );
|
||||
$posts = \IPS\Db::i()->select( "count(*) as sum, type_id", 'core_reputation_index', $where, NULL, NULL, array( 'type_id' ) );
|
||||
|
||||
$posts = iterator_to_array( $posts );
|
||||
|
||||
usort($posts, function( $item1, $item2 )
|
||||
usort( $posts, function( $item1, $item2 )
|
||||
{
|
||||
return $item2['sum'] <=> $item1['sum'];
|
||||
} );
|
||||
|
||||
/* Just store the top 100 posts, they are already sorted by highest to lowest */
|
||||
$posts = \array_slice( $posts, 0, 100 );
|
||||
$this->_storeCached( $cacheKey, $posts );
|
||||
}
|
||||
|
||||
@@ -172,9 +172,9 @@ trait Statistics
|
||||
}
|
||||
|
||||
$return = array();
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $commentClass::$databaseTable, array(\IPS\Db::i()->in( $commentClass::$databaseColumnId, $postIds )), "FIND_IN_SET( {$commentClass::$databaseColumnId}, '" . implode( ",", $postIds ) . "' )", array( 0, $count ) ), $commentClass ) as $comment )
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $commentClass::$databaseTable, array( \IPS\Db::i()->in( $commentIdField, $postIds ) ), "FIND_IN_SET( {$commentIdField}, '" . implode( ",", $postIds ) . "' )", array( 0, $count ) ), $commentClass ) as $comment )
|
||||
{
|
||||
if ( $comment->canView() )
|
||||
if ( $comment->canView() and $comment->mapped('item') == $this->$idField )
|
||||
{
|
||||
$return[] = array( 'comment' => $comment, 'count' => $counts[ $comment->$commentIdField ] );
|
||||
}
|
||||
@@ -194,8 +194,7 @@ trait Statistics
|
||||
{
|
||||
$return = array();
|
||||
$commentClass = static::$commentClass;
|
||||
$idField = static::$databaseColumnId;
|
||||
$commentItemField = $commentClass::$databaseColumnMap['item'];
|
||||
$commentIdField = $commentClass::$databasePrefix . $commentClass::$databaseColumnId;
|
||||
$rows = array();
|
||||
$commentIds = array();
|
||||
|
||||
@@ -209,9 +208,8 @@ trait Statistics
|
||||
{
|
||||
$dateColumn = $commentClass::$databasePrefix . ( isset( $commentClass::$databaseColumnMap['updated'] ) ? $commentClass::$databaseColumnMap['updated'] : $commentClass::$databaseColumnMap['date'] );
|
||||
$where = $this->_getVisibleWhere();
|
||||
array_push( $where, array( $commentItemField . '=?', $this->$idField ) );
|
||||
|
||||
$posts = iterator_to_array( \IPS\Db::i()->select( "COUNT(*) AS count, MIN({$commentClass::$databaseColumnId}) as commentId, (DATE_FORMAT( FROM_UNIXTIME( IFNULL( {$dateColumn}, 0 ) ), '%Y-%c-%e' ) ) as time", $commentClass::$databaseTable, $where, 'count desc', array( 0, $count ), array('time') ) );
|
||||
$posts = iterator_to_array( \IPS\Db::i()->select( "COUNT(*) AS count, MIN({$commentIdField}) as commentId, (DATE_FORMAT( FROM_UNIXTIME( IFNULL( {$dateColumn}, 0 ) ), '%Y-%c-%e' ) ) as time", $commentClass::$databaseTable, $where, 'count desc', array( 0, $count ), array( 'time' ) ) );
|
||||
|
||||
$this->_storeCached( $cacheKey, $posts );
|
||||
}
|
||||
@@ -249,21 +247,27 @@ trait Statistics
|
||||
public function clearCachedStatistics()
|
||||
{
|
||||
$idField = static::$databaseColumnId;
|
||||
$cacheKey = $this->$idField . '_' . static::$module . '_activity';
|
||||
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, array(), \IPS\DateTime::create()->add( new \DateInterval('P1M') ), TRUE );
|
||||
\IPS\Db::i()->delete( 'core_item_statistics_cache', array( 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loaded Extensions
|
||||
*/
|
||||
protected static $loadedExtensions = array();
|
||||
|
||||
/**
|
||||
* Get all attachments for this item
|
||||
*
|
||||
* @param array $where Additional where for this
|
||||
* @param array $extraWhere Additional where clause
|
||||
* @param int $limit Number to return/limit to
|
||||
* @param string|NULL $orderBy Order by clause (optional)
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function _getAllAttachments( $extraWhere=NULL )
|
||||
protected function _getAllAttachments( $extraWhere=NULL, $limit=10, $orderBy=NULL )
|
||||
{
|
||||
$idField = static::$databaseColumnId;
|
||||
$cacheKey = 'allAttachments';
|
||||
$cacheKey = 'allAttachments' . md5( json_encode( $extraWhere ) . $limit . (string) $orderBy );
|
||||
$return = array();
|
||||
|
||||
try
|
||||
@@ -272,7 +276,7 @@ trait Statistics
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
$where = array( array('location_key=? and id1=? and id2 IN(?)', static::$application . '_' . mb_ucfirst( static::$module ), $this->$idField, $this->_subQueryVisibleComments() ) );
|
||||
$where = array( array( 'location_key=? and id1=? and id2 IN(?)', static::$application . '_' . mb_ucfirst( static::$module ), $this->$idField, $this->_subQueryVisibleComments( $this->$idField ) ) );
|
||||
|
||||
if ( $extraWhere !== NULL )
|
||||
{
|
||||
@@ -280,7 +284,39 @@ trait Statistics
|
||||
}
|
||||
|
||||
/* Get attachments from all comments */
|
||||
$return = iterator_to_array( \IPS\Db::i()->select( '*', 'core_attachments_map', $where )->join( 'core_attachments', array('attach_id=attachment_id') ) );
|
||||
$return = iterator_to_array( \IPS\Db::i()->select( '*', 'core_attachments_map', $where, $orderBy, $limit )->join( 'core_attachments', array( 'attach_id=attachment_id' ) ) );
|
||||
|
||||
/* Get link to comments */
|
||||
foreach( $return as $k => $map )
|
||||
{
|
||||
/* Get the attachment extension if we don't already have it */
|
||||
if ( !isset( static::$loadedExtensions[ $map['location_key'] ] ) )
|
||||
{
|
||||
$exploded = explode( '_', $map['location_key'] );
|
||||
try
|
||||
{
|
||||
$extensions = \IPS\Application::load( $exploded[0] )->extensions( 'core', 'EditorLocations' );
|
||||
if ( isset( $extensions[ $exploded[1] ] ) )
|
||||
{
|
||||
static::$loadedExtensions[ $map['location_key'] ] = $extensions[ $exploded[1] ];
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
catch ( \UnexpectedValueException $e ) { }
|
||||
}
|
||||
|
||||
if ( isset( static::$loadedExtensions[ $map['location_key'] ] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$url = static::$loadedExtensions[ $map['location_key'] ]->attachmentLookup( $map['id1'], $map['id2'], $map['id3'] );
|
||||
|
||||
$return[ $k ]['commentUrl'] = (string) $url->url();
|
||||
}
|
||||
catch ( \LogicException $e ) { }
|
||||
catch ( \BadMethodCallException $e ){ }
|
||||
}
|
||||
}
|
||||
|
||||
$this->_storeCached( $cacheKey, $return );
|
||||
}
|
||||
@@ -291,12 +327,13 @@ trait Statistics
|
||||
/**
|
||||
* Return a sub query to fetch only visible posts
|
||||
*
|
||||
* @param int $id Content item ID
|
||||
* @return \IPS\Db\Select
|
||||
*/
|
||||
protected function _subQueryVisibleComments()
|
||||
protected function _subQueryVisibleComments( $id )
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
return \IPS\Db::i()->select( $commentClass::$databaseColumnId, $commentClass::$databaseTable, $this->_getVisibleWhere() );
|
||||
return \IPS\Db::i()->select( $commentClass::$databasePrefix . $commentClass::$databaseColumnId, $commentClass::$databaseTable, array_merge( $this->_getVisibleWhere(), array( array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['item'] . '=' . $id ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,18 +344,23 @@ trait Statistics
|
||||
protected function _getVisibleWhere()
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
$idField = static::$databaseColumnId;
|
||||
$commentItemField = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['item'];
|
||||
|
||||
$where = array();
|
||||
if ( isset( $commentClass::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$approvedColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['approved'];
|
||||
$where[] = array("{$approvedColumn} = 1");
|
||||
$where[] = array( "{$approvedColumn} = 1" );
|
||||
}
|
||||
if ( isset( $commentClass::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$hiddenColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['hidden'];
|
||||
$where[] = array("{$hiddenColumn} = 0");
|
||||
$where[] = array( "{$hiddenColumn} = 0" );
|
||||
}
|
||||
|
||||
$where[] = array( $commentItemField . '=?', $this->$idField );
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
@@ -339,9 +381,21 @@ trait Statistics
|
||||
if ( static::$cachedActivity === NULL )
|
||||
{
|
||||
$idField = static::$databaseColumnId;
|
||||
$cacheKey = $this->$idField . '_' . static::$module . '_activity';
|
||||
|
||||
static::$cachedActivity = \IPS\Data\Cache::i()->getWithExpire( $cacheKey, TRUE );
|
||||
|
||||
try
|
||||
{
|
||||
$cache = \IPS\Db::i()->select( '*', 'core_item_statistics_cache', array( 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ) )->first();
|
||||
|
||||
if ( $cache['cache_added'] > time() - 86400 )
|
||||
{
|
||||
static::$cachedActivity = json_decode( $cache['cache_contents'], TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_item_statistics_cache', array( 'cache_class=? and cache_item_id=?', \get_class( $this ), $this->$idField ) );
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
|
||||
if ( static::$cachedActivity !== NULL and isset( static::$cachedActivity[ $key ] ) )
|
||||
@@ -350,10 +404,21 @@ trait Statistics
|
||||
}
|
||||
else
|
||||
{
|
||||
if( static::$cachedActivity === NULL )
|
||||
{
|
||||
static::$cachedActivity = array();
|
||||
}
|
||||
|
||||
static::$cachedActivity[ $key ] = array();
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Should we store the data in the cache?
|
||||
*/
|
||||
protected $storeCache = NULL;
|
||||
|
||||
/**
|
||||
* Set cached data
|
||||
*
|
||||
@@ -370,10 +435,32 @@ trait Statistics
|
||||
catch( \Exception $e ) { }
|
||||
|
||||
$idField = static::$databaseColumnId;
|
||||
$cacheKey = $this->$idField . '_' . static::$module . '_activity';
|
||||
|
||||
|
||||
static::$cachedActivity[ $key ] = $value;
|
||||
|
||||
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, static::$cachedActivity, \IPS\DateTime::create()->add( new \DateInterval('P1D') ), TRUE );
|
||||
$this->storeCache = $this->$idField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the cache during destruction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if( $this->storeCache )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_item_statistics_cache', array(
|
||||
'cache_class' => \get_class( $this ),
|
||||
'cache_item_id' => $this->storeCache,
|
||||
'cache_contents' => json_encode( static::$cachedActivity ),
|
||||
'cache_added' => time()
|
||||
), TRUE );
|
||||
}
|
||||
|
||||
if( \is_callable( 'parent::__destruct' ) )
|
||||
{
|
||||
parent::__destruct();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ abstract class _Widget extends \IPS\Widget\PermissionCache
|
||||
/* Date restrict */
|
||||
$options = array( 'unlimited' => -1 );
|
||||
|
||||
if ( $class::databaseTableCount() AND $class::databaseTableCount() > \IPS\UPGRADE_LARGE_TABLE_SIZE )
|
||||
if ( $class::databaseTableCount( TRUE ) > \IPS\UPGRADE_LARGE_TABLE_SIZE )
|
||||
{
|
||||
$options['unlimitedLang'] = 'search_year';
|
||||
}
|
||||
@@ -401,7 +401,7 @@ abstract class _Widget extends \IPS\Widget\PermissionCache
|
||||
}
|
||||
|
||||
/* Limit to days */
|
||||
if ( $class::databaseTableCount() > \IPS\UPGRADE_LARGE_TABLE_SIZE )
|
||||
if ( $class::databaseTableCount( TRUE ) > \IPS\UPGRADE_LARGE_TABLE_SIZE )
|
||||
{
|
||||
if ( isset( $this->configuration['widget_feed_restrict_days'] ) and $this->configuration['widget_feed_restrict_days'] > 0 and $this->configuration['widget_feed_restrict_days'] <= 365 )
|
||||
{
|
||||
|
||||
@@ -213,7 +213,7 @@ abstract class _WidgetComment extends \IPS\Widget\PermissionCache
|
||||
{
|
||||
$return['date_restrict'] = new \IPS\Helpers\Form\Select( 'widget_feed_comment_date', isset( $this->configuration['widget_feed_comment_date'] ) ? (int) $this->configuration['widget_feed_comment_date'] : 0, FALSE, array(
|
||||
'options' => array(
|
||||
0 => $class::databaseTableCount() > \IPS\UPGRADE_LARGE_TABLE_SIZE ? 'search_year' : 'show_all',
|
||||
0 => $class::databaseTableCount( TRUE ) > \IPS\UPGRADE_LARGE_TABLE_SIZE ? 'search_year' : 'show_all',
|
||||
1 => 'today',
|
||||
5 => 'last_5_days',
|
||||
7 => 'last_7_days',
|
||||
@@ -411,7 +411,7 @@ abstract class _WidgetComment extends \IPS\Widget\PermissionCache
|
||||
{
|
||||
$where[] = array( $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnMap['date'] . '>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $this->configuration['widget_feed_comment_date'] . 'D' ) )->getTimestamp() );
|
||||
}
|
||||
else if ( $class::databaseTableCount() > \IPS\UPGRADE_LARGE_TABLE_SIZE )
|
||||
else if ( $class::databaseTableCount( TRUE ) > \IPS\UPGRADE_LARGE_TABLE_SIZE )
|
||||
{
|
||||
$where[] = array( $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnMap['date'] . '>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P1Y' ) )->getTimestamp() );
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user