Version 4.2.0
This commit is contained in:
1 parent
0dc2aee5ed
commit
96997ddd8e
2074 files changed
+125454
-55780
No files matched your search
+212
-45
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Content Comment Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @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 8 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\Content;
|
||||
@@ -168,37 +167,13 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if profanity filters should mod-queue this comment */
|
||||
$obj->checkProfanityFilters( $first );
|
||||
|
||||
/* Save the comment */
|
||||
$obj->save();
|
||||
|
||||
/* Pass this through our profanity filters to see if it needs to be mod queued */
|
||||
try
|
||||
{
|
||||
$hiddenByFilter = FALSE;
|
||||
if ( !$obj->hidden() AND ( ! $item::$firstCommentRequired or ( $item::$firstCommentRequired and !$obj->isFirst() ) ) AND !$member->group['g_bypass_badwords'] )
|
||||
{
|
||||
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $comment );
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) { }
|
||||
|
||||
if ( $hiddenByFilter === TRUE )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
/* 'approved' is easy, clear and concise */
|
||||
$column = static::$databaseColumnMap['approved'];
|
||||
$obj->$column = 0;
|
||||
}
|
||||
else if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
/* 'hidden' is backwards */
|
||||
$column = static::$databaseColumnMap['hidden'];
|
||||
$obj->$column = 1;
|
||||
}
|
||||
|
||||
$obj->save();
|
||||
}
|
||||
|
||||
/* Increment post count */
|
||||
try
|
||||
{
|
||||
@@ -271,6 +246,81 @@ abstract class _Comment extends \IPS\Content
|
||||
/* Return */
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check comment against profanity filters
|
||||
*
|
||||
* @note We do not save here, as saving is done in user-land code after
|
||||
* @param bool $first Is this the first comment?
|
||||
* @param bool $edit Are we editing or merging (true) or is this a new comment (false)?
|
||||
* @return bool Whether to send unapproved notifications
|
||||
*/
|
||||
protected function checkProfanityFilters( $first=FALSE, $edit=TRUE )
|
||||
{
|
||||
/* We need our item */
|
||||
$item = $this->item();
|
||||
|
||||
/* And the author */
|
||||
$member = $this->author();
|
||||
|
||||
/* Pass this through our profanity filters to see if it needs to be mod queued */
|
||||
$sendNotifications = FALSE;
|
||||
|
||||
try
|
||||
{
|
||||
$hiddenByFilter = FALSE;
|
||||
if ( !$this->hidden() AND ( ! $item::$firstCommentRequired or ( $item::$firstCommentRequired and !$first ) ) AND !$member->group['g_bypass_badwords'] )
|
||||
{
|
||||
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $this->content() );
|
||||
}
|
||||
/* 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( $this->content() );
|
||||
|
||||
if ( isset( $item::$databaseColumnMap['approved'] ) and $itemHiddenByFilter )
|
||||
{
|
||||
/* 'approved' is easy, clear and concise */
|
||||
$column = $item::$databaseColumnMap['approved'];
|
||||
$item->$column = 0;
|
||||
$item->save();
|
||||
}
|
||||
elseif ( isset( $item::$databaseColumnMap['hidden'] ) and $itemHiddenByFilter )
|
||||
{
|
||||
/* 'hidden' is backwards */
|
||||
$column = $item::$databaseColumnMap['hidden'];
|
||||
$item->$column = 1;
|
||||
$item->save();
|
||||
}
|
||||
|
||||
if( $edit === TRUE )
|
||||
{
|
||||
$sendNotifications = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) { }
|
||||
|
||||
if ( $hiddenByFilter === TRUE )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
/* 'approved' is easy, clear and concise */
|
||||
$column = static::$databaseColumnMap['approved'];
|
||||
$this->$column = 0;
|
||||
}
|
||||
else if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
/* 'hidden' is backwards */
|
||||
$column = static::$databaseColumnMap['hidden'];
|
||||
$this->$column = 1;
|
||||
}
|
||||
|
||||
$sendNotifications = TRUE;
|
||||
}
|
||||
|
||||
return $sendNotifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join profile fields when loading comments?
|
||||
@@ -378,6 +428,9 @@ abstract class _Comment extends \IPS\Content
|
||||
$item->container()->save();
|
||||
}
|
||||
}
|
||||
|
||||
/* Are we tracking keywords? */
|
||||
$this->checkKeywords( $this->content() );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -482,7 +535,7 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
|
||||
/* Can the member edit their own content? */
|
||||
if ( $member->member_id == $this->author()->member_id and $member->group['g_edit_posts'] and ( !( $item instanceof \IPS\Content\Lockable ) or !$item->locked() ) )
|
||||
if ( $member->member_id == $this->author()->member_id and ( $member->group['g_edit_posts'] == '1' or in_array( get_class( $item ), explode( ',', $member->group['g_edit_posts'] ) ) ) and ( !( $item instanceof \IPS\Content\Lockable ) or !$item->locked() ) )
|
||||
{
|
||||
if ( !$member->group['g_edit_cutoff'] )
|
||||
{
|
||||
@@ -518,7 +571,7 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
catch ( \BadMethodCallException $e ) { }
|
||||
|
||||
return ( !$this->isFirst() and ( static::modPermission( 'hide', $member, $container ) or ( $member->member_id and $member->member_id == $this->author()->member_id and $member->group['gbw_soft_delete_own'] ) ) );
|
||||
return ( !$this->isFirst() and ( static::modPermission( 'hide', $member, $container ) or ( $member->member_id and $member->member_id == $this->author()->member_id and ( $member->group['g_hide_own_posts'] == '1' or in_array( get_class( $this->item() ), explode( ',', $member->group['g_hide_own_posts'] ) ) ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,7 +618,7 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
catch ( \BadMethodCallException $e ) { }
|
||||
|
||||
return ( !$this->isFirst() and ( static::modPermission( 'delete', $member, $container ) or ( $member->member_id and $member->member_id == $this->author()->member_id and $member->group['g_delete_own_posts'] ) ) );
|
||||
return ( !$this->isFirst() and ( static::modPermission( 'delete', $member, $container ) or ( $member->member_id and $member->member_id == $this->author()->member_id and ( $member->group['g_delete_own_posts'] == '1' or in_array( get_class( $this->item() ), explode( ',', $member->group['g_delete_own_posts'] ) ) ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -596,6 +649,28 @@ abstract class _Comment extends \IPS\Content
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can report?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return bool
|
||||
*/
|
||||
public function canReport( $member=NULL )
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\ReportCenter ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( $this->hidden() === 1 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return ( $member->group['g_can_report'] == '1' or in_array( get_class( $this->item() ), explode( ',', $member->group['g_can_report'] ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Index Permissions
|
||||
*
|
||||
@@ -624,6 +699,11 @@ abstract class _Comment extends \IPS\Content
|
||||
*/
|
||||
public function isIgnored( $member=NULL )
|
||||
{
|
||||
if ( !\IPS\Settings::i()->ignore_system_on )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( $member === NULL )
|
||||
{
|
||||
$member = \IPS\Member::loggedIn();
|
||||
@@ -661,16 +741,46 @@ abstract class _Comment extends \IPS\Content
|
||||
$valueField = static::$databaseColumnMap['content'];
|
||||
$oldValue = $this->$valueField;
|
||||
$this->$valueField = $newContent;
|
||||
|
||||
$isHiddenNow = $this->hidden();
|
||||
|
||||
/* Check if profanity filters should mod-queue this comment */
|
||||
$sendNotifications = $this->checkProfanityFilters( $this->isFirst(), TRUE );
|
||||
|
||||
$this->save();
|
||||
|
||||
/* Send any new mention/quote notifications */
|
||||
$this->sendAfterEditNotifications( $oldValue );
|
||||
|
||||
/* Resync the item - necessary as profanity filters may have just hidden an otherwise approved post */
|
||||
$item = $this->item();
|
||||
if( $isHiddenNow != $this->hidden() )
|
||||
{
|
||||
$item->resyncCommentCounts();
|
||||
$item->resyncLastComment();
|
||||
$item->save();
|
||||
}
|
||||
|
||||
if ( $container = $item->containerWrapper() )
|
||||
{
|
||||
$container->resetCommentCounts();
|
||||
$container->save();
|
||||
}
|
||||
|
||||
/* Reindex */
|
||||
if ( $this instanceof \IPS\Content\Searchable )
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->index( $this );
|
||||
}
|
||||
|
||||
/* Send notifications */
|
||||
if ( $sendNotifications AND !in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
|
||||
{
|
||||
if( $this->hidden() === 1 )
|
||||
{
|
||||
$this->sendUnapprovedNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -852,10 +962,11 @@ abstract class _Comment extends \IPS\Content
|
||||
/**
|
||||
* Move Comment to another item
|
||||
*
|
||||
* @param \IPS\Content\Item $item The item to move this comment too.
|
||||
* @param \IPS\Content\Item $item The item to move this comment to
|
||||
* @param bool $skip Skip rebuilding new/old content item data (used for multimod where we can do it in one go after)
|
||||
* @return void
|
||||
*/
|
||||
public function move( \IPS\Content\Item $item )
|
||||
public function move( \IPS\Content\Item $item, $skip=FALSE )
|
||||
{
|
||||
$oldItem = $this->item();
|
||||
|
||||
@@ -872,13 +983,16 @@ abstract class _Comment extends \IPS\Content
|
||||
\IPS\Db::i()->update( 'core_notifications', array( 'item_id' => $item->$idColumn ), array( 'item_class=? and item_id=? and item_sub_class=? and item_sub_id=?', (string) get_class( $item ), $oldItem->$idColumn, (string) get_called_class(), $this->$commentIdColumn ) );
|
||||
|
||||
/* Update reputation */
|
||||
if ( $this instanceof \IPS\Content\Reputation )
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_reputation_index', array( 'item_id' => $item->$idColumn ), array( 'class_type_id_hash=?', md5( get_class( $this ) . ':' . $oldItem->$idColumn ) ) );
|
||||
}
|
||||
|
||||
$oldItem->rebuildFirstAndLastCommentData();
|
||||
$item->rebuildFirstAndLastCommentData();
|
||||
if( $skip === FALSE )
|
||||
{
|
||||
$oldItem->rebuildFirstAndLastCommentData();
|
||||
$item->rebuildFirstAndLastCommentData();
|
||||
}
|
||||
|
||||
/* Add to search index */
|
||||
if ( $this instanceof \IPS\Content\Searchable )
|
||||
@@ -937,13 +1051,19 @@ abstract class _Comment extends \IPS\Content
|
||||
$item = NULL;
|
||||
$itemId = $this->mapped('item');
|
||||
}
|
||||
|
||||
/* Remove featured comment associations */
|
||||
if( $this->isFeatured() AND $item )
|
||||
{
|
||||
\IPS\Application::load('core')->extensions( 'core', 'MetaData' )['FeaturedComments']->unfeatureComment( $item, $this );
|
||||
}
|
||||
|
||||
/* Unclaim attachments */
|
||||
\IPS\File::unclaimAttachments( $itemClass::$application . '_' . ucfirst( $itemClass::$module ), $itemId, $this->$idColumn );
|
||||
|
||||
/* Reduce the number of comment/reviews count on the item but only if the item is unapproved or visible
|
||||
* - hidden as opposed to unapproved items do not get included in either of the unapproved_comments/num_comments columns */
|
||||
if( $this->hidden() !== -1 )
|
||||
if( $this->hidden() !== -1 AND $this->hidden() !== -2 )
|
||||
{
|
||||
$columnName = ( $this->hidden() === 1 ) ? 'unapproved_comments' : 'num_comments';
|
||||
if ( in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
|
||||
@@ -1005,7 +1125,7 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
\IPS\Member::load( $member )->recountNotifications();
|
||||
}
|
||||
|
||||
|
||||
/* Actually delete */
|
||||
parent::delete();
|
||||
|
||||
@@ -1031,7 +1151,7 @@ abstract class _Comment extends \IPS\Content
|
||||
{
|
||||
if ( $item->container()->_comments !== NULL )
|
||||
{
|
||||
if ( !$this->hidden() )
|
||||
if ( !$this->hidden() AND $this->hidden() !== -2 )
|
||||
{
|
||||
$item->container()->_comments = ( $item->container()->_comments > 0 ) ? ( $item->container()->_comments - 1 ) : 0;
|
||||
}
|
||||
@@ -1257,6 +1377,18 @@ abstract class _Comment extends \IPS\Content
|
||||
}
|
||||
}
|
||||
|
||||
/* No matter if we can or cannot view hidden items, we do not want these to show as they are queued for deletion */
|
||||
if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$col = static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['hidden'];
|
||||
$where[] = array( "{$col}!=-2" );
|
||||
}
|
||||
else if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$col = static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnMap['approved'];
|
||||
$where[] = array( "{$col}!=-2" );
|
||||
}
|
||||
|
||||
if ( $joinContainer AND isset( $itemClass::$containerNodeClass ) )
|
||||
{
|
||||
$containerClass = $itemClass::$containerNodeClass;
|
||||
@@ -1368,6 +1500,30 @@ abstract class _Comment extends \IPS\Content
|
||||
return array( $this->item()->$idColumn, $this->$commentIdColumn );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content images
|
||||
*
|
||||
* @param int|null $limit Number of attachments to fetch, or NULL for all
|
||||
*
|
||||
* @return array|NULL
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function contentImages( $limit = NULL )
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$item = $this->item();
|
||||
$attachments = array();
|
||||
$itemIdColumn = $item::$databaseColumnId;
|
||||
$internal = \IPS\Db::i()->select( 'attachment_id', 'core_attachments_map', array( 'location_key=? and id1=? and id2=?', $item::$application . '_' . ucfirst( $item::$module ), $item->$itemIdColumn, $this->$idColumn ) );
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_attachments', array( array( 'attach_id IN(?)', $internal ), array( 'attach_is_image=1' ) ), 'attach_id ASC', $limit ) as $row )
|
||||
{
|
||||
$attachments[] = array( 'core_Attachment' => $row['attach_location'] );
|
||||
}
|
||||
|
||||
return count( $attachments ) ? $attachments : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Existing warning
|
||||
*/
|
||||
@@ -1414,6 +1570,17 @@ abstract class _Comment extends \IPS\Content
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a featured comment?
|
||||
*
|
||||
* @return bool
|
||||
* @note This is a wrapper for the extension so content items can extend and apply their own logic
|
||||
*/
|
||||
public function isFeatured()
|
||||
{
|
||||
return \IPS\Application::load('core')->extensions( 'core', 'MetaData' )['FeaturedComments']->isFeatured( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user