Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+249 -128
View File
@@ -2,9 +2,9 @@
/**
* @brief Abstract Content Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 3 Oct 2013
* @version SVN_VERSION_NUMBER
*/
@@ -98,22 +98,28 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
{
if ( isset( $data[ static::$databaseTable ] ) and is_array( $data[ static::$databaseTable ] ) )
{
/* Add author data to multiton storeto prevent ->author() running another query later */
{
/* Add author data to multiton store to prevent ->author() running another query later */
if ( isset( $data['author'] ) and is_array( $data['author'] ) )
{
$author = \IPS\Member::constructFromData( $data['author'], FALSE );
if ( isset( $data['author_pfields'] ) )
{
unset( $data['author_pfields']['member_id'] );
$author->contentProfileFields();
}
}
/* Load content */
$obj = parent::constructFromData( $data[ static::$databaseTable ], $updateMultitonStoreIfExists );
/* Add reputation if it was passed*/
if ( isset( $data['core_reputation_index'] ) and is_array( $data['core_reputation_index'] ) )
{
$obj->_data = array_merge( $obj->_data, $data['core_reputation_index'] );
}
/* Return */
return $obj;
}
@@ -248,8 +254,8 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
*/
public function truncated( $oneLine=FALSE )
{
/* Specifically remove quotes, and any scripts (which someone with HTML posting allowed may have legitimately enabled */
$text = \IPS\Text\Parser::removeElements( $this->content(), array( 'blockquote', 'script' ) );
/* Specifically remove quotes, any scripts (which someone with HTML posting allowed may have legitimately enabled, and spoilers (to prevent contents from being revealed) */
$text = \IPS\Text\Parser::removeElements( $this->content(), array( 'blockquote', 'script', 'div[class=ipsSpoiler]' ) );
/* Convert headers and paragraphs into line breaks or just spaces */
$text = str_replace( array( '</p>', '</h1>', '</h2>', '</h3>', '</h4>', '</h5>', '</h6>' ), ( $oneLine ? ' ' : '<br>' ), $text );
@@ -261,7 +267,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$text = strip_tags( $text, '<br>' );
/* Remove any <br>s from the start so there isn't just blank space at the top, but maintaining <br>s elsewhere */
$text = preg_replace( '/^[(\s)(<br>)\x{00a0}]*/u', '', $text );
$text = preg_replace( '/^(\s|<br>|' . chr(0xC2) . chr(0xA0) . ')+?/', '', $text );
/* Return */
return $text;
@@ -376,7 +382,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
*/
public static function canSeeMultiModTools( \IPS\Member $member = NULL, \IPS\Node\Model $container = NULL )
{
return static::modPermission( 'edit', $member, $container ) or static::modPermission( 'hide', $member, $container ) or static::modPermission( 'unhide', $member, $container ) or static::modPermission( 'delete', $member, $container );
return static::modPermission( 'pin', $member, $container ) or static::modPermission( 'unpin', $member, $container ) or static::modPermission( 'feature', $member, $container ) or static::modPermission( 'unfeature', $member, $container ) or static::modPermission( 'edit', $member, $container ) or static::modPermission( 'hide', $member, $container ) or static::modPermission( 'unhide', $member, $container ) or static::modPermission( 'delete', $member, $container );
}
/**
@@ -558,11 +564,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
/**
* Hide
*
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
* @param string $reason Reason
* @param \IPS\Member|NULL|FALSE $member The member doing the action (NULL for currently logged in member, FALSE for no member)
* @param string $reason Reason
* @return void
*/
public function hide( \IPS\Member $member = NULL, $reason = NULL )
public function hide( $member, $reason = NULL )
{
if ( isset( static::$databaseColumnMap['hidden'] ) )
{
@@ -585,7 +591,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$this->$column = -1;
$this->save();
$this->onHide();
$this->onHide( $member );
if ( static::$hideLogKey )
{
@@ -594,7 +600,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
\IPS\Db::i()->insert( 'core_soft_delete_log', array(
'sdl_obj_id' => $this->$idColumn,
'sdl_obj_key' => static::$hideLogKey,
'sdl_obj_member_id' => intval( $member ? $member->member_id : \IPS\Member::loggedIn()->member_id ),
'sdl_obj_member_id' => $member === FALSE ? 0 : intval( $member ? $member->member_id : \IPS\Member::loggedIn()->member_id ),
'sdl_obj_date' => time(),
'sdl_obj_reason' => $reason,
@@ -618,17 +624,17 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
/**
* Unhide
*
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
* @param \IPS\Member|NULL|FALSE $member The member doing the action (NULL for currently logged in member, FALSE for no member)
* @return void
*/
public function unhide( $member=NULL )
public function unhide( $member )
{
/* If we're approving, we have to do extra stuff */
$approving = FALSE;
if ( $this->hidden() === 1 )
{
$approving = TRUE;
if ( isset( static::$databaseColumnMap['approved_by'] ) )
if ( isset( static::$databaseColumnMap['approved_by'] ) and $member !== FALSE )
{
$column = static::$databaseColumnMap['approved_by'];
$this->$column = $member ? $member->member_id : \IPS\Member::loggedIn()->member_id;
@@ -639,8 +645,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$this->$column = time();
}
}
/* Now do the actual stuff */
if ( isset( static::$databaseColumnMap['hidden'] ) )
{
@@ -671,7 +676,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
throw new \RuntimeException;
}
$this->save();
$this->onUnhide( $approving );
$this->onUnhide( $approving, $member );
/* And update the tags perm cache */
if ( $this instanceof \IPS\Content\Tags )
@@ -690,10 +695,9 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
{
$this->sendApprovedNotification();
}
}
/**
* Send
$this->expireWidgetCaches();
}
/**
* Blurb for when/why/by whom this content was hidden
@@ -783,6 +787,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
try
{
$index = \IPS\core\Reports\Report::load( $this->$idColumn, 'content_id', array( 'class=?', get_called_class() ) );
$index->num_reports = $index->num_reports + 1;
}
catch ( \OutOfRangeException $e )
{
@@ -792,10 +797,18 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$index->perm_id = $this->permId();
$index->first_report_by = (int) \IPS\Member::loggedIn()->member_id;
$index->first_report_date = time();
$index->last_updated = time();
$index->author = (int) $this->author()->member_id;
$index->num_reports = 1;
$index->num_comments = 0;
}
/* Only set this to a new report if it is not already under review */
if( $index->status != 2 )
{
$index->status = 1;
}
$index->status = 1;
$index->save();
/* Create a report */
@@ -809,10 +822,6 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
\IPS\Db::i()->insert( 'core_rc_reports', $reportInsert );
/* Rebuild */
$index->rebuild();
/* Send notification to mods */
$moderators = array( 'm' => array(), 'g' => array() );
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
@@ -869,14 +878,15 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
break;
case 'author_name':
$this->$col = $newAuthor->member_id ? $newAuthor->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;
}
}
}
$this->save();
if ( \IPS\Dispatcher::hasInstance() )
if ( \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation == 'front' )
{
\IPS\Session::i()->modLog( 'modlog__action_changeauthor', 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() );
}
@@ -888,15 +898,17 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param bool $iPostedIn If the user has posted in the item
* @param string $view 'expanded' or 'condensed'
* @param bool $asItem Displaying results as items?
* @param bool $canIgnoreComments Can ignore comments in the result stream? Activity stream can, but search results cannot.
* @param array $template Optional custom template
* @return string
*/
public static function searchResult( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem )
public static function searchResult( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments=FALSE, $template=NULL )
{
/* Item details */
$itemClass = $indexData['index_class'];
@@ -913,6 +925,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
/* Object URL */
$indefiniteArticle = static::_indefiniteArticle( $containerData );
$definiteArticle = static::_definiteArticle( $containerData );
if ( in_array( 'IPS\Content\Comment', class_parents( get_called_class() ) ) )
{
if ( in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
@@ -927,22 +940,23 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
}
$indefiniteArticle = $itemClass::_indefiniteArticle( $containerData );
$definiteArticle = $itemClass::_definiteArticle( $containerData );
}
else
{
$objectUrl = $itemUrl;
$showRepUrl = $itemUrl->setQueryString( 'do', 'showRep' );
}
$articles = array( 'indefinite' => $indefiniteArticle, 'definite' => \IPS\Member::loggedIn()->language()->addToStack( $itemClass::$title, FALSE, array( 'strtolower' => TRUE ) ) );
$articles = array( 'indefinite' => $indefiniteArticle, 'definite' => $definiteArticle );
/* Container details */
$containerUrl = NULL;
$containerTitle = NULL;
if ( isset( $itemClass::$containerNodeClass ) )
{
$containerClass = $itemClass::$containerNodeClass;
$containerTitle = \IPS\Member::loggedIn()->language()->addToStack( $containerClass::$titleLangPrefix . $indexData['index_container_id'] );
$containerUrl = $containerClass::urlFromIndexData( $indexData, $itemData, $containerData );
$containerClass = $itemClass::$containerNodeClass;
$containerTitle = $containerClass::titleFromIndexData( $indexData, $itemData, $containerData );
$containerUrl = $containerClass::urlFromIndexData( $indexData, $itemData, $containerData );
}
/* Reputation */
@@ -950,9 +964,14 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
/* Snippet */
$snippet = static::searchResultSnippet( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $view );
/* Return */
return \IPS\Theme::i()->getTemplate( 'system', 'core', 'front' )->searchResult( $indexData, $articles, $authorData, $itemData, $unread, $asItem ? $itemUrl : $objectUrl, $itemUrl, $containerUrl, $containerTitle, $repCount, $showRepUrl, $snippet, $iPostedIn, $view );
if ( $template === NULL )
{
$template = array( \IPS\Theme::i()->getTemplate( 'system', 'core', 'front' ), 'searchResult' );
}
/* Return */
return call_user_func_array( $template, array( $indexData, $articles, $authorData, $itemData, $unread, $asItem ? $itemUrl : $objectUrl, $itemUrl, $containerUrl, $containerTitle, $repCount, $showRepUrl, $snippet, $iPostedIn, $view, $canIgnoreComments ) );
}
/**
@@ -961,7 +980,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
@@ -1138,7 +1157,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$idColumn = static::$databaseColumnId;
\IPS\Db::i()->delete( 'core_reputation_index', array( 'app=? AND type=? AND member_id=? AND type_id=?', static::$application, static::$reputationType, $member->member_id, $this->$idColumn ) );
if ( $this->repGiven( $member ) )
{
if ( $this->reputation !== NULL )
@@ -1148,7 +1167,6 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
}
else
{
$limit = ( $type === 1 ) ? $member->group['g_rep_max_positive'] : $member->group['g_rep_max_negative'];
if ( $limit !== 999 )
@@ -1161,13 +1179,16 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
}
\IPS\Db::i()->insert( 'core_reputation_index', array(
'member_id' => $member->member_id,
'app' => static::$application,
'type' => static::$reputationType,
'type_id' => $this->$idColumn,
'rep_date' => time(),
'rep_rating' => $type,
'member_received' => (int) $this->author()->member_id
'member_id' => $member->member_id,
'app' => static::$application,
'type' => static::$reputationType,
'type_id' => $this->$idColumn,
'rep_date' => time(),
'rep_rating' => $type,
'member_received' => (int) $this->author()->member_id,
'class_type_id_hash' => md5( get_class( $this ) . ':' . $this->$idColumn ),
'rep_class' => get_class( $this ),
'item_id' => (int) $this->mapped('item')
) );
/* Send Notification */
@@ -1275,59 +1296,84 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
*/
public function likeBlurb()
{
if( $this->likeBlurb !== NULL )
if( $this->likeBlurb === NULL )
{
return $this->likeBlurb;
}
$reputation = $this->reputation();
$people = array();
/* Nobody */
if ( !$reputation )
{
return '';
}
/* You */
if ( $this->repGiven() === 1 )
{
$reputation--;
if ( $reputation )
/* Did anyone like it? */
$numberOfLikes = $this->reputation(); # int
if ( $numberOfLikes )
{
$people[] = \IPS\Member::loggedIn()->language()->addToStack('like_blurb_you_and_others');
/* Is it just us? */
$userLiked = ( $this->repGiven() === 1 );
if ( $userLiked and $numberOfLikes < 2 )
{
$this->likeBlurb = \IPS\Member::loggedIn()->language()->addToStack('like_blurb_just_you');
}
/* Nope, we need to display a number... */
else
{
$peopleToDisplayInMainView = array();
$andXOthers = $numberOfLikes;
/* If the user liked, we always show "You" first */
if ( $userLiked )
{
$peopleToDisplayInMainView[] = \IPS\Member::loggedIn()->language()->addToStack('like_blurb_you_and_others');
$andXOthers--;
}
/* If we have permission to see who the others are, we need to do that... */
if ( \IPS\Member::loggedIn()->group['gbw_view_reps'] )
{
$peopleToDisplayInSecondaryView = array();
/* Some random names */
$idColumn = static::$databaseColumnId;
$i = 0;
$peopleToDisplayInSecondaryView = array();
foreach ( \IPS\Db::i()->select( '*', 'core_reputation_index', array( 'app=? AND type=? AND type_id=? AND member_id!=? AND rep_rating=?', static::$application, static::$reputationType, $this->$idColumn, ( \IPS\Member::loggedIn()->member_id ) ?: 0, 1 ), 'RAND()', $userLiked ? 17 : 18 ) as $rep )
{
if ( $i < ( $userLiked ? 2 : 3 ) )
{
$peopleToDisplayInMainView[] = \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $rep['member_id'] ) );
$andXOthers--;
}
else
{
$peopleToDisplayInSecondaryView[] = htmlspecialchars( \IPS\Member::load( $rep['member_id'] )->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
$i++;
}
/* If there's people to display in the secondary view, add that */
if ( $peopleToDisplayInSecondaryView )
{
if ( count( $peopleToDisplayInSecondaryView ) < $andXOthers )
{
$peopleToDisplayInSecondaryView[] = \IPS\Member::loggedIn()->language()->addToStack( 'like_blurb_others_secondary', FALSE, array( 'pluralize' => array( $andXOthers - count( $peopleToDisplayInSecondaryView ) ) ) );
}
$peopleToDisplayInMainView[] = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->reputationOthers( $this->url( 'showRep' ), \IPS\Member::loggedIn()->language()->addToStack( 'like_blurb_others', FALSE, array( 'pluralize' => array( $andXOthers ) ) ), json_encode( $peopleToDisplayInSecondaryView ) );
}
}
/* Otherwise the "and X others" will just be static */
else
{
$peopleToDisplayInMainView[] = \IPS\Member::loggedIn()->language()->addToStack( empty( $peopleToDisplayInMainView ) ? 'like_blurb_generic' : 'like_blurb_others', FALSE, array( 'pluralize' => array( $andXOthers ) ) );
}
/* Put it all together */
$this->likeBlurb = \IPS\Member::loggedIn()->language()->addToStack( 'like_blurb', FALSE, array( 'pluralize' => array( $numberOfLikes ), 'htmlsprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $peopleToDisplayInMainView ) ) ) );
}
}
/* Nobody liked it - show nothing */
else
{
$this->likeBlurb = \IPS\Member::loggedIn()->language()->addToStack('like_blurb_just_you');
return $this->likeBlurb;
$this->likeBlurb = '';
}
}
if( \IPS\Member::loggedIn()->group['gbw_view_reps'] )
{
/* 3 random names */
$idColumn = static::$databaseColumnId;
foreach ( \IPS\Db::i()->select( '*', 'core_reputation_index', array( 'app=? AND type=? AND type_id=? AND member_id!=? AND rep_rating=?', static::$application, static::$reputationType, $this->$idColumn, ( \IPS\Member::loggedIn()->member_id ) ?: 0, 1 ), 'RAND()', 3 ) as $rep )
{
$people[] = \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $rep['member_id'] ) );
$reputation--;
}
}
/* X others */
$count = count( $people ) + $reputation;
if ( $reputation )
{
$others = \IPS\Member::loggedIn()->language()->addToStack( empty( $people ) ? 'like_blurb_generic' : 'like_blurb_others', FALSE, array( 'pluralize' => array( $reputation ) ) );
if ( \IPS\Member::loggedIn()->group['gbw_view_reps'] )
{
$others = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->reputationOthers( $this, $others );
}
$people[] = $others;
}
$this->likeBlurb = \IPS\Member::loggedIn()->language()->addToStack( 'like_blurb', FALSE, array( 'pluralize' => array( $count ), 'htmlsprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $people ) ) ) );
return $this->likeBlurb;
}
@@ -1405,7 +1451,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$idColumn = $this::$databaseColumnId;
try
{
$count = $this->notificationRecipients()->count( TRUE );
$count = $this->notificationRecipients( NULL, NULL, TRUE );
}
catch ( \BadMethodCallException $e )
{
@@ -1415,7 +1461,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
/* Queue if there's lots, or just send them */
if ( $count > static::NOTIFICATIONS_PER_BATCH )
{
\IPS\Task::queue( 'core', 'Follow', array( 'class' => get_class( $this ), 'item' => $this->$idColumn, 'exclude' => array_keys( $sentTo ) ), 1 );
\IPS\Task::queue( 'core', 'Follow', array( 'class' => get_class( $this ), 'item' => $this->$idColumn, 'sentTo' => $sentTo ), 1 );
}
else
{
@@ -1427,11 +1473,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
* Send notifications batch
*
* @param int $offset Current offset
* @param array $exclude IDs to exclude
* @param array $sentTo Members who have already received a notification and how - e.g. array( 1 => array( 'inline', 'email' )
* @param string|NULL $extra Additional data
* @return int|null New offset or NULL if complete
*/
public function sendNotificationsBatch( $offset=0, $exclude=array(), $extra=NULL )
public function sendNotificationsBatch( $offset=0, &$sentTo=array(), $extra=NULL )
{
$followIds = array();
$followers = $this->notificationRecipients( array( $offset, static::NOTIFICATIONS_PER_BATCH ), $extra );
@@ -1442,19 +1488,20 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
foreach ( $followers as $follower )
{
$member = \IPS\Member::load( $follower['follow_member_id'] );
if ( $member != $this->author() and $this->canView( $member ) and !in_array( $follower['follow_member_id'], $exclude ) )
if ( $member != $this->author() and $this->canView( $member ) )
{
$followIds[] = $follower['follow_id'];
$notification->recipients->attach( $member, $follower );
}
}
$notification->send();
/* Log that we sent it */
if( count( $followIds ) )
{
\IPS\Db::i()->update( 'core_follow', array( 'follow_notify_sent' => time() ), \IPS\Db::i()->in( 'follow_id', $followIds ) );
}
$sentTo = $notification->send( $sentTo );
/* Update the queue */
$newOffset = $offset + static::NOTIFICATIONS_PER_BATCH;
@@ -1486,29 +1533,59 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
foreach( \IPS\Db::i()->select( '*', 'core_moderators' ) AS $mod )
{
$canView = FALSE;
$canApprove = FALSE;
if ( $mod['perms'] == '*' )
{
$canView = TRUE;
$canApprove = TRUE;
}
if ( $canView === FALSE )
else
{
$perms = json_decode( $mod['perms'], TRUE );
if ( isset( $perms['can_view_hidden_content'] ) AND $perms['can_view_hidden_content'] )
foreach ( array( 'canView' => 'can_view_hidden_', 'canApprove' => 'can_unhide_' ) as $varKey => $modPermKey )
{
$canView = TRUE;
}
else if ( isset( $perms['can_view_hidden_' . static::$title ] ) AND $perms['can_view_hidden_' . static::$title ] )
{
$canView = TRUE;
if ( isset( $perms[ $modPermKey . 'content' ] ) AND $perms[ $modPermKey . 'content' ] )
{
$$varKey = TRUE;
}
else
{
try
{
$container = ( $this instanceof \IPS\Content\Comment ) ? $this->item()->container() : $this->container();
$containerClass = get_class( $container );
$title = static::$title;
if
(
isset( $containerClass::$modPerm )
and
(
$perms[ $containerClass::$modPerm ] === -1
or
(
is_array( $perms[ $containerClass::$modPerm ] )
and
in_array( $container->_id, $perms[ $containerClass::$modPerm ] )
)
)
and
$perms["{$modPermKey}{$title}"]
)
{
$$varKey = TRUE;
}
}
catch ( \BadMethodCallException $e ) { }
}
}
}
if ( $canView === TRUE )
if ( $canView === TRUE and $canApprove === TRUE )
{
$moderators[ $mod['type'] ][] = $mod['id'];
}
}
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'unapproved_content', $this, array( $this, $this->author() ) );
foreach ( \IPS\Db::i()->select( '*', 'core_members', ( count( $moderators['m'] ) ? \IPS\Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . \IPS\Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) ) as $member )
{
@@ -1537,7 +1614,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
* Send quote and mention notifications
*
* @param array $exclude An array of member IDs *not* to send notifications to
* @return array Member IDs sent to
* @return array The members that were notified and how they were notified
*/
protected function sendQuoteAndMentionNotifications( $exclude=array() )
{
@@ -1549,7 +1626,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
*
* @param array array( 'quotes' => array( ... member IDs ... ), 'mentions' => array( ... member IDs ... ) )
* @param array $exclude An array of member IDs *not* to send notifications to
* @return array Member IDs sent to
* @return array The members that were notified and how they were notified
*/
protected function _sendQuoteAndMentionNotifications( $data, $exclude=array() )
{
@@ -1563,16 +1640,16 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
} );
if ( !empty( $data['quotes'] ) )
{
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'quote', ( $this instanceof \IPS\Content\Item ) ? $this : $this->item(), array( $this ), array( $this->author()->member_id ) );
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'quote', ( $this instanceof \IPS\Content\Item ) ? $this : $this->item(), array( $this ), array( $this->author()->member_id ), FALSE );
foreach ( $data['quotes'] as $quote )
{
$member = \IPS\Member::load( $quote );
if ( $member != $this->author() and $this->canView( $member ) )
if ( $member->member_id and $member != $this->author() and $this->canView( $member ) )
{
$notification->recipients->attach( $member );
}
}
$sentTo = array_merge( $notification->send(), $sentTo );
$sentTo = $notification->send( $sentTo );
}
/* Mentions */
@@ -1582,16 +1659,16 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
} );
if ( !empty( $data['mentions'] ) )
{
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'mention', ( $this instanceof \IPS\Content\Item ) ? $this : $this->item(), array( $this ), array( $this->author()->member_id ) );
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'mention', ( $this instanceof \IPS\Content\Item ) ? $this : $this->item(), array( $this ), array( $this->author()->member_id ), FALSE );
foreach ( $data['mentions'] as $mention )
{
$member = \IPS\Member::load( $mention );
if ( $member != $this->author() and $this->canView( $member ) )
if ( $member != $this->author() and $this->canView( $member ) and !$member->isIgnoring( $this->author(), 'mentions' ) )
{
$notification->recipients->attach( $member );
}
}
$sentTo = array_merge( $notification->send(), $sentTo );
$sentTo = $notification->send( $sentTo );
}
/* Return */
@@ -1608,9 +1685,8 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
{
$return = array( 'quotes' => array(), 'mentions' => array() );
$document = new \DOMDocument;
libxml_use_internal_errors(TRUE);
if ( @$document->loadHTML( '<div>' . $content . '</div>' ) !== FALSE )
$document = new \IPS\Xml\DOMDocument( '1.0', 'UTF-8' );
if ( @$document->loadHTML( \IPS\Xml\DOMDocument::wrapHtml( '<div>' . $content . '</div>' ) ) !== FALSE )
{
/* Quotes */
foreach( $document->getElementsByTagName('blockquote') as $quote )
@@ -1625,9 +1701,8 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
foreach( $document->getElementsByTagName('a') as $link )
{
if ( $link->getAttribute('data-mentionid') )
{
$path = explode( '/', $link->getNodePath() );
if ( !in_array( 'blockquote', $path ) )
{
if ( !preg_match( '/\/blockquote(\[\d*\])?\//', $link->getNodePath() ) )
{
$return['mentions'][] = $link->getAttribute('data-mentionid');
}
@@ -1696,6 +1771,18 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
return $classes;
}
/**
* Override the HTML parsing enabled flag for rebuilds?
*
* @note By default this will return FALSE, but classes can override
* @see \IPS\forums\Topic\Post
* @return bool
*/
public function htmlParsingEnforced()
{
return FALSE;
}
/**
* Return any custom multimod actions this content item supports
*
@@ -1753,4 +1840,38 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( '__indefart_' . static::$title, FALSE );
}
/**
* Definite Article
*
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public function definiteArticle( \IPS\Lang $lang = NULL )
{
$container = ( $this instanceof \IPS\Content\Comment ) ? $this->item()->containerWrapper() : $this->containerWrapper();
return static::_definiteArticle( $container ? $container->_data : array(), $lang );
}
/**
* Definite Article
*
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( '__defart_' . static::$title, FALSE );
}
/**
* Get preview image for share services
*
* @return string
*/
public function shareImage()
{
return (string) \IPS\Theme::i()->logo_sharer;
}
}