Version 5.0.0 beta 6
This commit is contained in:
1 parent
57d9db6ce2
commit
fa2a720105
115 files changed
+1823
-1147
No files matched your search
+10
-54
@@ -927,60 +927,6 @@ abstract class Comment extends Content
|
||||
|
||||
return Theme::i()->getTemplate( static::$commentTemplate[0][0], static::$commentTemplate[0][1], ( isset( static::$commentTemplate[0][2] ) ) ? static::$commentTemplate[0][2] : NULL )->$template( $this->item(), $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Users to receive immediate notifications
|
||||
*
|
||||
* @param int|array|null $limit LIMIT clause
|
||||
* @param boolean $countOnly Just return the count
|
||||
* @return Select|int
|
||||
*/
|
||||
public function notificationRecipients( int|array|null $limit=array( 0, 25 ), bool $countOnly=FALSE ): Select|int
|
||||
{
|
||||
/* Do we only want the count? */
|
||||
if( $countOnly )
|
||||
{
|
||||
$count = 0;
|
||||
$count += $this->author()->followersCount( 3, array( 'immediate' ), $this->mapped('date') );
|
||||
if( IPS::classUsesTrait( $this->item(), 'IPS\Content\Followable' ) )
|
||||
{
|
||||
$count += $this->item()->followersCount( 3, array( 'immediate' ), $this->mapped('date') );
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
$memberFollowers = $this->author()->followers( 3, array( 'immediate' ), $this->mapped('date'), NULL );
|
||||
|
||||
if( $memberFollowers !== NULL AND $memberFollowers !== 0 and IPS::classUsesTrait( $this->item(), 'IPS\Content\Followable' ) )
|
||||
{
|
||||
$unions = array(
|
||||
$this->item()->followers( 3, array( 'immediate' ), $this->mapped('date'), NULL ),
|
||||
$memberFollowers
|
||||
);
|
||||
|
||||
return Db::i()->union( $unions, 'follow_added', $limit );
|
||||
}
|
||||
else if( IPS::classUsesTrait( $this->item(), 'IPS\Content\Followable' ) )
|
||||
{
|
||||
return $this->item()->followers( static::FOLLOW_PUBLIC + static::FOLLOW_ANONYMOUS, array( 'immediate' ), $this->mapped('date'), $limit, 'follow_added' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return $memberFollowers;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Notification
|
||||
*
|
||||
* @param string|NULL $extra Additional data
|
||||
* @return Notification
|
||||
*/
|
||||
protected function createNotification( string|null $extra=NULL ): Notification
|
||||
{
|
||||
return new Notification( Application::load( 'core' ), 'new_comment', $this->item(), array( $this ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Move Comment to another item
|
||||
@@ -1764,6 +1710,16 @@ abstract class Comment extends Content
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom where conditions used specifically for finding comments
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public static function findCommentWhere() : array|null
|
||||
{
|
||||
return static::commentWhere();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a featured comment?
|
||||
|
||||
@@ -1257,11 +1257,18 @@ abstract class Content extends ActiveRecord
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* How many followers? */
|
||||
try
|
||||
{
|
||||
$count = $this->notificationRecipients( NULL, TRUE );
|
||||
if( $this instanceof Comment )
|
||||
{
|
||||
$count = $this->item()->notificationRecipientsForComments( null, true, $this );
|
||||
}
|
||||
else
|
||||
{
|
||||
$count = $this->notificationRecipients( NULL, TRUE );
|
||||
}
|
||||
}
|
||||
catch ( BadMethodCallException $e )
|
||||
{
|
||||
@@ -1290,7 +1297,8 @@ abstract class Content extends ActiveRecord
|
||||
*/
|
||||
public function sendNotificationsBatch( int $offset=0, array &$sentTo=array(), string|null $extra=NULL ): int|NULL
|
||||
{
|
||||
if( !IPS::classUsesTrait( $this, Followable::class ) )
|
||||
/* Stop here if the content does not use the "followable" trait */
|
||||
if( ( $this instanceof Item and !IPS::classUsesTrait( $this, Followable::class ) ) or ( $this instanceof Comment and !IPS::classUsesTrait( $this->item(), Followable::class ) ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1303,7 +1311,9 @@ abstract class Content extends ActiveRecord
|
||||
}
|
||||
|
||||
$followIds = array();
|
||||
$followers = $this->notificationRecipients( array( $offset, static::NOTIFICATIONS_PER_BATCH ) );
|
||||
$followers = ( $this instanceof Comment ) ?
|
||||
$this->item()->notificationRecipientsForComments( array( $offset, static::NOTIFICATIONS_PER_BATCH ), false, $this ) :
|
||||
$this->notificationRecipients( array( $offset, static::NOTIFICATIONS_PER_BATCH ) );
|
||||
|
||||
/* If $followers is NULL (which can be the case if the follows are just people following the author), just return as there is nothing to do */
|
||||
if ( $followers === NULL )
|
||||
@@ -1320,7 +1330,7 @@ abstract class Content extends ActiveRecord
|
||||
}
|
||||
|
||||
/* Send notification */
|
||||
$notification = $this->createNotification( $extra );
|
||||
$notification = ( $this instanceof Comment ) ? $this->item()->createNotification( $extra, $this ) : $this->createNotification( $extra );
|
||||
$notification->unsubscribeType = 'follow';
|
||||
foreach ( $followers as $follower )
|
||||
{
|
||||
|
||||
@@ -887,7 +887,7 @@ class Controller extends CoverPhotoController
|
||||
/* @var $databaseColumnMap array */
|
||||
$titleField = $item::$databaseColumnMap['title'];
|
||||
|
||||
if( strlen( Request::i()->newTitle ) > $maxLength )
|
||||
if( mb_strlen( Request::i()->newTitle ) > $maxLength )
|
||||
{
|
||||
throw new LengthException( Member::loggedIn()->language()->addToStack( 'form_maxlength', FALSE, array( 'pluralize' => array( $maxLength ) ) ) );
|
||||
}
|
||||
@@ -903,6 +903,12 @@ class Controller extends CoverPhotoController
|
||||
throw new InvalidArgumentException( Member::loggedIn()->language()->addToStack( 'form_tags_not_allowed', FALSE, array( 'sprintf' => array( Request::i()->newTitle ) ) ) );
|
||||
}
|
||||
|
||||
/* Stop doing anything if the title wasn't changed */
|
||||
if( $item->$titleField == $newTitle->value )
|
||||
{
|
||||
\IPS\Output::i()->json( $item->$titleField );
|
||||
}
|
||||
|
||||
$item->$titleField = $newTitle->value;
|
||||
$idField = $item::$databaseColumnId;
|
||||
$item->save();
|
||||
@@ -916,14 +922,18 @@ class Controller extends CoverPhotoController
|
||||
|
||||
if( SearchContent::isSearchable( $item ) )
|
||||
{
|
||||
Index::i()->index( $item );
|
||||
if( $item::$firstCommentRequired )
|
||||
{
|
||||
$class = $item->firstComment();
|
||||
}
|
||||
else
|
||||
{
|
||||
$class = $item;
|
||||
}
|
||||
Index::i()->index( $class );
|
||||
}
|
||||
|
||||
/* Only add the mod log entry if we actually changed the title */
|
||||
if( $item->$titleField !== $oldTitle )
|
||||
{
|
||||
Session::i()->modLog( 'modlog__comment_edit_title', array( (string) $item->url() => FALSE, $item->$titleField => FALSE, $oldTitle => FALSE ), $item );
|
||||
}
|
||||
Session::i()->modLog( 'modlog__comment_edit_title', array( (string) $item->url() => FALSE, $item->$titleField => FALSE, $oldTitle => FALSE ), $item );
|
||||
|
||||
Output::i()->json( $item->$titleField );
|
||||
}
|
||||
@@ -1906,7 +1916,7 @@ class Controller extends CoverPhotoController
|
||||
$class = static::$contentModel;
|
||||
$item = $class::loadAndCheckPerms( Request::i()->id );
|
||||
|
||||
$timeLastRead = $item->timeLastRead();
|
||||
$timeLastRead = ( IPS::classUsesTrait( $item, ReadMarkers::class ) ) ? $item->timeLastRead() : null;
|
||||
|
||||
if ( $timeLastRead instanceof DateTime )
|
||||
{
|
||||
@@ -1935,7 +1945,7 @@ class Controller extends CoverPhotoController
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $item->unread() )
|
||||
if ( IPS::classUsesTrait( $item, ReadMarkers::class ) and $item->unread() )
|
||||
{
|
||||
/* If we do not have a time last read set for this content, fallback to the reset time */
|
||||
$resetTimes = Member::loggedIn()->markersResetTimes( $class::$application );
|
||||
@@ -2694,9 +2704,9 @@ class Controller extends CoverPhotoController
|
||||
$where[] = array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['hidden'] . '<>?', -3 );
|
||||
}
|
||||
|
||||
if ( $commentClass::commentWhere() !== NULL )
|
||||
if ( $commentClass::findCommentWhere() !== NULL )
|
||||
{
|
||||
$where[] = $commentClass::commentWhere();
|
||||
$where[] = $commentClass::findCommentWhere();
|
||||
}
|
||||
if ( $container = $item->containerWrapper() )
|
||||
{
|
||||
|
||||
@@ -227,6 +227,11 @@ trait Followable
|
||||
*/
|
||||
public function notificationRecipients( int|array|null $limit=array( 0, 25 ), bool $countOnly=FALSE ): Select|int
|
||||
{
|
||||
if( $this instanceof Comment )
|
||||
{
|
||||
return $this->item()->notificationRecipientsForComments( $limit, $countOnly, $this );
|
||||
}
|
||||
|
||||
/* Do we only want the count? */
|
||||
if( $countOnly )
|
||||
{
|
||||
@@ -259,15 +264,68 @@ trait Followable
|
||||
return static::containerFollowers( $this->container(), Content::FOLLOW_PUBLIC + Content::FOLLOW_ANONYMOUS, array( 'immediate' ), $this->mapped('date'), $limit, 'follow_added' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Users to receive immediate notifications
|
||||
*
|
||||
* @param int|array|null $limit LIMIT clause
|
||||
* @param boolean $countOnly Just return the count
|
||||
* @param Comment|null $comment The comment that is triggering this notification
|
||||
* @return Select|int
|
||||
*/
|
||||
public function notificationRecipientsForComments( int|array|null $limit=array( 0, 25 ), bool $countOnly=FALSE, ?Comment $comment=null ): Select|int
|
||||
{
|
||||
if( !( $comment instanceof Comment ) or !IPS::classUsesTrait( $this, Followable::class ) or ( !$comment->item() instanceof static ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do we only want the count? */
|
||||
if( $countOnly )
|
||||
{
|
||||
$count = 0;
|
||||
$count += $comment->author()->followersCount( 3, array( 'immediate' ), $comment->mapped('date') );
|
||||
if( IPS::classUsesTrait( $this, 'IPS\Content\Followable' ) )
|
||||
{
|
||||
$count += $this->followersCount( 3, array( 'immediate' ), $comment->mapped('date') );
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
$memberFollowers = $comment->author()->followers( 3, array( 'immediate' ), $comment->mapped('date'), NULL );
|
||||
|
||||
if( $memberFollowers !== 0 )
|
||||
{
|
||||
$unions = array(
|
||||
$this->followers( 3, array( 'immediate' ), $comment->mapped('date'), NULL ),
|
||||
$memberFollowers
|
||||
);
|
||||
|
||||
return Db::i()->union( $unions, 'follow_added', $limit );
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->followers( static::FOLLOW_PUBLIC + static::FOLLOW_ANONYMOUS, array( 'immediate' ), $comment->mapped('date'), $limit, 'follow_added' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create Notification
|
||||
*
|
||||
* @param mixed $extra Additional data
|
||||
* @param Comment|null $comment
|
||||
* @return Notification
|
||||
*/
|
||||
public function createNotification( mixed $extra=NULL ): Notification
|
||||
public function createNotification( mixed $extra=NULL, ?Comment $comment=null ): Notification
|
||||
{
|
||||
if( $comment instanceof Comment )
|
||||
{
|
||||
$key = ( $comment instanceof Review ) ? 'new_review' : 'new_comment';
|
||||
return new Notification( Application::load( 'core' ), $key, $this, array( $comment ) );
|
||||
}
|
||||
|
||||
// New content is sent with itself as the item as we deliberately do not group notifications about new content items. Unlike comments where you're going to read them all - you might scan the notifications list for topic titles you're interested in
|
||||
return new Notification( Application::load( 'core' ), 'new_content', $this, array( $this ), $extra );
|
||||
}
|
||||
|
||||
+8
-10
@@ -6527,7 +6527,7 @@ abstract class Item extends Content
|
||||
$member = $member ?: Member::loggedIn();
|
||||
|
||||
/* Check it isn't hidden */
|
||||
if ( IPS::classUsesTrait( $this, 'IPS\Content\Hideble' ) and $this->hidden() )
|
||||
if ( $this->hidden() !== 0 )
|
||||
{
|
||||
/* If we're a moderator who can see hidden items it's fine, unless it's a guest post before register */
|
||||
if ( $this->hidden() !== -3 and static::canViewHiddenItems( $member, $this->containerWrapper() ) )
|
||||
@@ -7147,10 +7147,11 @@ abstract class Item extends Content
|
||||
|
||||
if ( IPS::classUsesTrait( $this, 'IPS\Content\FuturePublishing' ) AND $this->isFutureDate() AND static::canFuturePublish($member, $this->container()))
|
||||
{
|
||||
$menu->add( new ContentMenuLink( url: $this->url()->csrf()->setQueryString( array( 'action' => 'publish' ) ), languageString: 'publish', dataAttributes: ['data-confirm','title=\'{lang="publish_desc"}\''], identifier: 'publish' ) );
|
||||
$publish = new ContentMenuLink( url: $this->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' => 'publish' ) ), languageString: 'publish', dataAttributes: [ 'title=\'{lang="publish_desc"}\'' ], identifier: 'publish' );
|
||||
$publish->requiresConfirm();
|
||||
$menu->add( $publish );
|
||||
}
|
||||
|
||||
|
||||
if( IPS::classUsesTrait( $this, 'IPS\Content\Pinnable' ) AND $this->canPin( $member ) )
|
||||
{
|
||||
$menu->add( new ContentMenuLink( $this->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' => 'pin' ) ), 'pin', identifier: 'pin' ) );
|
||||
@@ -7217,8 +7218,7 @@ abstract class Item extends Content
|
||||
if( $this->canUnarchive( $member ) )
|
||||
{
|
||||
$unarchive = new ContentMenuLink( url: $this->url()->csrf()->setQueryString( array( 'do' => 'unarchive' ) ), languageString: 'unarchive');
|
||||
$unarchive->addAttribute( 'data-confirm')
|
||||
->addAttribute( 'data-confirmSubMessage', $this->unarchiveBlurb() );
|
||||
$unarchive->requiresConfirm( $this->unarchiveBlurb() );
|
||||
$menu->add( $unarchive );
|
||||
}
|
||||
|
||||
@@ -7262,7 +7262,7 @@ abstract class Item extends Content
|
||||
if( $this->canDelete( $member ) )
|
||||
{
|
||||
$delete = new ContentMenuLink( url: $this->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' =>'delete' ) ), languageString: 'delete');
|
||||
$delete->addAttribute( 'data-confirm' );
|
||||
$delete->requiresConfirm();
|
||||
$menu->add( $delete );
|
||||
}
|
||||
|
||||
@@ -7284,9 +7284,7 @@ abstract class Item extends Content
|
||||
if( $this->canToggleItemModeration( $member ) )
|
||||
{
|
||||
$toggle = new ContentMenuLink( url: $this->url()->csrf()->setQueryString( array( 'do' => 'toggleItemModeration' ) ), languageString: $this->itemModerationEnabled() ?'disable_topic_moderation' : 'enable_topic_moderation' );
|
||||
$toggle
|
||||
->addAttribute( 'data-confirm')
|
||||
->addAttribute( 'data-confirmSubMessage', Member::loggedIn()->language()->addToStack( $this->itemModerationEnabled() ? 'disable_topic_moderation_confirm' : 'enable_topic_moderation_confirm' ) );
|
||||
$toggle->requiresConfirm( $this->itemModerationEnabled() ? 'disable_topic_moderation_confirm' : 'enable_topic_moderation_confirm' );
|
||||
$menu->add( $toggle );
|
||||
}
|
||||
|
||||
@@ -7296,7 +7294,7 @@ abstract class Item extends Content
|
||||
foreach ( $actions as $action )
|
||||
{
|
||||
$actionLink = new ContentMenuLink( url: $this->url()->csrf()->setQueryString( array( 'do' => 'savedAction', 'action' => $action->_id ) ), languageString: $action->_title );
|
||||
$actionLink->addAttribute( 'data-confirm' );
|
||||
$actionLink->requiresConfirm();
|
||||
$menu->add( $actionLink );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,17 +364,6 @@ abstract class Review extends Comment
|
||||
return array( $this->item()->$idColumn, $this->$commentIdColumn, 'review' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Notification
|
||||
*
|
||||
* @param string|NULL $extra Additional data
|
||||
* @return Notification
|
||||
*/
|
||||
protected function createNotification( string|null $extra=NULL ): Notification
|
||||
{
|
||||
return new Notification( Application::load( 'core' ), 'new_review', $this->item(), array( $this ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Review
|
||||
*
|
||||
|
||||
@@ -16,6 +16,7 @@ use Exception;
|
||||
use IPS\Application;
|
||||
use IPS\Content;
|
||||
use IPS\Content\Comment;
|
||||
use IPS\Content\FuturePublishing;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Content\Search\Elastic\MassIndexer;
|
||||
use IPS\DateTime;
|
||||
@@ -200,8 +201,18 @@ abstract class Index extends Singleton
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If this is a comment on an item that uses future publishing AND the item is in the future, don't index */
|
||||
if( $object instanceof Comment )
|
||||
{
|
||||
$item = $object->item();
|
||||
if( $item::$firstCommentRequired and $object->isFirst() and IPS::classUsesTrait( $item, FuturePublishing::class ) and $item->isFutureDate() )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't index if this is an item to be published in the future */
|
||||
if ( IPS::classUsesTrait( $object, 'IPS\Content\FuturePublishing' ) AND $object->isFutureDate() )
|
||||
if ( IPS::classUsesTrait( $object, FuturePublishing::class ) AND $object->isFutureDate() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace IPS\Content\Search;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Content;
|
||||
use IPS\Content\Item;
|
||||
use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\Db\Select;
|
||||
@@ -102,9 +102,13 @@ abstract class Query
|
||||
|
||||
/* Exclude disabled applications */
|
||||
$filters = array();
|
||||
foreach ( Content::routedClasses( $member, FALSE, TRUE ) as $class )
|
||||
foreach( SearchContent::searchableClasses() as $class )
|
||||
{
|
||||
$filters[] = ContentFilter::init( $class );
|
||||
/* We only want items here */
|
||||
if( is_subclass_of( $class, Item::class ) )
|
||||
{
|
||||
$filters[] = ContentFilter::init( $class );
|
||||
}
|
||||
}
|
||||
if ( !empty( $filters ) )
|
||||
{
|
||||
|
||||
@@ -105,7 +105,9 @@ trait Taggable
|
||||
*/
|
||||
public static function definedTags(): array
|
||||
{
|
||||
return array_values( Tag::getStore() );
|
||||
$tags = array_values( Tag::getStore() );
|
||||
natcasesort( $tags );
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +149,7 @@ trait Taggable
|
||||
$tagList[ $key ] = strtolower( $value );
|
||||
} );
|
||||
|
||||
foreach ( Db::i()->select( '*', 'core_tags', array( 'tag_meta_app=? AND tag_meta_area=? AND tag_meta_id=?', static::$application, static::$module, $this->$idColumn ) ) as $tag )
|
||||
foreach ( Db::i()->select( '*', 'core_tags', array( 'tag_meta_app=? AND tag_meta_area=? AND tag_meta_id=?', static::$application, static::$module, $this->$idColumn ), 'tag_text' ) as $tag )
|
||||
{
|
||||
if ( $tag['tag_prefix'] )
|
||||
{
|
||||
@@ -322,7 +324,8 @@ trait Taggable
|
||||
'resultItemTemplate' => 'core.autocomplete.tagsResultItem',
|
||||
'freeChoice' => false,
|
||||
'minimized' => $minimized,
|
||||
'addTokenText' => Member::loggedIn()->language()->get( 'tags_optional' )
|
||||
'addTokenText' => Member::loggedIn()->language()->get( 'tags_optional' ),
|
||||
'alphabetical' => true
|
||||
) );
|
||||
|
||||
if ( Settings::i()->tags_force_lower )
|
||||
|
||||
@@ -37,13 +37,18 @@ class Link extends MenuItem
|
||||
|
||||
/**
|
||||
* Adds all necessary attributes for a confirmation box
|
||||
* @param $desc
|
||||
* @param string|null $desc
|
||||
* @return $this
|
||||
*/
|
||||
public function requiresConfirm( $desc ): self
|
||||
public function requiresConfirm( ?string $desc=null ): self
|
||||
{
|
||||
$this->addAttribute( 'data-confirm');
|
||||
$this->addAttribute( 'data_confirmSubmessage', Member::loggedIn()->language()->addToStack( $desc ) );
|
||||
|
||||
if( $desc !== null )
|
||||
{
|
||||
$this->addAttribute( 'data_confirmSubmessage', Member::loggedIn()->language()->addToStack( $desc ) );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +220,12 @@ class Menu
|
||||
*/
|
||||
public function linkHtml(): string
|
||||
{
|
||||
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->link( $this );
|
||||
if( $this->hasContent() )
|
||||
{
|
||||
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->link( $this );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +235,12 @@ class Menu
|
||||
*/
|
||||
public function contentHtml(): string
|
||||
{
|
||||
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->content( $this );
|
||||
if( $this->hasContent() )
|
||||
{
|
||||
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->content( $this );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace IPS;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use BadFunctionCallException;
|
||||
use BadMethodCallException;
|
||||
use DateInterval;
|
||||
use DateTimeZone;
|
||||
@@ -699,7 +700,7 @@ class Member extends ActiveRecord
|
||||
public function set_member_group_id( int $value ) : void
|
||||
{
|
||||
$this->_data['member_group_id'] = $value;
|
||||
$this->_group = NULL;
|
||||
$this->resetGroupsCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -717,7 +718,7 @@ class Member extends ActiveRecord
|
||||
}
|
||||
|
||||
$this->_data['mgroup_others'] = implode( ',', $groups );
|
||||
$this->_group = NULL;
|
||||
$this->resetGroupsCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1086,6 +1087,17 @@ class Member extends ActiveRecord
|
||||
*/
|
||||
protected ?array $_groups = NULL;
|
||||
|
||||
/**
|
||||
* Reset the group and groups cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function resetGroupsCaches(): void
|
||||
{
|
||||
$this->_group = NULL;
|
||||
$this->_groups = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the group IDs (including secondary groups) this member belongs to
|
||||
*
|
||||
@@ -4367,7 +4379,7 @@ class Member extends ActiveRecord
|
||||
{
|
||||
$location = GeoLocation::getRequesterLocation();
|
||||
}
|
||||
catch( BadMethodCallException| Http\Request\Exception | RuntimeException |OutOfRangeException $e )
|
||||
catch( BadFunctionCallException | BadMethodCallException| Http\Request\Exception | RuntimeException |OutOfRangeException $e )
|
||||
{
|
||||
/* If it fails for any reason, don't bother. */
|
||||
Log::debug( $e, 'spam-service' );
|
||||
|
||||
@@ -110,7 +110,7 @@ class UserMenu
|
||||
|
||||
$menu->addSeparator();
|
||||
|
||||
if( $member->isAdmin() )
|
||||
if( $member->modPermission( 'can_use_theme_editor' ) )
|
||||
{
|
||||
$menu->add( new Link( Url::internal( "app=core&module=system&controller=themeeditor", "front", "theme_editor" ), 'menu_theme_editor', dataAttributes: [
|
||||
'target' => '_top'
|
||||
|
||||
@@ -3507,6 +3507,24 @@ abstract class Model extends ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete any node menu items */
|
||||
foreach( Db::i()->select( '*', 'core_menu', [ 'app=? and extension=?', 'core', 'Node' ] ) as $row )
|
||||
{
|
||||
if( $row['config'] and $config = json_decode( $row['config'], true ) )
|
||||
{
|
||||
if( $config['nodeClass'] == get_called_class() and $config['id'] == $this->_id )
|
||||
{
|
||||
Db::i()->delete( 'core_menu', [ 'id=?', $row['id'] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
unset( Store::i()->frontNavigation );
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
|
||||
parent::delete();
|
||||
|
||||
Event::fire( 'onDelete', $this );
|
||||
|
||||
@@ -1119,7 +1119,7 @@ class Output
|
||||
$queryLog = Db::i()->log;
|
||||
if (QUERY_LOG)
|
||||
{
|
||||
if ( defined('QUERY_LOG_TO_PATH') )
|
||||
if ( defined('QUERY_LOG_TO_PATH') or defined('QUERY_LOG_TO_SCREEN') )
|
||||
{
|
||||
$queryLogHtml = SystemOutput::generateDbLogHtml( $queryLog );
|
||||
|
||||
@@ -1127,6 +1127,13 @@ class Output
|
||||
{
|
||||
@ob_end_clean();
|
||||
@ob_start();
|
||||
|
||||
/* Rest of our HTTP headers */
|
||||
foreach ( $httpHeaders as $key => $header )
|
||||
{
|
||||
$this->sendHeader( $key . ': ' . $header );
|
||||
}
|
||||
|
||||
print $queryLogHtml;
|
||||
exit();
|
||||
}
|
||||
@@ -1589,7 +1596,7 @@ class Output
|
||||
}
|
||||
|
||||
|
||||
if( isset( $this->sidebar['widgetareas'] ) and count( $this->sidebar['widgetareas'] ) )
|
||||
if( isset( $this->sidebar['widgetareas']['sidebar'] ) and count( $this->sidebar['widgetareas']['sidebar'] ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -123,6 +123,13 @@ class Bridge
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Requester Location
|
||||
*
|
||||
* @return \IPS\GeoLocation
|
||||
* @throws \BadFunctionCallException Service is not available
|
||||
* @throws \IPS\Http\Request\Exception Error communicating with external service
|
||||
* @throws \RuntimeException Error within the external service
|
||||
*
|
||||
* @was cloud/hooks/ipsGeolocation::getRequesterLocation()
|
||||
*/
|
||||
public function getRequesterLocation(): Geolocation
|
||||
|
||||
Reference in new issue
Block a user