Version 4.2.0
This commit is contained in:
1 parent
0dc2aee5ed
commit
96997ddd8e
2074 files changed
+125454
-55780
No files matched your search
+406
-432
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Abstract Content 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 3 Oct 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS;
|
||||
@@ -48,6 +47,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
*/
|
||||
public static $includeInSitemap = TRUE;
|
||||
|
||||
/**
|
||||
* @brief Reputation Store
|
||||
*/
|
||||
protected $reputation;
|
||||
|
||||
/**
|
||||
* Should posting this increment the poster's post count?
|
||||
*
|
||||
@@ -244,6 +248,35 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
return $this->mapped('content');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
$internal = NULL;
|
||||
$attachments = array();
|
||||
|
||||
if ( isset( static::$databaseColumnMap['content'] ) )
|
||||
{
|
||||
$internal = \IPS\Db::i()->select( 'attachment_id', 'core_attachments_map', array( 'location_key=? and id1=?', static::$application . '_' . ucfirst( static::$module ), $this->$idColumn ) );
|
||||
}
|
||||
|
||||
if ( $internal )
|
||||
{
|
||||
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; }
|
||||
|
||||
/**
|
||||
* Text for use with data-ipsTruncate
|
||||
* Returns the post with paragraphs turned into line breaks
|
||||
@@ -280,12 +313,17 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
if ( $this instanceof \IPS\Content\Reputation )
|
||||
$idColumn = static::$databaseColumnId;
|
||||
|
||||
if ( \IPS\IPS::classUsesTrait( $this, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array( 'app=? AND type=? AND type_id=?', static::$application, static::$reputationType, $this->$idColumn ) );
|
||||
\IPS\Db::i()->delete( 'core_reputation_index', array( 'app=? AND type=? AND type_id=?', static::$application, $this->reactionType(), $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 ) );
|
||||
|
||||
\IPS\Db::i()->delete( 'core_deletion_log', array( "dellog_content_class=? AND dellog_content_id=?", get_class( $this ), $this->$idColumn ) );
|
||||
parent::delete();
|
||||
|
||||
$this->expireWidgetCaches();
|
||||
@@ -329,14 +367,15 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* Content is hidden?
|
||||
*
|
||||
* @return int
|
||||
* @li -2 is pending deletion
|
||||
* @li -1 is hidden having been hidden by a moderator
|
||||
* @li 0 is unhidden
|
||||
* @li 1 is hidden needing approval
|
||||
* @note The actual column may also contain 2 which means the item is hidden because the parent is hidden, but it is not hidden in itself. This method will return -1 in that case.
|
||||
*
|
||||
* @note A piece of content (item and comment) can have an alias for hidden OR approved.
|
||||
* With hidden: 0=not hidden, 1=hidden (needs moderator approval), -1=hidden by moderator, 2=parent item is hidden
|
||||
* With approved: 1=not hidden, 0=hidden (needs moderator approval), -1=hidden by moderator
|
||||
* With hidden: 0=not hidden, 1=hidden (needs moderator approval), -1=hidden by moderator, 2=parent item is hidden, -2=pending deletion
|
||||
* With approved: 1=not hidden, 0=hidden (needs moderator approval), -1=hidden by moderator, -2=pending deletion
|
||||
*
|
||||
* User posting has moderator approval set: When adding an unapproved ITEM (approved=0, hidden=1) you should *not* increment container()->_comments but you should update container()->_unapprovedItems
|
||||
* User posting has moderator approval set: When adding an unapproved COMMENT (approved=0, hidden=1) you should *not* increment item()->num_comments in item or container()->_comments but you should update item()->unapproved_comments and container()->_unapprovedComments
|
||||
@@ -361,6 +400,10 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
elseif ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['approved'];
|
||||
if ( $this->$column == -2 )
|
||||
{
|
||||
return intval( $this->$column );
|
||||
}
|
||||
return $this->$column == -1 ? intval( $this->$column ) : intval( !$this->$column );
|
||||
}
|
||||
else
|
||||
@@ -430,27 +473,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/* Per-container permission */
|
||||
elseif ( $container )
|
||||
{
|
||||
$containerClass = get_class( $container );
|
||||
$title = static::$title;
|
||||
if
|
||||
(
|
||||
isset( $containerClass::$modPerm )
|
||||
and
|
||||
(
|
||||
$member->modPermission( $containerClass::$modPerm ) === -1
|
||||
or
|
||||
(
|
||||
is_array( $member->modPermission( $containerClass::$modPerm ) )
|
||||
and
|
||||
in_array( $container->_id, $member->modPermission( $containerClass::$modPerm ) )
|
||||
)
|
||||
)
|
||||
and
|
||||
$member->modPermission( "can_{$type}_{$title}" )
|
||||
)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return $container->modPermission( $type, $member );
|
||||
}
|
||||
|
||||
/* Still here? return false */
|
||||
@@ -463,10 +486,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* @param string $action The action
|
||||
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
|
||||
* @param string|NULL $reason Reason (for hides)
|
||||
* @param bool $immediately Delete Immediately
|
||||
* @return void
|
||||
* @throws \OutOfRangeException|\InvalidArgumentException|\RuntimeException
|
||||
*/
|
||||
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL )
|
||||
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL, $immediately = FALSE )
|
||||
{
|
||||
if( $action === 'approve' )
|
||||
{
|
||||
@@ -474,13 +498,19 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Check it's a valid action */
|
||||
if ( !in_array( $action, array( 'pin', 'unpin', 'feature', 'unfeature', 'hide', 'unhide', 'move', 'lock', 'unlock', 'delete', 'publish' ) ) )
|
||||
if ( !in_array( $action, array( 'pin', 'unpin', 'feature', 'unfeature', 'hide', 'unhide', 'move', 'lock', 'unlock', 'delete', 'publish', 'restore', 'restoreAsHidden' ) ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
/* And that we can do it */
|
||||
if ( !call_user_func( array( $this, 'can' . ucfirst( $action ) ), $member ) )
|
||||
$toCheck = $action;
|
||||
if ( $action == 'restoreAsHidden' )
|
||||
{
|
||||
$toCheck = 'restore';
|
||||
}
|
||||
|
||||
if ( !call_user_func( array( $this, 'can' . ucfirst( $toCheck ) ), $member ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
@@ -541,9 +571,32 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
/* Delete is just a method */
|
||||
elseif ( $action === 'delete' )
|
||||
{
|
||||
/* 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 ( $this instanceof \IPS\Content\Hideable ) AND $immediately === FALSE )
|
||||
{
|
||||
$this->logDelete();
|
||||
return;
|
||||
}
|
||||
|
||||
$idColumn = static::$databaseColumnId;
|
||||
\IPS\Db::i()->delete( 'core_deletion_log', array( "dellog_content_class=? AND dellog_content_id=?", get_class( $this ), $this->$idColumn ) );
|
||||
$this->delete();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restore is just a method */
|
||||
elseif ( $action === 'restore' )
|
||||
{
|
||||
$this->restore();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restore As Hidden is just a method */
|
||||
elseif ( $action === 'restoreAsHidden' )
|
||||
{
|
||||
$this->restore( TRUE );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Publish is just a method */
|
||||
elseif ( $action === 'publish' )
|
||||
@@ -561,6 +614,200 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log for deletion later
|
||||
*
|
||||
* \IPS\Member|NULL $member The member or NULL for currently logged in
|
||||
* @return void
|
||||
*/
|
||||
public function logDelete( $member = NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
/* Log it! */
|
||||
$log = new \IPS\core\DeletionLog;
|
||||
$log->setContentAndMember( $this, $member );
|
||||
$log->save();
|
||||
|
||||
if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['hidden'];
|
||||
}
|
||||
else if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['approved'];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( $this->container() )
|
||||
{
|
||||
if ( $this->container()->_comments !== NULL )
|
||||
{
|
||||
/* Hidden content already decrements */
|
||||
if ( !$this->hidden() )
|
||||
{
|
||||
$this->container()->_comments = ( $this->container()->_comments - $this->mapped('num_comments') );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->container()->_unapprovedComments !== NULL )
|
||||
{
|
||||
$this->container()->_unapprovedComments = ( $this->container()->_unapprovedComments - $this->mapped( 'unapproved_comments' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
|
||||
$this->$column = -2;
|
||||
$this->save();
|
||||
|
||||
if ( $this instanceof \IPS\Content\Comment )
|
||||
{
|
||||
$item = $this->item();
|
||||
|
||||
/* Update last comment stuff */
|
||||
$item->resyncLastComment();
|
||||
|
||||
/* Update last review stuff */
|
||||
$item->resyncLastReview();
|
||||
|
||||
/* Update number of comments */
|
||||
$item->resyncCommentCounts();
|
||||
|
||||
/* Update number of reviews */
|
||||
$item->resyncReviewCounts();
|
||||
|
||||
/* Save*/
|
||||
$item->save();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( $this->container() )
|
||||
{
|
||||
$this->container()->setLastComment();
|
||||
$this->container()->save();
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore Content
|
||||
*
|
||||
* @param bool Restore as hidden?
|
||||
* @return void
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function restore( $hidden = FALSE )
|
||||
{
|
||||
try
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$log = \IPS\core\DeletionLog::constructFromData( \IPS\Db::i()->select( '*', 'core_deletion_log', array( "dellog_content_class=? AND dellog_content_id", get_class( $this ), $this->$idColumn ) )->first() );
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
/* Restoring as hidden? */
|
||||
if ( $hidden )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['hidden'];
|
||||
}
|
||||
else if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['approved'];
|
||||
}
|
||||
|
||||
$this->$column = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['hidden'];
|
||||
$this->$column = 0;
|
||||
}
|
||||
else if ( isset( static::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = static::$databaseColumnMap['approved'];
|
||||
$this->$column = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the changes */
|
||||
$this->save();
|
||||
|
||||
/* Reindex the now hidden content */
|
||||
if ( $this instanceof \IPS\Content\Item and static::$firstCommentRequired )
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->index( $this->firstComment() );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Content\Search\Index::i()->index( $this );
|
||||
}
|
||||
|
||||
/* Delete the log */
|
||||
$log->delete();
|
||||
|
||||
/* Log to moderate logs */
|
||||
if ( !$hidden )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( $this->container() )
|
||||
{
|
||||
if ( $this->container()->_comments !== NULL )
|
||||
{
|
||||
if ( $this instanceof \IPS\Content\Item )
|
||||
{
|
||||
$this->container()->_comments = ( $this->container()->_comments + $this->mapped('num_comments') );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->container()->_comments = $this->container()->_comments + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->container()->_unapprovedComments !== NULL )
|
||||
{
|
||||
if ( $this instanceof \IPS\Content\Item )
|
||||
{
|
||||
$this->container()->_unapprovedComments = ( $this->container()->_unapprovedComments + $this->mapped('unapproved_comments') );
|
||||
}
|
||||
}
|
||||
|
||||
$this->container()->setLastComment();
|
||||
$this->container()->save();
|
||||
|
||||
if ( $this instanceof \IPS\Content\Comment )
|
||||
{
|
||||
$this->item()->rebuildFirstAndLastCommentData();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can restore?*
|
||||
*
|
||||
* @param \IPS\Member|NULL The member, or currently logged in member
|
||||
* @return bool
|
||||
*/
|
||||
public function canRestore( $member=NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return \IPS\Member::loggedIn()->modPermission('can_restore_deleted_content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide
|
||||
*
|
||||
@@ -722,7 +969,43 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blurb for when/why/by whom this content was deleted
|
||||
*
|
||||
* @return string
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function deletedBlurb()
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\Hideable ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$log = \IPS\core\DeletionLog::constructFromData( \IPS\Db::i()->select( '*', 'core_deletion_log', array( "dellog_content_class=? AND dellog_content_id=?", get_class( $this ), $this->$idColumn ) )->first() );
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'deletion_blurb', FALSE, array( 'sprintf' => array( $log->_deleted_by->name, $log->deleted_date->fullYearLocaleDate(), $log->deletion_date->fullYearLocaleDate() ) ) );
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('deleted');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can promote this comment/item?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return boolean
|
||||
*/
|
||||
public function canPromoteToSocialMedia( $member=NULL )
|
||||
{
|
||||
return \IPS\core\Promote::canPromote( $member );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can report?
|
||||
*
|
||||
@@ -741,7 +1024,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* Can the member report content? */
|
||||
if ( $member->group['gbw_no_report'] )
|
||||
if ( !$member->group['g_can_report'] )
|
||||
{
|
||||
return 'no_module_permission';
|
||||
}
|
||||
@@ -866,7 +1149,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
$oldAuthor = $this->author();
|
||||
|
||||
foreach ( array( 'author', 'author_name' ) as $k )
|
||||
foreach ( array( 'author', 'author_name', 'edit_member_name' ) as $k )
|
||||
{
|
||||
if ( isset( static::$databaseColumnMap[ $k ] ) )
|
||||
{
|
||||
@@ -878,6 +1161,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
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;
|
||||
@@ -906,9 +1190,10 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
* @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
|
||||
* @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 )
|
||||
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() )
|
||||
{
|
||||
/* Item details */
|
||||
$itemClass = $indexData['index_class'];
|
||||
@@ -931,12 +1216,12 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
if ( in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
|
||||
{
|
||||
$objectUrl = $itemUrl->setQueryString( array( 'do' => 'findReview', 'review' => $indexData['index_object_id'] ) );
|
||||
$showRepUrl = $itemUrl->setQueryString( array( 'do' => 'showRepReview', 'review' => $indexData['index_object_id'] ) );
|
||||
$showRepUrl = $itemUrl->setQueryString( array( 'do' => 'showReactionsReview', 'review' => $indexData['index_object_id'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$objectUrl = $itemUrl->setQueryString( array( 'do' => 'findComment', 'comment' => $indexData['index_object_id'] ) );
|
||||
$showRepUrl = $itemUrl->setQueryString( array( 'do' => 'showRepComment', 'comment' => $indexData['index_object_id'] ) );
|
||||
$showRepUrl = $itemUrl->setQueryString( array( 'do' => 'showReactionsComment', 'comment' => $indexData['index_object_id'] ) );
|
||||
}
|
||||
|
||||
$indefiniteArticle = $itemClass::_indefiniteArticle( $containerData );
|
||||
@@ -945,7 +1230,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
else
|
||||
{
|
||||
$objectUrl = $itemUrl;
|
||||
$showRepUrl = $itemUrl->setQueryString( 'do', 'showRep' );
|
||||
$showRepUrl = $itemUrl->setQueryString( 'do', 'showReactions' );
|
||||
}
|
||||
$articles = array( 'indefinite' => $indefiniteArticle, 'definite' => $definiteArticle );
|
||||
|
||||
@@ -971,7 +1256,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
}
|
||||
|
||||
/* 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 ) );
|
||||
return call_user_func_array( $template, array( $indexData, $articles, $authorData, $itemData, $unread, $asItem ? $itemUrl : $objectUrl, $itemUrl, $containerUrl, $containerTitle, $repCount, $showRepUrl, $snippet, $iPostedIn, $view, $canIgnoreComments, $reactions ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -991,6 +1276,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
return $view == 'expanded' ? \IPS\Theme::i()->getTemplate( 'system', 'core', 'front' )->searchResultSnippet( $indexData ) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a classname applied to the search result block
|
||||
*/
|
||||
public static $searchResultClassName = '';
|
||||
|
||||
/**
|
||||
* Return the filters that are available for selecting table rows
|
||||
*
|
||||
@@ -1039,397 +1329,6 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
|
||||
}
|
||||
|
||||
/* !Reputation */
|
||||
|
||||
/**
|
||||
* Can give reputation?
|
||||
*
|
||||
* @note This method is also ran to check if a member can "unrep"
|
||||
* @param int $type 1 for positive, -1 for negative
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return bool
|
||||
*/
|
||||
public function canGiveReputation( $type, \IPS\Member $member = NULL )
|
||||
{
|
||||
return static::_canGiveReputation( $type, $this->author()->member_id, $this->author()->member_group_id, $this->repGiven( $member ), $member );
|
||||
}
|
||||
|
||||
/**
|
||||
* Can give reputation?
|
||||
*
|
||||
* @note This method is also ran to check if a member can "unrep"
|
||||
* @param int $type 1 for positive, -1 for negative
|
||||
* @param int $authorId The author ID
|
||||
* @param int $authorGroup The author group
|
||||
* @param int $repGiven The reputation we have already given (1 = positive, -1 = negative, 0 = no rep given)
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return bool
|
||||
*/
|
||||
public static function _canGiveReputation( $type, $authorId, $authorGroup, $repGiven, \IPS\Member $member = NULL )
|
||||
{
|
||||
/* Reputation needs to be enabled */
|
||||
if ( !\IPS\Settings::i()->reputation_enabled or !in_array( 'IPS\Content\Reputation', class_implements( get_called_class() ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Guests cannot rep */
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
if ( !$member->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Author needs to not be protected */
|
||||
if ( in_array( $authorGroup, explode( ',', \IPS\Settings::i()->reputation_protected_groups ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Users may not be able to rep themselves */
|
||||
if ( !\IPS\Settings::i()->reputation_can_self_vote and $authorId == $member->member_id )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Rep per day */
|
||||
$limit = ( $type === 1 ) ? $member->group['g_rep_max_positive'] : $member->group['g_rep_max_negative'];
|
||||
if ( $limit == 0 and !$repGiven )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Have we already given rep? */
|
||||
switch ( \IPS\Settings::i()->reputation_point_types )
|
||||
{
|
||||
/* If we're using a positive system, we can rep positive only if we haven't repped yet, or negative only if we have */
|
||||
case 'like':
|
||||
case 'positive':
|
||||
return ( $repGiven === 1 ) ? ( $type === -1 ) : ( $type === 1 );
|
||||
|
||||
/* If we're using a negative system, we can rep negative only if we haven't repped yet, or positive only if we have */
|
||||
case 'negative':
|
||||
return $repGiven ? ( $type === 1 ) : ( $type === -1 );
|
||||
|
||||
/* If we're using a positive and negative system - it's more complicated... */
|
||||
case 'both':
|
||||
switch ( $repGiven )
|
||||
{
|
||||
/* If we haven't repped yet, we can do either */
|
||||
case 0:
|
||||
return TRUE;
|
||||
|
||||
/* If we've given positive rep already, we can only do negative now */
|
||||
case 1:
|
||||
return ( $type === -1 );
|
||||
|
||||
/* If we've given negative rep already, we can only do positive now */
|
||||
case -1:
|
||||
return ( $type === 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch all */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give reputation
|
||||
*
|
||||
* @param int $type 1 for positive, -1 for negative
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return void
|
||||
* @throws \DomainException|\BadMethodCallException
|
||||
*/
|
||||
public function giveReputation( $type, \IPS\Member $member=NULL )
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\Reputation ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
if ( !$this->canGiveReputation( $type, $member ) )
|
||||
{
|
||||
throw new \DomainException( 'cannot_rep_user' );
|
||||
}
|
||||
|
||||
$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 )
|
||||
{
|
||||
unset( $this->reputation[ $member->member_id ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$limit = ( $type === 1 ) ? $member->group['g_rep_max_positive'] : $member->group['g_rep_max_negative'];
|
||||
|
||||
if ( $limit !== 999 )
|
||||
{
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_reputation_index', array( 'member_id=? AND rep_date>? AND rep_rating=?', $member->member_id, \IPS\DateTime::create()->sub( new \DateInterval( 'P1D' ) )->getTimestamp(), $type ) )->first();
|
||||
if ( $count >= $limit )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( \IPS\Settings::i()->reputation_point_types == 'like' ? 'rep_daily_exceeded_likes' :'rep_daily_exceeded', FALSE, array( 'sprintf' => array( $limit ) ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
\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,
|
||||
'class_type_id_hash' => md5( get_class( $this ) . ':' . $this->$idColumn ),
|
||||
'rep_class' => get_class( $this ),
|
||||
'item_id' => (int) $this->mapped('item')
|
||||
) );
|
||||
|
||||
/* Send Notification */
|
||||
if ( $type === 1 AND $this->author()->member_id AND $this->author() != \IPS\Member::loggedIn() AND $this->canView( $this->author() ) )
|
||||
{
|
||||
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'new_likes', $this, array( $this, \IPS\Member::loggedIn() ) );
|
||||
$notification->recipients->attach( $this->author() );
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
if ( $this->reputation !== NULL )
|
||||
{
|
||||
$this->reputation[ $member->member_id ] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
if( $this->author()->member_id )
|
||||
{
|
||||
$this->author()->pp_reputation_points += $type;
|
||||
$this->author()->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reputation Cache
|
||||
*/
|
||||
public $reputation = NULL;
|
||||
|
||||
/**
|
||||
* Get reputation count
|
||||
*
|
||||
* @return int
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function reputation()
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\Reputation ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
if ( $this->reputation === NULL )
|
||||
{
|
||||
$this->reputation = iterator_to_array( \IPS\Db::i()->select( 'member_id, rep_rating', 'core_reputation_index', $this->getReputationWhereClause() )->setKeyField( 'member_id' )->setValueField( 'rep_rating' ) );
|
||||
return array_sum( $this->reputation );
|
||||
}
|
||||
else
|
||||
{
|
||||
$repCount = 0;
|
||||
foreach( $this->reputation as $member => $value )
|
||||
{
|
||||
if( is_int( $value ) )
|
||||
{
|
||||
$repCount += $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$repCount += $value['rep_rating'];
|
||||
}
|
||||
|
||||
}
|
||||
return $repCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reputation where clause
|
||||
*
|
||||
* @return array
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function getReputationWhereClause()
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\Reputation ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$where = array( array( 'app=? AND type=? AND type_id=?', static::$application, static::$reputationType, $this->$idColumn ) );
|
||||
|
||||
switch( \IPS\Settings::i()->reputation_point_types )
|
||||
{
|
||||
case 'positive':
|
||||
case 'like':
|
||||
$where[] = array( 'rep_rating=?', "1" );
|
||||
break;
|
||||
case 'negative':
|
||||
$where[] = array( 'rep_rating=?', "-1" );
|
||||
break;
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached like blurb
|
||||
*/
|
||||
public $likeBlurb = NULL;
|
||||
|
||||
/**
|
||||
* Get "like" blurb (You and X others like this)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function likeBlurb()
|
||||
{
|
||||
if( $this->likeBlurb === NULL )
|
||||
{
|
||||
/* Did anyone like it? */
|
||||
$numberOfLikes = $this->reputation(); # int
|
||||
if ( $numberOfLikes )
|
||||
{
|
||||
/* 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 = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $this->likeBlurb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has reputation been given by a particular member?
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
|
||||
* @return int 1 = Positive rep given. -1 = Negative rep given. 0 = No rep given
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function repGiven( \IPS\Member $member = NULL )
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\Reputation ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
if ( $this->reputation === NULL )
|
||||
{
|
||||
$this->reputation();
|
||||
}
|
||||
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return array_key_exists( $member->member_id, $this->reputation ) ? intval( $this->reputation[ $member->member_id ] ) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get table showing who has given reputation
|
||||
*
|
||||
* @return \IPS\Helpers\Table\Db
|
||||
* @throws \DomainException
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function reputationTable()
|
||||
{
|
||||
if ( !( $this instanceof \IPS\Content\Reputation ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
if ( !\IPS\Member::loggedIn()->group['gbw_view_reps'] )
|
||||
{
|
||||
throw new \DomainException;
|
||||
}
|
||||
|
||||
$idColumn = static::$databaseColumnId;
|
||||
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_reputation_index', $this->url('showRep'), $this->getReputationWhereClause() );
|
||||
$table->sortBy = 'rep_date';
|
||||
$table->sortDirection = 'desc';
|
||||
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' ), 'reputationLogTable' );
|
||||
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' ), 'reputationLog' );
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/* !Follow */
|
||||
|
||||
const FOLLOW_PUBLIC = 1;
|
||||
@@ -1874,4 +1773,79 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
return (string) \IPS\Theme::i()->logo_sharer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log keyword usage, if any
|
||||
*
|
||||
* @param string $content Content/text of submission
|
||||
* @param string|NULL $title Title of submission
|
||||
* @return void
|
||||
*/
|
||||
public function checkKeywords( $content, $title=NULL )
|
||||
{
|
||||
/* Do we have any keywords to track? */
|
||||
if( !\IPS\Settings::i()->stats_keywords )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need to know the ID */
|
||||
$idColumn = static::$databaseColumnId;
|
||||
|
||||
/* If this is a content item and first comment is required, skip checking the comment */
|
||||
if ( $this instanceof \IPS\Content\Comment )
|
||||
{
|
||||
$itemClass = static::$itemClass;
|
||||
|
||||
if( $itemClass::$firstCommentRequired === TRUE )
|
||||
{
|
||||
/* During initial post, at this point the firstCommentIdColumn value won't be set, so we check for that or explicitly if this is the first post */
|
||||
if( !$this->item()->mapped('first_comment_id') OR $this->$idColumn == $this->item()->mapped('first_comment_id') )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$words = preg_split("/[\s]+/", trim( strip_tags( preg_replace( "/<br( \/)?>/", "\n", $content ) ) ), NULL, PREG_SPLIT_NO_EMPTY );
|
||||
|
||||
if( $title !== NULL )
|
||||
{
|
||||
$titleWords = explode( ' ', $title );
|
||||
$words = array_merge( $words, $titleWords );
|
||||
}
|
||||
|
||||
$words = array_unique( $words );
|
||||
|
||||
$keywords = json_decode( \IPS\Settings::i()->stats_keywords, true );
|
||||
|
||||
$extraData = json_encode( array( 'class' => get_class( $this ), 'id' => $this->$idColumn ) );
|
||||
|
||||
foreach( $keywords as $keyword )
|
||||
{
|
||||
if( in_array( $keyword, $words ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_statistics', array( 'time' => time(), 'type' => 'keyword', 'value_4' => $keyword, 'extra_data' => $extraData ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* !Deprecated */
|
||||
/* The methods below are deprecated and will be removed in Invision Community 4.3 */
|
||||
|
||||
/**
|
||||
* Get reputation count
|
||||
*
|
||||
* @return int
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function reputation()
|
||||
{
|
||||
if ( !\IPS\IPS::classUsesTrait( $this, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
throw new \BadMethodCallException;
|
||||
}
|
||||
|
||||
return $this->reactionCount();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user