Version 4.3.6

This commit is contained in:
Neo committed 2025-12-19 05:49:12 -08:00
1 parent fe1acf984a
commit 1a0c7fd3c2
609 files changed
+14707 -5726

No files matched your search

+2 -2
View File
@@ -209,11 +209,11 @@ class _CommentController extends \IPS\Api\Controller
$class = $this->class;
if ( in_array( 'IPS\Content\Review', class_parents( $class ) ) )
{
$comment = $class::create( $item, $content, FALSE, intval( \IPS\Request::i()->rating ), $author->member_id ? NULL : $author->real_name, $author, $date, ( !$this->member and \IPS\Request::i()->ip_address ) ?: \IPS\Request::i()->ipAddress(), $hidden );
$comment = $class::create( $item, $content, FALSE, intval( \IPS\Request::i()->rating ), $author->member_id ? NULL : $author->real_name, $author, $date, ( !$this->member and \IPS\Request::i()->ip_address ) ? \IPS\Request::i()->ip_address : \IPS\Request::i()->ipAddress(), $hidden );
}
else
{
$comment = $class::create( $item, $content, FALSE, $author->member_id ? NULL : $author->real_name, NULL, $author, $date, ( !$this->member and \IPS\Request::i()->ip_address ) ?: \IPS\Request::i()->ipAddress(), $hidden );
$comment = $class::create( $item, $content, FALSE, $author->member_id ? NULL : $author->real_name, NULL, $author, $date, ( !$this->member and \IPS\Request::i()->ip_address ) ? \IPS\Request::i()->ip_address : \IPS\Request::i()->ipAddress(), $hidden );
}
/* Index */
+1 -1
View File
@@ -382,7 +382,7 @@ class _ItemController extends \IPS\Api\Controller
}
$commentClass = $item::$commentClass;
$post = $commentClass::create( $item, $postContents, TRUE, $author->member_id ? NULL : $author->real_name, NULL, $author, $date );
$post = $commentClass::create( $item, $postContents, TRUE, $author->member_id ? NULL : $author->real_name, NULL, $author, $date, ( !$this->member and \IPS\Request::i()->ip_address ) ? \IPS\Request::i()->ip_address : \IPS\Request::i()->ipAddress() );
if ( isset( $class::$databaseColumnMap['first_comment_id'] ) )
{
+22 -9
View File
@@ -130,12 +130,15 @@ trait ClubContainer
{
$this->setPermissionsToClub( $club );
}
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $nodeClass, mb_strrpos( $nodeClass, '\\' ) + 1 ) );
$time = time();
\IPS\Db::i()->insert( 'core_follow', \IPS\Db::i()->select( "MD5( CONCAT( '{$followApp};{$followArea};{$this->_id};', follow_member_id ) ) AS follow_id, '{$followApp}' AS follow_app, '{$followArea}' AS follow_area, '{$this->_id}' AS follow_rel_id, follow_member_id, follow_is_anon, '{$time}' AS follow_added, follow_notify_do, follow_notify_meta, follow_notify_freq, 0 AS follow_notify_sent, follow_visible", 'core_follow', array(
'follow_app=? AND follow_area=? AND follow_rel_id=?', 'core', 'club', $club->id ) ) );
if ( !$haveId )
{
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $nodeClass, mb_strrpos( $nodeClass, '\\' ) + 1 ) );
$time = time();
\IPS\Db::i()->insert( 'core_follow', \IPS\Db::i()->select( "MD5( CONCAT( '{$followApp};{$followArea};{$this->_id};', follow_member_id ) ) AS follow_id, '{$followApp}' AS follow_app, '{$followArea}' AS follow_area, '{$this->_id}' AS follow_rel_id, follow_member_id, follow_is_anon, '{$time}' AS follow_added, follow_notify_do, follow_notify_meta, follow_notify_freq, 0 AS follow_notify_sent, follow_visible", 'core_follow', array(
'follow_app=? AND follow_area=? AND follow_rel_id=?', 'core', 'club', $club->id ) ) );
}
}
/**
@@ -299,12 +302,22 @@ trait ClubContainer
{
if ( \IPS\Settings::i()->clubs )
{
$clubIdColumn = $this->clubIdColumn();
$clubIdColumn = $this->clubIdColumn();
$itemClass = $itemClass ?: static::$contentItemClass;
$title = $itemClass::$title;
if ( $this->$clubIdColumn and $club = $this->club() )
{
if ( in_array( $club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR ) ) )
if ( \in_array( $club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR ) ) )
{
if ( in_array( $type, explode( ',', \IPS\Settings::i()->clubs_modperms ) ) )
if ( \in_array( $type, explode( ',', \IPS\Settings::i()->clubs_modperms ) ) )
{
return TRUE;
}
}
elseif ( $member->modPermission( "can_{$type}_{$title}" ) and \is_array( $member->modPermission( static::$modPerm ) ) and $member->modPermission('can_access_all_clubs') )
{
if ( \in_array( $type, explode( ',', \IPS\Settings::i()->clubs_modperms ) ) )
{
return TRUE;
}
+41 -75
View File
@@ -184,20 +184,6 @@ abstract class _Comment extends \IPS\Content
}
catch( \BadMethodCallException $e ) { }
/* Update the container */
if ( !$obj->hidden() AND !$item->hidden() )
{
try
{
$container = $item->container();
if ( $container->_comments !== NULL )
{
$container->setLastComment( $obj );
$container->save();
}
}
catch ( \BadMethodCallException $e ) { }
}
/* Update member's last post and daily post limits */
if( $obj->author()->member_id )
@@ -253,10 +239,14 @@ abstract class _Comment extends \IPS\Content
* @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)?
* @param string|NULL $content The content to check - useful for if the content needs to be checked first, before it gets saved to the database.
* @return bool Whether to send unapproved notifications
*/
protected function checkProfanityFilters( $first=FALSE, $edit=TRUE )
public function checkProfanityFilters( $first=FALSE, $edit=TRUE, $content=NULL )
{
/* Set our content */
$content = $content ?: $this->content();
/* We need our item */
$item = $this->item();
@@ -265,25 +255,29 @@ abstract class _Comment extends \IPS\Content
/* Pass this through our profanity filters to see if it needs to be mod queued */
$sendNotifications = FALSE;
/* Do we need to recount item comments and container comments? */
$recount = 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() );
$hiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $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() );
$itemHiddenByFilter = \IPS\core\Profanity::hiddenByFilters( $content );
if ( isset( $item::$databaseColumnMap['approved'] ) and $itemHiddenByFilter )
{
/* 'approved' is easy, clear and concise */
$column = $item::$databaseColumnMap['approved'];
$item->$column = 0;
$item->save();
$recount = TRUE;
}
elseif ( isset( $item::$databaseColumnMap['hidden'] ) and $itemHiddenByFilter )
{
@@ -291,8 +285,9 @@ abstract class _Comment extends \IPS\Content
$column = $item::$databaseColumnMap['hidden'];
$item->$column = 1;
$item->save();
$recount = TRUE;
}
if( $edit === TRUE )
{
$sendNotifications = TRUE;
@@ -303,6 +298,7 @@ abstract class _Comment extends \IPS\Content
if ( $hiddenByFilter === TRUE )
{
$recount = TRUE;
if ( isset( static::$databaseColumnMap['approved'] ) )
{
/* 'approved' is easy, clear and concise */
@@ -318,6 +314,20 @@ abstract class _Comment extends \IPS\Content
$sendNotifications = TRUE;
}
if ( $recount === TRUE )
{
$item->resyncCommentCounts();
$item->resyncLastComment();
$item->save();
if ( $container = $item->containerWrapper() )
{
$container->resetCommentCounts();
$container->save();
}
}
return $sendNotifications;
}
@@ -422,7 +432,7 @@ abstract class _Comment extends \IPS\Content
{
$item->save();
if ( $item->containerWrapper() AND !$item->approvedButHidden() AND $item->container()->_unapprovedComments !== NULL )
if ( $item->containerWrapper() AND !$item->approvedButHidden() AND $this->hidden() == 1 AND $item->container()->_unapprovedComments !== NULL )
{
$item->container()->_unapprovedComments = $item->container()->_unapprovedComments + 1;
$item->container()->save();
@@ -564,14 +574,7 @@ abstract class _Comment extends \IPS\Content
{
$member = $member ?: \IPS\Member::loggedIn();
$container = NULL;
try
{
$container = $this->item()->container();
}
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['g_hide_own_posts'] == '1' or in_array( get_class( $this->item() ), explode( ',', $member->group['g_hide_own_posts'] ) ) ) ) ) );
return ( !$this->isFirst() and ( static::modPermission( 'hide', $member, $this->item()->containerWrapper() ) 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'] ) ) ) ) ) );
}
/**
@@ -584,13 +587,6 @@ abstract class _Comment extends \IPS\Content
{
$member = $member ?: \IPS\Member::loggedIn();
$container = NULL;
try
{
$container = $this->item()->container();
}
catch ( \BadMethodCallException $e ) { }
$hiddenByItem = FALSE;
if ( isset( static::$databaseColumnMap['hidden'] ) )
{
@@ -598,7 +594,7 @@ abstract class _Comment extends \IPS\Content
$hiddenByItem = (boolean) ( $this->$column === 2 );
}
return ( !$this->isFirst() and ! $hiddenByItem and static::modPermission( 'unhide', $member, $container ) );
return ( !$this->isFirst() and ! $hiddenByItem and static::modPermission( 'unhide', $member, $this->item()->containerWrapper() ) );
}
/**
@@ -611,14 +607,7 @@ abstract class _Comment extends \IPS\Content
{
$member = $member ?: \IPS\Member::loggedIn();
$container = NULL;
try
{
$container = $this->item()->container();
}
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'] == '1' or in_array( get_class( $this->item() ), explode( ',', $member->group['g_delete_own_posts'] ) ) ) ) ) );
return ( !$this->isFirst() and ( static::modPermission( 'delete', $member, $this->item()->containerWrapper() ) 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'] ) ) ) ) ) );
}
/**
@@ -633,17 +622,10 @@ abstract class _Comment extends \IPS\Content
if ( $itemClass::$firstCommentRequired )
{
$container = NULL;
try
{
$container = $this->item()->container();
}
catch ( \BadMethodCallException $e ) { }
if ( !$this->isFirst() )
{
$member = $member ?: \IPS\Member::loggedIn();
return $itemClass::modPermission( 'split_merge', $member, $container );
return $itemClass::modPermission( 'split_merge', $member, $this->item()->containerWrapper() );
}
}
return FALSE;
@@ -715,35 +697,17 @@ abstract class _Comment extends \IPS\Content
*/
public function editContents( $newContent )
{
/* Check if profanity filters should mod-queue this comment */
$sendNotifications = $this->checkProfanityFilters( $this->isFirst(), TRUE, $newContent );
/* Do it */
$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 )
@@ -1158,7 +1122,9 @@ abstract class _Comment extends \IPS\Content
{
$oldAuthor = $this->author();
if( $oldAuthor->member_id == $newAuthor->member_id )
/* If we delete a member, then change author, the old author returns 0 as does the new author as the
member row is deleted before the task is run */
if( $newAuthor->member_id and ( $oldAuthor->member_id == $newAuthor->member_id ) )
{
return;
}
+44 -7
View File
@@ -700,6 +700,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
{
$this->container()->resetCommentCounts();
$this->container()->setLastComment();
$this->container()->setLastReview();
$this->container()->save();
}
}
@@ -756,13 +757,15 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
/* Save the changes */
$this->save();
/* Reindex the now hidden content */
if ( $this instanceof \IPS\Content\Item and static::$firstCommentRequired )
/* Reindex the now hidden content - if this is a content item with comments or reviews, then make sure to do those too. */
if ( $this instanceof \IPS\Content\Item AND ( isset( static::$commentClass ) OR isset( static::$reviewClass ) ) )
{
\IPS\Content\Search\Index::i()->index( $this->firstComment() );
\IPS\Content\Search\Index::i()->index( ( static::$firstCommentRequired ) ? $this->firstComment() : $this );
\IPS\Content\Search\Index::i()->indexSingleItem( $this );
}
else
{
/* Either this is a comment / review, or the item doesn't support comments or reviews, so we can just reindex it now. */
\IPS\Content\Search\Index::i()->index( $this );
}
@@ -774,6 +777,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
{
$this->container()->resetCommentCounts();
$this->container()->setLastComment();
$this->container()->setLastReview();
$this->container()->save();
}
}
@@ -980,11 +984,11 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
if ( $log['sdl_obj_member_id'] )
{
$this->hiddenBlurb = \IPS\Member::loggedIn()->language()->addToStack('hidden_blurb', FALSE, array( 'sprintf' => array( \IPS\Member::load( $log['sdl_obj_member_id'] )->name, \IPS\DateTime::ts( $log['sdl_obj_date'] )->relative(), \IPS\Member::loggedIn()->language()->addToStack( $log['sdl_obj_reason'] ) ?: \IPS\Member::loggedIn()->language()->addToStack('hidden_no_reason') ) ) );
$this->hiddenBlurb = \IPS\Member::loggedIn()->language()->addToStack('hidden_blurb', FALSE, array( 'sprintf' => array( \IPS\Member::load( $log['sdl_obj_member_id'] )->name, \IPS\DateTime::ts( $log['sdl_obj_date'] )->relative(), $log['sdl_obj_reason'] ?: \IPS\Member::loggedIn()->language()->addToStack('hidden_no_reason') ) ) );
}
else
{
$this->hiddenBlurb = \IPS\Member::loggedIn()->language()->addToStack('hidden_blurb_no_member', FALSE, array( 'sprintf' => array( \IPS\DateTime::ts( $log['sdl_obj_date'] )->relative(), \IPS\Member::loggedIn()->language()->addToStack( $log['sdl_obj_reason'] ) ?: \IPS\Member::loggedIn()->language()->addToStack('hidden_no_reason') ) ) );
$this->hiddenBlurb = \IPS\Member::loggedIn()->language()->addToStack('hidden_blurb_no_member', FALSE, array( 'sprintf' => array( \IPS\DateTime::ts( $log['sdl_obj_date'] )->relative(), $log['sdl_obj_reason'] ?: \IPS\Member::loggedIn()->language()->addToStack('hidden_no_reason') ) ) );
}
}
@@ -1219,6 +1223,22 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
return $index;
}
/**
* Change IP Address
* @param string $ip The new IP address
*
* @return void
*/
public function changeIpAddress( $ip )
{
if ( isset( static::$databaseColumnMap['ip_address'] ) )
{
$col = static::$databaseColumnMap['ip_address'];
$this->$col = (string) $ip;
$this->save();
}
}
/**
* Change Author
*
@@ -1229,7 +1249,9 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
{
$oldAuthor = $this->author();
if( $oldAuthor->member_id == $newAuthor->member_id )
/* If we delete a member, then change author, the old author returns 0 as does the new author as the
member row is deleted before the task is run */
if( $newAuthor->member_id and ( $oldAuthor->member_id == $newAuthor->member_id ) )
{
return;
}
@@ -1503,6 +1525,21 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
}
/**
* Prune IP addresses from content
*
* @param int $days Remove from content posted older than DAYS ago
* @return void
*/
public static function pruneIpAddresses( $days=0 )
{
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 ) );
}
}
/* !Follow */
const FOLLOW_PUBLIC = 1;
@@ -1813,7 +1850,7 @@ abstract class _Content extends \IPS\Patterns\ActiveRecord
}
/* We have to send a limit even though we want all records because otherwise the Database store does not return all columns */
foreach( \IPS\Session\Store::i()->getOnlineUsers( 0, 'desc', array( 0, 5000 ), NULL, TRUE, TRUE ) as $session )
foreach( \IPS\Session\Store::i()->getOnlineUsers( 0, 'desc', array( 0, 5000 ), NULL, TRUE ) as $session )
{
if( mb_strpos( $session['location_url'], (string) $item->url() ) === 0 )
{
+38 -5
View File
@@ -423,9 +423,21 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
{
$class = static::$contentModel;
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
if ( !$item->canEdit() and !\IPS\Request::i()->form_submitted ) // We check if the form has been submitted to prevent the user loosing their content
// We check if the form has been submitted to prevent the user loosing their content
if ( isset( \IPS\Request::i()->form_submitted ) )
{
throw new \OutOfRangeException;
if ( ! $item->couldEdit() )
{
throw new \OutOfRangeException;
}
}
else
{
if ( ! $item->canEdit() )
{
throw new \OutOfRangeException;
}
}
$container = NULL;
@@ -639,12 +651,23 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
if ( !$item->canEditTitle() )
{
throw new \DomainException;
throw new \RuntimeException;
}
$oldTitle = $item->mapped( 'title' );
$titleField = $item::$databaseColumnMap['title'];
$maxLength = \IPS\Settings::i()->max_title_length ?: 255;
$titleField = $item::$databaseColumnMap['title'];
if( \strlen( \IPS\Request::i()->newTitle ) > $maxLength )
{
throw new \LengthException( \IPS\Member::loggedIn()->language()->addToStack( 'form_maxlength', FALSE, array( 'pluralize' => array( $maxLength ) ) ) );
}
elseif( !trim( \IPS\Request::i()->newTitle ) )
{
throw new \InvalidArgumentException('form_required');
}
$item->$titleField = \IPS\Request::i()->newTitle;
$idField = $item::$databaseColumnId;
$item->save();
@@ -680,6 +703,10 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->json( 'OK' );
}
catch( \LogicException $e )
{
\IPS\Output::i()->error( $e->getMessage(), '2S136/1M', 403, '' );
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '2S136/11', 404, '' );
@@ -2020,6 +2047,11 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
$url = $url->setQueryString( 'showDeleted', 1 );
}
if ( isset( \IPS\Request::i()->_report ) )
{
$url = $url->setQueryString( '_report', \IPS\Request::i()->_report );
}
/* And redirect */
\IPS\Output::i()->redirect( $url->setFragment( $fragment . '-' . $comment->$idColumn ) );
}
@@ -2333,6 +2365,7 @@ class _Controller extends \IPS\Helpers\CoverPhoto\Controller
if ( $item->container() )
{
$item->container()->setLastComment();
$this->container()->setLastReview();
$item->container()->save();
}
}
+138 -131
View File
@@ -933,6 +933,18 @@ abstract class _Item extends \IPS\Content
$field = $commentClass::$databaseColumnMap['edit_show'];
$commentObj->$field = 0;
}
/* Check if profanity filters should mod-queue this comment */
$sendNotifications = $commentObj->checkProfanityFilters( TRUE, TRUE );
/* Send notifications */
if ( $sendNotifications AND !in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
{
if( $commentObj->hidden() === 1 )
{
$commentObj->sendUnapprovedNotification();
}
}
}
$oldValue = $commentObj->$column;
@@ -1231,20 +1243,47 @@ abstract class _Item extends \IPS\Content
public function contentImages( $limit = NULL )
{
$idColumn = static::$databaseColumnId;
$internal = NULL;
$internal = array();
$attachments = array();
$loadedExtensions = array();
/* Get attachments from the content, or all comments */
if ( isset( static::$databaseColumnMap['content'] ) or isset( static::$commentClass ) )
{
$internal = \IPS\Db::i()->select( 'attachment_id', 'core_attachments_map', array( 'location_key=? and id1=?', static::$application . '_' . mb_ucfirst( static::$module ), $this->$idColumn ) );
$internal = iterator_to_array( \IPS\Db::i()->select( '*', 'core_attachments_map', array( 'location_key=? and id1=?', static::$application . '_' . mb_ucfirst( static::$module ), $this->$idColumn ) )->setKeyField('attachment_id') );
}
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'] );
foreach( \IPS\Db::i()->select( '*', 'core_attachments', array( array( \IPS\Db::i()->in( 'attach_id', array_keys( $internal ) ) ), array( 'attach_is_image=1' ) ), 'attach_id ASC', $limit ) as $row )
{
$map = $internal[ $row['attach_id'] ];
if ( !isset( $loadedExtensions[ $map['location_key'] ] ) )
{
$exploded = explode( '_', $map['location_key'] );
try
{
$extensions = \IPS\Application::load( $exploded[0] )->extensions( 'core', 'EditorLocations' );
if ( isset( $extensions[ $exploded[1] ] ) )
{
$loadedExtensions[ $map['location_key'] ] = $extensions[ $exploded[1] ];
}
}
catch ( \OutOfRangeException $e ) { }
}
if ( isset( $loadedExtensions[ $map['location_key'] ] ) )
{
try
{
if ( $loadedExtensions[ $map['location_key'] ]->attachmentPermissionCheck( \IPS\Member::loggedIn(), $map['id1'], $map['id2'], $map['id3'], $row, TRUE ) )
{
$attachments[] = array( 'core_Attachment' => $row['attach_location'] );
}
}
catch ( \Exception $e ) { }
}
}
}
@@ -1285,9 +1324,9 @@ abstract class _Item extends \IPS\Content
{
$return = parent::content();
}
elseif( static::$firstCommentRequired )
elseif( static::$firstCommentRequired AND $comment = $this->firstComment() )
{
$return = $this->firstComment()->content();
$return = $comment->content();
}
else
{
@@ -1505,29 +1544,18 @@ abstract class _Item extends \IPS\Content
/* Add to search index */
if ( $this instanceof \IPS\Content\Searchable )
{
if ( $this instanceof \IPS\Content\Item and static::$firstCommentRequired )
if ( $this instanceof \IPS\Content\Item AND ( isset( static::$commentClass ) OR isset( static::$reviewClass ) ) )
{
\IPS\Content\Search\Index::i()->index( $this->firstComment() );
\IPS\Content\Search\Index::i()->index( ( static::$firstCommentRequired ) ? $this->firstComment() : $this );
\IPS\Content\Search\Index::i()->indexSingleItem( $this );
}
else
{
/* Either this is a comment / review, or the item doesn't support comments or reviews, so we can just reindex it now. */
\IPS\Content\Search\Index::i()->index( $this );
}
}
$idColumn = static::$databaseColumnId;
foreach ( array( 'commentClass', 'reviewClass' ) as $class )
{
if ( isset( static::$$class ) )
{
$className = static::$$class;
if ( in_array( 'IPS\Content\Searchable', class_implements( $className ) ) )
{
\IPS\Content\Search\Index::i()->massUpdate( $className, NULL, $this->$idColumn, $this->searchIndexPermissions(), NULL, $container->_id );
}
}
}
/* Update caches */
$this->expireWidgetCaches();
$this->adjustSessions();
@@ -1782,11 +1810,11 @@ abstract class _Item extends \IPS\Content
$existingFlag = static::$useWriteServer;
static::$useWriteServer = TRUE;
$firstComment = $this->comments( 1, 0, 'date', 'asc', NULL, static::$firstCommentRequired ?: FALSE, NULL, NULL, TRUE );
$idColumn = static::$databaseColumnId;
if ( isset( static::$commentClass ) )
{
$firstComment = $this->comments( 1, 0, 'date', 'asc', NULL, static::$firstCommentRequired ?: FALSE, NULL, NULL, TRUE );
$idColumn = static::$databaseColumnId;
$commentClass = static::$commentClass;
$commentIdColumn = $commentClass::$databaseColumnId;
@@ -1897,6 +1925,7 @@ abstract class _Item extends \IPS\Content
/* Update container */
$this->container()->resetCommentCounts();
$this->container()->setLastComment();
$this->container()->setLastReview();
$this->container()->save();
}
@@ -1922,31 +1951,26 @@ abstract class _Item extends \IPS\Content
\IPS\Db::i()->delete( 'core_notifications', array( 'item_class=? AND item_id=?', (string) get_class( $this ), (int) $this->$idColumn ) );
foreach ( array( 'commentClass', 'reviewClass' ) as $class )
if ( $this instanceof \IPS\Content\Searchable )
{
if ( isset( static::$$class ) )
if ( $this instanceof \IPS\Content\Item AND ( isset( static::$commentClass ) OR isset( static::$reviewClass ) ) )
{
$className = static::$$class;
if ( in_array( 'IPS\Content\Hideable', class_implements( $className ) ) AND isset( $className::$databaseColumnMap['hidden'] ) )
$firstComment = NULL;
if ( static::$firstCommentRequired AND isset( static::$commentClass ) )
{
\IPS\Db::i()->update( $className::$databaseTable, array( $className::$databasePrefix . $className::$databaseColumnMap['hidden'] => 2 ), array( $className::$databasePrefix . $className::$databaseColumnMap['item'] . '=? AND ' . $className::$databasePrefix . $className::$databaseColumnMap['hidden'] . '=?', $this->$idColumn, 0 ) );
}
if ( in_array( 'IPS\Content\Searchable', class_implements( $className ) ) )
{
\IPS\Content\Search\Index::i()->massUpdate( $className, NULL, $this->$idColumn, NULL, 2 );
if ( static::$firstCommentRequired )
{
$firstComment = $this->comments( 1, NULL, 'date', 'asc' );
if( $firstComment )
{
$column = $className::$databaseColumnMap['hidden'];
$firstComment->$column = 2;
\IPS\Content\Search\Index::i()->index( $firstComment );
}
}
$className = static::$commentClass;
$firstComment = $this->firstComment();
$column = $className::$databaseColumnMap['hidden'];
$firstComment->$column = 2;
}
\IPS\Content\Search\Index::i()->index( ( static::$firstCommentRequired ) ? $firstComment : $this );
\IPS\Content\Search\Index::i()->indexSingleItem( $this );
}
else
{
/* Either this is a comment / review, or the item doesn't support comments or reviews, so we can just reindex it now. */
\IPS\Content\Search\Index::i()->index( $this );
}
}
@@ -2008,27 +2032,26 @@ abstract class _Item extends \IPS\Content
parent::unhide( $member );
/* And then update the search index */
if ( isset( static::$commentClass ) and static::$firstCommentRequired AND $this->mapped('first_comment_id') )
if ( $this instanceof \IPS\Content\Searchable )
{
$commentClass = static::$commentClass;
/* We have to do it this way because of R/W Separation */
$firstComment = $this->firstComment();
$column = $commentClass::$databaseColumnMap['hidden'];
$firstComment->$column = 0;
\IPS\Content\Search\Index::i()->index( $firstComment );
}
foreach ( array( 'commentClass', 'reviewClass' ) as $class )
{
if ( isset( static::$$class ) )
if ( $this instanceof \IPS\Content\Item AND ( isset( static::$commentClass ) OR isset( static::$reviewClass ) ) )
{
$className = static::$$class;
if ( in_array( 'IPS\Content\Searchable', class_implements( $className ) ) )
$firstComment = NULL;
if ( static::$firstCommentRequired AND isset( static::$commentClass ) )
{
\IPS\Content\Search\Index::i()->massUpdate( $className, NULL, $this->$idColumn, NULL, 0 );
$className = static::$commentClass;
$firstComment = $this->firstComment();
$column = $className::$databaseColumnMap['hidden'];
$firstComment->$column = 0;
}
\IPS\Content\Search\Index::i()->index( ( static::$firstCommentRequired ) ? $firstComment : $this );
\IPS\Content\Search\Index::i()->indexSingleItem( $this );
}
else
{
/* Either this is a comment / review, or the item doesn't support comments or reviews, so we can just reindex it now. */
\IPS\Content\Search\Index::i()->index( $this );
}
}
@@ -2247,6 +2270,28 @@ abstract class _Item extends \IPS\Content
}
}
/**
* Change IP Address
* @param string $ip The new IP address
*
* @return void
*/
public function changeIpAddress( $ip )
{
parent::changeIpAddress( $ip );
/* How about a required comment? */
if ( isset( static::$commentClass ) and static::$firstCommentRequired )
{
$commentClass = static::$commentClass;
if ( isset( static::$databaseColumnMap['first_comment_id'] ) AND $comment = $this->firstComment() )
{
$comment->changeIpAddress( $ip );
}
}
}
/**
* Change Author
*
@@ -2257,7 +2302,9 @@ abstract class _Item extends \IPS\Content
{
$oldAuthor = $this->author();
if( $oldAuthor->member_id == $newAuthor->member_id )
/* If we delete a member, then change author, the old author returns 0 as does the new author as the
member row is deleted before the task is run */
if( $newAuthor->member_id and ( $oldAuthor->member_id == $newAuthor->member_id ) )
{
return;
}
@@ -3297,7 +3344,7 @@ abstract class _Item extends \IPS\Content
$order = ( isset( $class::$databaseColumnMap[ $order ] ) ? ( $class::$databasePrefix . $class::$databaseColumnMap[ $order ] ) : $order ) . ' ' . $orderDirection;
}
$this->cachedReviews[ $cacheKey ] = $this->_comments( $class, $limit ?: static::$reviewsPerPage, $offset, $order, $member, $includeHiddenReviews, $cutoff, NULL, $extraWhereClause, $includeDeleted, $canViewWarn );
$this->cachedReviews[ $cacheKey ] = $this->_comments( $class, $limit ?: static::$reviewsPerPage, $offset, $order, $member, $includeHiddenReviews, $cutoff, $canViewWarn, $extraWhereClause, $includeDeleted );
return $this->cachedReviews[ $cacheKey ];
}
@@ -4233,7 +4280,7 @@ abstract class _Item extends \IPS\Content
public function canReview( $member=NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
if ( $member->member_group_id == \IPS\Settings::i()->guest_group or $member->restrict_post or ( $this instanceof \IPS\Content\Lockable and $this->locked() and ( !$member->member_id or !static::modPermission( 'reply_to_locked', $member, $this->container() ) ) ) )
if ( $member->member_group_id == \IPS\Settings::i()->guest_group or $member->restrict_post or ( $this instanceof \IPS\Content\Lockable and $this->locked() and ( !$member->member_id or !static::modPermission( 'reply_to_locked', $member, $this->containerWrapper() ) ) ) )
{
return FALSE;
}
@@ -4303,17 +4350,7 @@ abstract class _Item extends \IPS\Content
return FALSE;
}
$container = NULL;
if ( method_exists( $this, 'container' ) )
{
try
{
$container = $this->container();
}
catch ( \BadMethodCallException $e ) { }
}
return ( static::modPermission( 'reply_to_locked', $member, $container ) and $this->can( $type, $member ) );
return ( static::modPermission( 'reply_to_locked', $member, $this->containerWrapper() ) and $this->can( $type, $member ) );
}
/* Check permissions as normal */
@@ -4694,6 +4731,9 @@ abstract class _Item extends \IPS\Content
if ( $resync )
{
$existingFlag = static::$useWriteServer;
static::$useWriteServer = TRUE;
try
{
$comment = $this->comments( 1, 0, 'date', 'desc', NULL, FALSE, NULL, NULL, TRUE );
@@ -4770,6 +4810,8 @@ abstract class _Item extends \IPS\Content
}
}
}
static::$useWriteServer = $existingFlag;
}
}
@@ -4797,6 +4839,9 @@ abstract class _Item extends \IPS\Content
if ( $resync )
{
$existingFlag = static::$useWriteServer;
static::$useWriteServer = TRUE;
try
{
$review = $this->reviews( 1, 0, 'date', 'desc', NULL, FALSE );
@@ -4856,6 +4901,8 @@ abstract class _Item extends \IPS\Content
}
}
}
static::$useWriteServer = $existingFlag;
}
}
@@ -5408,7 +5455,7 @@ abstract class _Item extends \IPS\Content
}
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and static::modPermission( 'pin', $member, $this->container() ) );
return ( $member->member_id and static::modPermission( 'pin', $member, $this->containerWrapper() ) );
}
/**
@@ -5425,7 +5472,7 @@ abstract class _Item extends \IPS\Content
}
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and static::modPermission( 'unpin', $member, $this->container() ) );
return ( $member->member_id and static::modPermission( 'unpin', $member, $this->containerWrapper() ) );
}
/**
@@ -5442,7 +5489,7 @@ abstract class _Item extends \IPS\Content
}
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and static::modPermission( 'feature', $member, $this->container() ) );
return ( $member->member_id and static::modPermission( 'feature', $member, $this->containerWrapper() ) );
}
/**
@@ -5459,7 +5506,7 @@ abstract class _Item extends \IPS\Content
}
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and static::modPermission( 'unfeature', $member, $this->container() ) );
return ( $member->member_id and static::modPermission( 'unfeature', $member, $this->containerWrapper() ) );
}
/**
@@ -5499,20 +5546,10 @@ abstract class _Item extends \IPS\Content
{
return FALSE;
}
$container = NULL;
if ( method_exists( $this, 'container' ) )
{
try
{
$container = $this->container();
}
catch ( \BadMethodCallException $e ) { }
}
$member = $member ?: \IPS\Member::loggedIn();
if( $member->member_id and static::modPermission( 'lock', $member, $container ) )
if( $member->member_id and static::modPermission( 'lock', $member, $this->containerWrapper() ) )
{
return TRUE;
}
@@ -5537,20 +5574,10 @@ abstract class _Item extends \IPS\Content
{
return FALSE;
}
$container = NULL;
if ( method_exists( $this, 'container' ) )
{
try
{
$container = $this->container();
}
catch ( \BadMethodCallException $e ) { }
}
$member = $member ?: \IPS\Member::loggedIn();
if( $member->member_id and static::modPermission( 'unlock', $member, $container ) )
if( $member->member_id and static::modPermission( 'unlock', $member, $this->containerWrapper() ) )
{
return TRUE;
}
@@ -5576,18 +5603,8 @@ abstract class _Item extends \IPS\Content
return FALSE;
}
$container = NULL;
if ( method_exists( $this, 'container' ) )
{
try
{
$container = $this->container();
}
catch ( \BadMethodCallException $e ) { }
}
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and ( static::modPermission( 'hide', $member, $container ) or ( $member->member_id == $this->author()->member_id and ( $member->group['g_hide_own_posts'] == '1' or in_array( get_class( $this ), explode( ',', $member->group['g_hide_own_posts'] ) ) ) ) ) );
return ( $member->member_id and ( static::modPermission( 'hide', $member, $this->containerWrapper() ) or ( $member->member_id == $this->author()->member_id and ( $member->group['g_hide_own_posts'] == '1' or in_array( get_class( $this ), explode( ',', $member->group['g_hide_own_posts'] ) ) ) ) ) );
}
/**
@@ -5609,18 +5626,8 @@ abstract class _Item extends \IPS\Content
return FALSE;
}
$container = NULL;
if ( method_exists( $this, 'container' ) )
{
try
{
$container = $this->container();
}
catch ( \BadMethodCallException $e ) { }
}
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and ( static::modPermission( 'unhide', $member, $container ) ) );
return ( $member->member_id and ( static::modPermission( 'unhide', $member, $this->containerWrapper() ) ) );
}
/**
@@ -5719,7 +5726,7 @@ abstract class _Item extends \IPS\Content
try
{
return ( $member->member_id and $this->container() and ( static::modPermission( 'move', $member, $this->container() ) ) );
return ( $member->member_id and $this->container() and ( static::modPermission( 'move', $member, $this->containerWrapper() ) ) );
}
catch( \BadMethodCallException $e )
{
@@ -5738,7 +5745,7 @@ abstract class _Item extends \IPS\Content
if ( static::$firstCommentRequired )
{
$member = $member ?: \IPS\Member::loggedIn();
return ( $member->member_id and ( static::modPermission( 'split_merge', $member, $this->container() ) ) );
return ( $member->member_id and ( static::modPermission( 'split_merge', $member, $this->containerWrapper() ) ) );
}
return FALSE;
}
@@ -5768,7 +5775,7 @@ abstract class _Item extends \IPS\Content
/* What about this? */
try
{
return static::modPermission( 'delete', $member, $this->container() );
return static::modPermission( 'delete', $member, $this->containerWrapper() );
}
catch ( \BadMethodCallException $e )
{
+56 -18
View File
@@ -40,19 +40,10 @@ class _Facebook extends PromoteAbstract
'tags' => NULL,
'image' => NULL,
'last_sync' => 0,
'shareable' => array()
'shareable' => array(),
'member_token' => array(),
);
/**
* Is connected?
*
* @return bool
*/
public function connected()
{
return ( $this->member->fb_uid and $this->member->fb_token );
}
/**
* Get image
*
@@ -103,7 +94,7 @@ class _Facebook extends PromoteAbstract
*/
public function canPostToPage()
{
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
$facebook = static::getLoginHandler();
$authorizedScopes = $facebook->authorizedScopes( $this->member );
@@ -112,7 +103,7 @@ class _Facebook extends PromoteAbstract
return FALSE;
}
foreach( array( 'user_managed_groups', 'manage_pages', 'publish_pages', 'publish_actions' ) as $perm )
foreach( array( 'publish_to_groups', 'manage_pages', 'publish_pages' ) as $perm )
{
if ( ! in_array( $perm, $authorizedScopes ) )
{
@@ -131,7 +122,7 @@ class _Facebook extends PromoteAbstract
*/
protected static function appSecretProof( $token )
{
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
$facebook = static::getLoginHandler();
return hash_hmac( 'sha256', $token, $facebook->settings['client_secret'] );
}
@@ -218,7 +209,7 @@ class _Facebook extends PromoteAbstract
$settings = $promote->form_data['facebook'];
$shareable = $this->settings['shareable'];
$responses = array();
foreach( $settings['shareable'] as $id )
{
$feedId = mb_substr( $id, 2 );
@@ -229,7 +220,7 @@ class _Facebook extends PromoteAbstract
}
else
{
$responses[ $id ][] = $this->_post( $promote, $photos, $feedId, $this->settings['token'] );
$responses[ $id ][] = $this->_post( $promote, $photos, $feedId, isset( $this->settings['member_token']['access_token'] ) ? $this->settings['member_token']['access_token'] : $this->settings['token'] );
}
}
@@ -292,14 +283,14 @@ class _Facebook extends PromoteAbstract
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $feedId . "/photos" )->request()->post( $this->_addToken( array(
'message' => $promote->text['facebook'],
'url' => (string) $this->returnUrlWithProtocol( $thePhoto->url ),
'link' => $promote->short_link
'link' => (string) $promote->short_link
), $token ) )->decodeJson();
}
else
{
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $feedId . "/feed" )->request()->post( $this->_addToken( array(
'message' => $promote->text['facebook'],
'link' => $promote->short_link
'link' => (string) $promote->short_link
), $token ) )->decodeJson();
}
}
@@ -315,6 +306,11 @@ class _Facebook extends PromoteAbstract
}
else
{
if ( isset( $response['error'] ) )
{
\IPS\Log::log( $response['error']['message'], 'facebook' );
}
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('facebook_publish_exception') );
}
}
@@ -400,6 +396,30 @@ class _Facebook extends PromoteAbstract
throw new \InvalidArgumentException();
}
/**
* Is this member connected to the Facebook app?
*
* @param \IPS\Member $member A member object
* @return boolean
*/
public function isConnected( $member )
{
if ( \is_numeric( \IPS\Settings::i()->promote_facebook_auth ) )
{
/* Standard handler */
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
return $facebook->canProcess( $member );
}
/* Custom */
if ( isset( $this->settings['member_token']['access_token'] ) )
{
return TRUE;
}
return FALSE;
}
/**
* Ensure the URL is not protocol relative
*
@@ -414,4 +434,22 @@ class _Facebook extends PromoteAbstract
return $url;
}
/**
* Wrapper to Facebook log in handler with the correct settings
*
* @return \IPS\Login object
*/
public static function getLoginHandler()
{
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
/* We are using the default app here */
if ( ! \is_numeric( \IPS\Settings::i()->promote_facebook_auth ) )
{
$facebook->settings = json_decode( \IPS\Settings::i()->promote_facebook_auth, TRUE );
}
return $facebook;
}
}
+2 -1
View File
@@ -139,7 +139,8 @@ abstract class _PromoteAbstract extends \IPS\Patterns\ActiveRecord
*/
public function get_settings()
{
return array_merge( $this->defaultSettings, json_decode( $this->_data['settings'], TRUE ) );
$settings = json_decode( $this->_data['settings'], TRUE );
return ( $settings ? array_merge( $this->defaultSettings, $settings ) : $this->defaultSettings );
}
/**
+4 -4
View File
@@ -191,16 +191,16 @@ 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 $member )
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[ $member ] = $member;
$memberIds[ $memberToRecount ] = $memberToRecount;
}
\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 $member )
foreach( $memberIds as $memberToRecount )
{
\IPS\Member::load( $member )->recountNotifications();
\IPS\Member::load( $memberToRecount )->recountNotifications();
}
/* Reset some cached values */
+15
View File
@@ -125,6 +125,21 @@ class _ContentFilter
return $obj;
}
/**
* Constructor
* init() adds in review classes, comment classes, etc. But if we want to filter based on just the comment class, we need this method
*
* @param string $class The class
* @return \IPS\Content\Search\ContentFilter
*/
public static function initWithSpecificClass( $class )
{
$obj = new static;
$obj->classes = array( $class );
return $obj;
}
/**
* Only include results in containers
*
+234 -103
View File
@@ -47,7 +47,10 @@ class _Index extends \IPS\Content\Search\Index
{
$this->url->request()->delete();
$this->url->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->put( json_encode( array(
'mappings' => array(
'settings' => array(
'max_result_window' => \IPS\Settings::i()->search_index_maxresults
),
'mappings' => array(
'content' => array(
'properties' => array(
'index_class' => array( 'type' => 'keyword' ),
@@ -145,17 +148,87 @@ class _Index extends \IPS\Content\Search\Index
try
{
$class = get_class( $object );
/* Do not allow hidden comments to be flagged as latest */
if ( $object instanceof \IPS\Content\Comment and $indexData['index_is_last_comment'] and $indexData['index_item_id'] and $indexData['index_hidden'] !== 0 ) //
$existingData = NULL;
$existingIndexId = NULL;
$resetLastComment = FALSE;
try
{
$indexData['index_is_last_comment'] = false;
$r = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/' . $this->getIndexId( $object ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get()->decodeJson();
if ( $r['found'] )
{
$existingData = $r['_source'];
$existingIndexId = $r['_id'];
}
}
catch( \Exception $e ) { }
if ( $object instanceof \IPS\Content\Comment and $existingIndexId and $existingData['index_is_last_comment'] and $indexData['index_is_last_comment'] and $indexData['index_item_id'] and $indexData['index_hidden'] !== 0 )
{
/* We do not allow hidden or needing approval comments to become flagged as the last comment as this means users without hidden view permission never see the item in an item only stream */
$indexData['index_is_last_comment'] = false;
$resetLastComment = TRUE;
}
else if ( $indexData['index_is_last_comment'] and $indexData['index_item_id'] )
{
$classes = array( $class );
/* If this is the latest comment, unflag what was set before on both item and comment */
if ( $object instanceof \IPS\Content\Comment )
{
$itemClass = $object::$itemClass;
if ( ! $itemClass::$firstCommentRequired )
{
$classes[] = $itemClass;
}
if ( isset( $itemClass::$reviewClass ) )
{
$classes[] = $itemClass::$reviewClass;
}
}
else if ( $object instanceof \IPS\Content\Item )
{
if ( isset( $class::$commentClass ) )
{
$classes[] = $class::$commentClass;
}
if ( isset( $class::$reviewClass ) )
{
$classes[] = $class::$reviewClass;
}
}
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_is_last_comment = false;",
'lang' => 'painless'
),
'query' => array(
'bool' => array(
'must' => array(
array(
'terms' => array(
'index_class' => $classes
)
),
array(
'term' => array(
'index_item_id' => $indexData['index_item_id']
)
),
)
)
)
) ) );
}
/* Insert into index */
$r = $this->url
->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/' . $this->getIndexId( $object ) )
->request()
->request( \IPS\LONG_REQUEST_TIMEOUT )
->setHeaders( array( 'Content-Type' => 'application/json' ) )
->put( json_encode( $indexData ) );
@@ -174,6 +247,11 @@ class _Index extends \IPS\Content\Search\Index
{
\IPS\Log::log( $e, 'elasticsearch' );
}
if ( $resetLastComment )
{
$this->resetLastComment( array( $indexData['index_class'] ), $indexData['index_item_id'] );
}
}
}
}
@@ -198,7 +276,7 @@ class _Index extends \IPS\Content\Search\Index
$classes[] = $class::$reviewClass;
}
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_views += ". intval( $count ) . ";",
'lang' => 'painless'
@@ -221,6 +299,44 @@ class _Index extends \IPS\Content\Search\Index
)
) ) );
}
/**
* Clear out any tasks associated with the search index method
*
* @return void
*/
public function clearTasks()
{
try
{
/* This request *intentionally* goes to _tasks and not (ourpath)/_tasks */
$response = $this->url->setPath( '/_tasks' )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->get()->decodeJson();
foreach( $response['nodes'] as $nodeId => $nodeData )
{
foreach( $nodeData['tasks'] as $taskId => $taskData )
{
/* We only need to worry about deleting parent tasks */
if( isset( $taskData['parent_task_id'] ) )
{
continue;
}
/* If the task is cancellable it isn't finished yet */
if( $taskData['cancellable'] === TRUE )
{
continue;
}
$this->url->setPath( '/.tasks/task' . $taskId )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->delete();
}
}
}
catch( \Exception $e )
{
\IPS\Log::log( $e, 'elasticsearch' );
}
}
/**
* Get the comment / review counts for an item
@@ -296,7 +412,7 @@ class _Index extends \IPS\Content\Search\Index
{
$updates[] = "ctx._source.index_is_last_comment = ( ctx._id == '{$lastCommentIndexId}' );";
}
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request( \IPS\LONG_REQUEST_TIMEOUT )->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => implode( ' ', $updates ),
'lang' => 'painless'
@@ -356,7 +472,7 @@ class _Index extends \IPS\Content\Search\Index
if ( isset( $class::$commentClass ) )
{
$commentClass = $class::$commentClass;
$response = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$response = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'query' => array(
'bool' => array(
'must' => array(
@@ -379,7 +495,7 @@ class _Index extends \IPS\Content\Search\Index
if ( isset( $class::$reviewClass ) )
{
$reviewClass = $class::$reviewClass;
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'query' => array(
'bool' => array(
'must' => array(
@@ -455,13 +571,13 @@ class _Index extends \IPS\Content\Search\Index
);
}
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'query' => $query
) ) );
}
else
{
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'query' => array(
'term' => array(
'index_class' => $class
@@ -558,7 +674,7 @@ class _Index extends \IPS\Content\Search\Index
if ( count( $updates ) )
{
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => implode( ' ', $updates ),
'lang' => 'painless'
@@ -578,7 +694,7 @@ class _Index extends \IPS\Content\Search\Index
)
);
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_permissions.add( 'm.' + ctx._source.index_author );",
'lang' => 'painless'
@@ -595,7 +711,7 @@ class _Index extends \IPS\Content\Search\Index
{
$conditions['must'][] = array(
'term' => array(
'index_item_author' => '0'
'index_hidden' => 0
)
);
}
@@ -603,14 +719,14 @@ class _Index extends \IPS\Content\Search\Index
{
$conditions['must'][] = array(
'term' => array(
'index_item_author' => '2'
'index_hidden' => 2
)
);
}
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_permissions = " . intval( $newHiddenStatus ) . ";",
'inline' => "ctx._source.index_hidden = " . intval( $newHiddenStatus ) . ";",
'lang' => 'painless'
),
'query' => array(
@@ -706,7 +822,7 @@ class _Index extends \IPS\Content\Search\Index
{
try
{
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_delete_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'query' => array(
'range' => array(
'index_date_updated' => array(
@@ -739,7 +855,7 @@ class _Index extends \IPS\Content\Search\Index
try
{
/* Remove the flag */
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_is_last_comment = false;",
'lang' => 'painless'
@@ -763,76 +879,66 @@ class _Index extends \IPS\Content\Search\Index
) ) );
/* Get the latest comment */
$latest = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
'query' => array(
'bool' => array(
'must' => array(
array(
'terms' => array(
'index_class' => $classes
)
),
array(
'term' => array(
'index_item_id' => $indexItemId
)
),
array(
'term' => array(
'index_hidden' => 0
)
),
)
)
),
'sort' => array(
array(
'index_date_created' => 'desc'
)
),
'size' => 1
) ) )->decodeJson();
/* If we got it... */
if ( $latest['hits']['total'] )
$itemClass = NULL;
foreach ( $classes as $class )
{
$result = $latest['hits']['hits'][0];
/* Set that it is the latest comment */
$r = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/' . $result['_type'] . '/' . $result['_id'] . '/_update' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'doc' => array(
'index_is_last_comment' => true
)
) ) );
/* And set the updated time on the main item (done as _update_by_query because it might not exist if the first comment is required) */
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( 'conflicts', 'proceed' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_date_updated = " . intval( $latest['_source']['index_date_updated'] ) ."; ctx._source.index_date_commented = " . intval( $latest['_source']['index_date_commented'] ) .";",
'lang' => 'painless'
),
'query' => array(
'bool' => array(
'must' => array(
array(
'terms' => array(
'index_class' => $classes
)
),
array(
'term' => array(
'index_item_id' => $indexItemId
)
),
array(
'term' => array(
'index_object_id' => $indexItemId
)
),
if ( in_array( 'IPS\Content\Item', class_parents( $class ) ) )
{
$itemClass = $class;
break;
}
elseif ( isset( $class::$itemClass ) )
{
$itemClass = $class::$itemClass;
}
}
if ( $itemClass )
{
try
{
$item = $itemClass::load( $indexItemId );
if ( $lastComment = $item->comments( 1, 0, 'date', 'desc', NULL, FALSE ) )
{
/* Set that it is the latest comment */
$r = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/' . $this->getIndexId( $lastComment ) . '/_update' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'doc' => array(
'index_is_last_comment' => true
)
)
)
) ) );
) ) );
/* And set the updated time on the main item (done as _update_by_query because it might not exist if the first comment is required) */
$indexDataForLastComment = $this->indexData( $lastComment );
$this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_update_by_query' )->setQueryString( array( 'conflicts' => 'proceed', 'wait_for_completion' => 'false' ) )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( array(
'script' => array(
'inline' => "ctx._source.index_date_updated = " . intval( $indexDataForLastComment['index_date_updated'] ) ."; ctx._source.index_date_commented = " . intval( $indexDataForLastComment['index_date_commented'] ) .";",
'lang' => 'painless'
),
'query' => array(
'bool' => array(
'must' => array(
array(
'terms' => array(
'index_class' => $classes
)
),
array(
'term' => array(
'index_item_id' => $indexItemId
)
),
array(
'term' => array(
'index_object_id' => $indexItemId
)
),
)
)
)
) ) );
}
}
catch ( \OutOfRangeException $e ) { }
}
}
catch ( \Exception $e )
@@ -852,23 +958,45 @@ class _Index extends \IPS\Content\Search\Index
{
try
{
$results = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
'query' => array(
'bool' => array(
'filter' => array(
array(
'terms' => array(
'index_item_index_id' => $itemIndexIds
),
/* Set the query */
$query = array(
'bool' => array(
'filter' => array(
array(
'terms' => array(
'index_item_index_id' => $itemIndexIds
),
array(
'term' => array(
'index_author' => $member->member_id
)
),
array(
'term' => array(
'index_author' => $member->member_id
)
)
)
)
);
/* Get the count */
$count = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
'size' => 0,
'query' => $query
) ) )->decodeJson();
if ( !$count['hits']['total'] )
{
return array();
}
/* Now get the unique item ids */
$results = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/content/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
'aggs' => array(
'itemIds' => array(
'terms' => array(
'field' => 'index_item_index_id',
'size' => $count['hits']['total']
)
)
),
'query' => $query
) ) )->decodeJson();
}
catch ( \Exception $e )
@@ -878,9 +1006,12 @@ class _Index extends \IPS\Content\Search\Index
}
$iPostedIn = array();
foreach ( $results['hits']['hits'] as $result )
foreach ( $results['aggregations']['itemIds']['buckets'] as $result )
{
$iPostedIn[] = $result['_source']['index_item_index_id'];
if ( $result['doc_count'] )
{
$iPostedIn[] = $result['key'];
}
}
return $iPostedIn;
+29 -8
View File
@@ -906,6 +906,12 @@ class _Query extends \IPS\Content\Search\Query
*/
public function search( $term = NULL, $tags = NULL, $method = 1, $operator = NULL )
{
/* If we're looking for more results than we can fetch, we don't need to ask Elastic Search */
if( ( $this->offset + $this->resultsToGet ) >= \IPS\Settings::i()->search_index_maxresults )
{
return new \IPS\Content\Search\Results( array(), 0 );
}
$operator = $operator ?: \IPS\Settings::i()->search_default_operator;
$must = array();
$filters = $this->filters;
@@ -924,11 +930,11 @@ class _Query extends \IPS\Content\Search\Query
$term = trim( $term, '"' );
if ( $method & static::TERM_TITLES_ONLY )
{
$searchConditions[] = array( 'match_phrase' => array( 'index_title' => array( 'query' => $term ), 'analyzer' => 'standard' ) );
$searchConditions[] = array( 'match_phrase' => array( 'index_title' => array( 'query' => $term ) ) );
}
else
{
$searchConditions[] = array( 'multi_match' => array( 'query' => $term, 'fields' => array( 'index_content', $titleField ), 'type' => 'phrase', 'analyzer' => 'standard' ) );
$searchConditions[] = array( 'multi_match' => array( 'query' => $term, 'fields' => array( 'index_content', $titleField ), 'type' => 'phrase' ) );
}
}
else
@@ -995,6 +1001,7 @@ class _Query extends \IPS\Content\Search\Query
/* Peform the search */
try
{
/* Initial query */
$query = array(
'bool' => array(
'must' => $must,
@@ -1003,6 +1010,7 @@ class _Query extends \IPS\Content\Search\Query
)
);
/* Add the time decay */
if ( \IPS\Settings::i()->search_decay_factor and !$this->sort )
{
$query = array(
@@ -1017,8 +1025,9 @@ class _Query extends \IPS\Content\Search\Query
)
);
}
if ( \IPS\Settings::i()->search_elastic_self_boost and $this->member->member_id )
/* Add the self boost */
if ( \IPS\Settings::i()->search_elastic_self_boost and $this->member->member_id and !$this->sort )
{
$query = array(
'function_score' => array(
@@ -1033,25 +1042,37 @@ class _Query extends \IPS\Content\Search\Query
);
}
$return = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( json_encode( array(
/* Build the JSON and validate it. Use JSON_PARTIAL_OUTPUT_ON_ERROR in case someone has used an unencodable value as
the term, and check json_encode() didn't return FALSE (which it may do on error) as a sanity check against
sending a blank query, which would return everything in the index */
$array = array(
'query' => $query,
'sort' => $this->sort ?: array(),
'from' => $this->offset,
'size' => $this->resultsToGet,
) ) )->decodeJson();
);
$json = json_encode( $array, JSON_PARTIAL_OUTPUT_ON_ERROR );
if ( $json === FALSE )
{
return new \IPS\Content\Search\Results( array(), 0 );
}
/* Make the call! */
$return = $this->url->setPath( $this->url->data[ \IPS\Http\Url::COMPONENT_PATH ] . '/_search' )->request()->setHeaders( array( 'Content-Type' => 'application/json' ) )->get( $json )->decodeJson();
if ( isset( $return['error'] ) )
{
\IPS\Log::log( print_r( $return['error'], TRUE ), 'elasticsearch' );
return new \IPS\Content\Search\Results( array(), 0 );
}
/* Set results */
return new \IPS\Content\Search\Results( array_map( function( $hit ) {
$indexData = $hit['_source'];
$indexData['index_permissions'] = implode( ',', $indexData['index_permissions'] );
$indexData['index_tags'] = $indexData['index_tags'] ? implode( ',', $indexData['index_tags'] ) : NULL;
return $indexData;
}, $return['hits']['hits'] ), $return['hits']['total'] );
}, $return['hits']['hits'] ), $return['hits']['total'] <= \IPS\Settings::i()->search_index_maxresults ? $return['hits']['total'] : (int) \IPS\Settings::i()->search_index_maxresults );
}
catch ( \Exception $e )
{
+49 -5
View File
@@ -39,7 +39,7 @@ abstract class _Index extends \IPS\Patterns\Singleton
{
if ( \IPS\Settings::i()->search_method == 'elastic' )
{
static::$instance = new \IPS\Content\Search\Elastic\Index( \IPS\Http\Url::external( \IPS\Settings::i()->search_elastic_server . '/' . \IPS\Settings::i()->search_elastic_index ) );
static::$instance = new \IPS\Content\Search\Elastic\Index( \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
}
else
{
@@ -59,7 +59,7 @@ abstract class _Index extends \IPS\Patterns\Singleton
{
if ( \IPS\Settings::i()->search_method == 'elastic' )
{
return new \IPS\Content\Search\Elastic\MassIndexer( \IPS\Http\Url::external( \IPS\Settings::i()->search_elastic_server . '/' . \IPS\Settings::i()->search_elastic_index ) );
return new \IPS\Content\Search\Elastic\MassIndexer( \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
}
else
{
@@ -104,6 +104,30 @@ abstract class _Index extends \IPS\Patterns\Singleton
}
}
/**
* Index a single items comments and reviews if applicable.
*
* @param \IPS\Content\Searchable $object The item to index
* @return void
*/
public function indexSingleItem( \IPS\Content\Searchable $object )
{
try
{
$idColumn = $object::$databaseColumnId;
if ( isset( $object::$commentClass ) AND is_subclass_of( $object::$commentClass, 'IPS\Content\Searchable' ) )
{
\IPS\Task::queue( 'core', 'IndexSingleItem', array( 'class' => $object::$commentClass, 'id' => $object->$idColumn, 'title' => $object->mapped('title'), 'url' => (string) $object->url() ), 5, TRUE );
}
if ( isset( $object::$reviewClass ) AND is_subclass_of( $object::$reviewClass, 'IPS\Content\Searchable' ) )
{
\IPS\Task::queue( 'core', 'IndexSingleItem', array( 'class' => $object::$reviewClass, 'id' => $object->$idColumn, 'title' => $object->mapped('title'), 'url' => (string) $object->url() ), 5, TRUE );
}
}
catch( \OutOfRangeException $e ) {}
}
/**
* Get index data
*
@@ -138,9 +162,19 @@ abstract class _Index extends \IPS\Patterns\Singleton
$itemClass = $class::$itemClass;
if ( $itemClass::$firstCommentRequired and $object->isFirst() )
{
$title = $object->item()->searchIndexTitle();
$tags = ( $object->item() instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? implode( ',', array_filter( $object->item()->tags() ) ) : NULL;
$prefix = ( $object->item() instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? $object->item()->prefix() : NULL;
try
{
$item = $object->item();
}
catch( \OutOfRangeException $ex )
{
/* Comment has no working item, return */
return NULL;
}
$title = $item->searchIndexTitle();
$tags = ( $item instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? implode( ',', array_filter( $item->tags() ) ) : NULL;
$prefix = ( $item instanceof \IPS\Content\Tags and \IPS\Settings::i()->tags_enabled ) ? $item->prefix() : NULL;
$isForItem = TRUE;
}
}
@@ -375,6 +409,16 @@ abstract class _Index extends \IPS\Patterns\Singleton
{
// Do nothing by default
}
/**
* Clear out any tasks associated with the search index method
*
* @return void
*/
public function clearTasks()
{
// Do nothing by default
}
/**
* Retrieve the search ID for an item
+4 -2
View File
@@ -484,8 +484,10 @@ class _Index extends \IPS\Content\Search\Index
{
if ( $cutoff )
{
\IPS\Db::i()->delete( 'core_search_index_item_map', array( 'index_item_id IN( ? )', \IPS\Db::i()->select( 'index_item_id', 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) ) ) );
\IPS\Db::i()->delete( 'core_search_index_tags', array( 'index_id IN( ? )', \IPS\Db::i()->select( 'index_id', 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) ) ) );
$prefix = \IPS\Db::i()->prefix;
\IPS\Db::i()->query( "DELETE {$prefix}core_search_index_item_map FROM {$prefix}core_search_index_item_map, {$prefix}core_search_index WHERE {$prefix}core_search_index_item_map.index_item_id={$prefix}core_search_index.index_item_id AND index_date_updated < " . $cutoff->getTimestamp() );
\IPS\Db::i()->query( "DELETE {$prefix}core_search_index_tags FROM {$prefix}core_search_index_tags, {$prefix}core_search_index WHERE {$prefix}core_search_index_tags.index_id={$prefix}core_search_index.index_id AND index_date_updated < " . $cutoff->getTimestamp() );
\IPS\Db::i()->delete( 'core_search_index', array( 'index_date_updated < ?', $cutoff->getTimestamp() ) );
}
else
+12 -9
View File
@@ -94,7 +94,7 @@ class _Query extends \IPS\Content\Search\Query
foreach ( $contentFilters as $filter )
{
$clause = array();
if ( $type )
if ( $type and $filter->itemClass )
{
$this->itemClasses[] = $filter->itemClass;
}
@@ -116,16 +116,19 @@ class _Query extends \IPS\Content\Search\Query
$clause[] = \IPS\Db::i()->in( 'index_container_id', $filter->containerIds, $filter->containerIdFilter === FALSE );
}
$itemClass = $filter->itemClass;
if ( isset( $itemClass::$containerNodeClass ) )
if ( $filter->itemClass )
{
$containerClass = $itemClass::$containerNodeClass;
$unsearchableIds = $containerClass::unsearchableNodeIds();
if ( $unsearchableIds != NULL )
$itemClass = $filter->itemClass;
if ( isset( $itemClass::$containerNodeClass ) )
{
$clause[] = \IPS\Db::i()->in( 'index_container_id', $unsearchableIds, TRUE );
}
$containerClass = $itemClass::$containerNodeClass;
$unsearchableIds = $containerClass::unsearchableNodeIds();
if ( $unsearchableIds != NULL )
{
$clause[] = \IPS\Db::i()->in( 'index_container_id', $unsearchableIds, TRUE );
}
}
}
/* Are we excluding certain container classes? */
+1 -1
View File
@@ -54,7 +54,7 @@ abstract class _Query
{
if ( \IPS\Settings::i()->search_method == 'elastic' )
{
return new \IPS\Content\Search\Elastic\Query( $member ?: \IPS\Member::loggedIn(), \IPS\Http\Url::external( \IPS\Settings::i()->search_elastic_server . '/' . \IPS\Settings::i()->search_elastic_index ) );
return new \IPS\Content\Search\Elastic\Query( $member ?: \IPS\Member::loggedIn(), \IPS\Http\Url::external( rtrim( \IPS\Settings::i()->search_elastic_server, '/' ) . '/' . \IPS\Settings::i()->search_elastic_index ) );
}
else
{
+8 -3
View File
@@ -119,8 +119,13 @@ class _Content extends \IPS\Content\Search\Result
*/
public function addToRssFeed( \IPS\Xml\Rss $document )
{
$class = $this->indexData['index_class'];
$object = $class::load( $this->indexData['index_object_id'] );
$document->addItem( $object instanceof \IPS\Content\Comment ? $object->item()->mapped('title') : $object->mapped('title'), $object->url(), $this->indexData['index_content'], \IPS\DateTime::ts( $this->indexData['index_date_created'] ) );
try
{
$class = $this->indexData['index_class'];
$object = $class::load( $this->indexData['index_object_id'] );
$document->addItem( $object instanceof \IPS\Content\Comment ? $object->item()->searchIndexTitle() : $object->searchIndexTitle(), $object->url(), $this->indexData['index_content'], \IPS\DateTime::ts( $this->indexData['index_date_created'] ) );
}
/* If the search result was orphaned, let us continue */
catch( \OutOfRangeException $e ){}
}
}
+1 -1
View File
@@ -546,7 +546,7 @@ class _Results extends \ArrayIterator
{
$extraItem = array_pop( $extraItems );
$mergeList = array_merge( array( $urlToThing ), $extraItem->getMergeData() );
$mergeList = array_filter( array_merge( array( $urlToThing ), $extraItem->getMergeData() ) );
$listToDisplay = $mergeList;
if( count( $mergeList ) > 3 )
+2 -34
View File
@@ -53,15 +53,12 @@ class _Facebook
*/
public static function canAutoshare()
{
if ( $method = \IPS\Login\Handler::findMethod( 'IPS\Login\Handler\OAuth2\Facebook' ) and $authorizedScopes = $method->authorizedScopes( \IPS\Member::loggedIn() ) )
{
return in_array( 'publish_actions', $authorizedScopes );
}
return FALSE;
}
/**
* 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]
@@ -69,26 +66,7 @@ class _Facebook
*/
public static function publish( $content, $url=null )
{
if ( static::canAutoshare() and $method = \IPS\Login\Handler::findMethod( 'IPS\Login\Handler\OAuth2\Facebook' ) )
{
try
{
if ( !$method->postToFacebook( \IPS\Member::loggedIn(), $content, $url ) )
{
throw new \Exception;
}
}
catch( \Exception $e )
{
\IPS\Log::log( \IPS\Member::loggedIn()->member_id . ': '. $e->getMessage(), 'facebook' );
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('facebook_publish_exception') );
}
}
else
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('facebook_publish_no_user') );
}
return FALSE;
}
/**
@@ -101,16 +79,6 @@ class _Facebook
public static function modifyForm( \IPS\Helpers\Form &$form, $service )
{
$form->add( new \IPS\Helpers\Form\Select( 'fbc_bot_group', \IPS\Settings::i()->fbc_bot_group, TRUE, array( 'options' => array_combine( array_keys( \IPS\Member\Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups() ) ) ) ) );
if ( \IPS\Login\Handler::findMethod( 'IPS\Login\Handler\OAuth2\Facebook' ) )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'share_autoshare_Facebook', $service->autoshare, false ) );
}
else
{
$form->add( new \IPS\Helpers\Form\YesNo( 'share_autoshare_Facebook', FALSE, false, array( 'disabled' => TRUE ) ) );
\IPS\Member::loggedIn()->language()->words['share_autoshare_Facebook_desc'] = \IPS\Member::loggedIn()->language()->addToStack('share_autoshare_Facebook_disabled');
}
}
/**
+2 -2
View File
@@ -44,7 +44,7 @@ abstract class _Widget extends \IPS\Widget\PermissionCache
}
/* Block title */
$form->add( new \IPS\Helpers\Form\Translatable( 'widget_feed_title', isset( $this->configuration['language_key'] ) ? NULL : \IPS\Member::loggedIn()->language()->addToStack( $class::$title . '_pl' ), FALSE, array( 'app' => 'cms', 'key' => ( isset( $this->configuration['language_key'] ) ? $this->configuration['language_key'] : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'widget_feed_title', isset( $this->configuration['language_key'] ) ? NULL : \IPS\Member::loggedIn()->language()->addToStack( $class::$title . '_pl' ), FALSE, array( 'app' => 'core', 'key' => ( isset( $this->configuration['language_key'] ) ? $this->configuration['language_key'] : NULL ) ) ) );
/* Container */
if ( isset( $class::$containerNodeClass ) )
@@ -357,7 +357,7 @@ abstract class _Widget extends \IPS\Widget\PermissionCache
$items = iterator_to_array( $class::getItemsWithPermission(
$where, /* Where clause */
( isset( $this->configuration['widget_feed_sort_on'] ) and isset( $this->configuration['widget_feed_sort_dir'] ) ) ? ( ( $this->configuration['widget_feed_sort_on'] == '_rand' ) ? $this->configuration['widget_feed_sort_on'] : ( $class::$databasePrefix . $this->configuration['widget_feed_sort_on'] . ' ' . $this->configuration['widget_feed_sort_dir'] ) ) : ( $class::$databasePrefix . $class::$databaseColumnMap['updated'] . ' DESC' ), /* Order */
isset( $this->configuration['widget_feed_show'] ) ? $this->configuration['widget_feed_show'] : 5, /* Limit */
( isset( $this->configuration['widget_feed_show'] ) AND $this->configuration['widget_feed_show'] ) ? $this->configuration['widget_feed_show'] : 5, /* Limit */
$skipPerms ? NULL : 'read', /* Permission key to check against */
$hidden, /* Whether or not to include hidden items */
0, NULL, FALSE, FALSE, FALSE, FALSE, NULL, $skipPerms, TRUE, FALSE, FALSE
+1 -1
View File
@@ -371,7 +371,7 @@ abstract class _WidgetComment extends \IPS\Widget\PermissionCache
$items = $class::getItemsWithPermission(
$this->buildWhere(),
( isset( $this->configuration['widget_feed_sort_on'] ) and isset( $this->configuration['widget_feed_sort_dir'] ) ) ? ( $class::$databasePrefix . $class::$databaseColumnMap['date'] . ' ' . $this->configuration['widget_feed_sort_dir'] ) : NULL,
isset( $this->configuration['widget_feed_show'] ) ? $this->configuration['widget_feed_show'] : 5,
( isset( $this->configuration['widget_feed_show'] ) AND $this->configuration['widget_feed_show'] ) ? $this->configuration['widget_feed_show'] : 5,
( !isset( $this->configuration['widget_feed_use_perms'] ) or $this->configuration['widget_feed_use_perms'] ) ? 'read' : NULL,
$hidden
);