Version 5.0.13
This commit is contained in:
1 parent
b89858b2ff
commit
5efe744c5f
1407 files changed
+69690
-30177
No files matched your search
+197
-10
@@ -17,10 +17,13 @@ use Exception;
|
||||
use IPS\Application\Module;
|
||||
use IPS\Content\ClubContainer;
|
||||
use IPS\Content\Comment;
|
||||
use IPS\Content\Followable;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Content\Permissions as PermissionsExtension;
|
||||
use IPS\Content\Review;
|
||||
use IPS\Content\Search\Index;
|
||||
use IPS\Content\Search\SearchContent;
|
||||
use IPS\Content\ViewUpdates;
|
||||
use IPS\core\DeletionLog;
|
||||
use IPS\Data\Store;
|
||||
use IPS\DateTime;
|
||||
@@ -60,6 +63,7 @@ use function is_array;
|
||||
use function is_int;
|
||||
use function is_null;
|
||||
use function is_numeric;
|
||||
use function mb_substr;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
@@ -74,6 +78,7 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*
|
||||
* @mixin ClubContainer
|
||||
* @mixin DelayedCount
|
||||
* @mixin Grouping
|
||||
* @mixin Statistics
|
||||
* @mixin Colorize
|
||||
* @mixin Permissions
|
||||
@@ -218,7 +223,7 @@ abstract class Model extends ActiveRecord
|
||||
* @param Member|null $member The member to check permissions for or NULL for the currently logged in member
|
||||
* @param mixed $where Additional WHERE clause
|
||||
* @param array|null $limit Limit/offset to use, or NULL for no limit (default)
|
||||
* @return Model[]
|
||||
* @return static[]
|
||||
*/
|
||||
public static function roots( ?string $permissionCheck='view', Member $member=NULL, mixed $where=array(), array $limit=NULL ): array
|
||||
{
|
||||
@@ -303,7 +308,11 @@ abstract class Model extends ActiveRecord
|
||||
/* Permission check? */
|
||||
if ( $permissionCheck )
|
||||
{
|
||||
$where[] = array( '(' . Db::i()->findInSet( 'core_permission_index.perm_' . static::$permissionMap[ $permissionCheck ], $member->permissionArray() ) . ' OR ' . 'core_permission_index.perm_' . static::$permissionMap[ $permissionCheck ] . '=? )', '*' );
|
||||
foreach( PermissionsExtension::nodePermissionClause( $permissionCheck, get_called_class(), $member ) as $clause )
|
||||
{
|
||||
$where[] = $clause;
|
||||
}
|
||||
|
||||
if ( static::$databaseColumnEnabledDisabled )
|
||||
{
|
||||
$where[] = array( static::$databasePrefix . static::$databaseColumnEnabledDisabled . '=1' );
|
||||
@@ -355,7 +364,10 @@ abstract class Model extends ActiveRecord
|
||||
{
|
||||
$member = $member ?: Member::loggedIn();
|
||||
|
||||
$where[] = array( '(' . Db::i()->findInSet( 'core_permission_index.perm_' . static::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'core_permission_index.perm_' . static::$permissionMap[ $permissionCheck ] . '=? )', '*' );
|
||||
foreach( PermissionsExtension::nodePermissionClause( $permissionCheck, get_called_class(), $member ) as $clause )
|
||||
{
|
||||
$where[] = $clause;
|
||||
}
|
||||
if ( static::$databaseColumnEnabledDisabled )
|
||||
{
|
||||
$where[] = array( static::$databasePrefix . static::$databaseColumnEnabledDisabled . '=1' );
|
||||
@@ -524,9 +536,11 @@ abstract class Model extends ActiveRecord
|
||||
$order = static::$databaseColumnOrder !== NULL ? static::$databasePrefix . static::$databaseColumnOrder : NULL;
|
||||
if ( in_array( 'IPS\Node\Permissions', class_implements( get_called_class() ) ) and $permissionCheck !== NULL )
|
||||
{
|
||||
$permQueryWhere = PermissionsExtension::nodePermissionClause( $permissionCheck, get_called_class(), $member );
|
||||
$permQueryWhere[] = [ 'core_permission_index.app=?', static::$permApp ];
|
||||
$permQueryWhere[] = [ 'core_permission_index.perm_type=?', static::$permType ];
|
||||
$where[] = array(
|
||||
'(' . static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnId . ' IN(?) )',
|
||||
Db::i()->select( 'perm_type_id', 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND ( ( " . Db::i()->findInSet( 'perm_' . static::$permissionMap[ $permissionCheck ], $member->permissionArray() ) . ' ) OR perm_' . static::$permissionMap[ $permissionCheck ] . '=? )', static::$permApp, static::$permType, '*' ) )
|
||||
'(' . static::$databaseTable . '.' . static::$databasePrefix . static::$databaseColumnId . ' IN( ' . Db::i()->select( 'perm_type_id', 'core_permission_index', $permQueryWhere )->returnFullQuery() . ') )',
|
||||
);
|
||||
|
||||
$select = Db::i()->select( '*', static::$databaseTable, $where, $order, NULL, NULL, NULL, Db::SELECT_MULTIDIMENSIONAL_JOINS );
|
||||
@@ -1408,8 +1422,10 @@ abstract class Model extends ActiveRecord
|
||||
/* Permission check? */
|
||||
if( in_array( Permissions::class, class_implements( $this ) ) and $permissionCheck !== null )
|
||||
{
|
||||
|
||||
$where[] = array( '(' . Db::i()->findInSet( 'perm_' . static::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'perm_' . static::$permissionMap[ $permissionCheck ] . '=? )', '*' );
|
||||
foreach( PermissionsExtension::nodePermissionClause( $permissionCheck, get_class( $this ), $member, false ) as $clause )
|
||||
{
|
||||
$where[] = $clause;
|
||||
}
|
||||
if ( static::$databaseColumnEnabledDisabled )
|
||||
{
|
||||
$where[] = array( static::$databasePrefix . static::$databaseColumnEnabledDisabled . '=1' );
|
||||
@@ -1462,7 +1478,10 @@ abstract class Model extends ActiveRecord
|
||||
if ( in_array( 'IPS\Node\Permissions', class_implements( $subnodeClass ) ) and $permissionCheck !== NULL )
|
||||
{
|
||||
/* @var $permissionMap array */
|
||||
$where[] = array( '(' . Db::i()->findInSet( 'perm_' . $subnodeClass::$permissionMap[ $permissionCheck ], $member->groups ) . ' OR ' . 'perm_' . $subnodeClass::$permissionMap[ $permissionCheck ] . '=? )', '*' );
|
||||
foreach( PermissionsExtension::nodePermissionClause( $permissionCheck, $subnodeClass, $member, false ) as $clause )
|
||||
{
|
||||
$where[] = $clause;
|
||||
}
|
||||
if ( $subnodeClass::$databaseColumnEnabledDisabled )
|
||||
{
|
||||
$where[] = array( $subnodeClass::$databasePrefix . $subnodeClass::$databaseColumnEnabledDisabled . '=1' );
|
||||
@@ -1790,6 +1809,12 @@ abstract class Model extends ActiveRecord
|
||||
*/
|
||||
public function canDelete(): bool
|
||||
{
|
||||
/* Extensions go first */
|
||||
if( static::$canBeExtended and $permCheck = PermissionsExtension::can( 'delete', $this ) )
|
||||
{
|
||||
return ( $permCheck === PermissionsExtension::PERM_ALLOW );
|
||||
}
|
||||
|
||||
if ( $this->deleteOrMoveQueued() === TRUE )
|
||||
{
|
||||
return FALSE;
|
||||
@@ -2334,10 +2359,16 @@ abstract class Model extends ActiveRecord
|
||||
/**
|
||||
* Get permissions
|
||||
*
|
||||
* @return void
|
||||
* @return array|null
|
||||
*/
|
||||
public function permissions()
|
||||
public function permissions() : array|null
|
||||
{
|
||||
/* If we don't use permissions, stop here */
|
||||
if ( !in_array( 'IPS\Node\Permissions', class_implements( $this ) ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( $this->_permissions === NULL )
|
||||
{
|
||||
if( !isset( static::permissionStore()[ get_called_class() ][ $this->_id ] ) )
|
||||
@@ -2530,6 +2561,15 @@ abstract class Model extends ActiveRecord
|
||||
*/
|
||||
public function can( mixed $permission, Group|Member $member=NULL, bool $considerPostBeforeRegistering = TRUE ): bool
|
||||
{
|
||||
/* Extensions go first, but only for viewing and commenting, not for modifying the node */
|
||||
if( in_array( $permission, [ 'view', 'read', 'add', 'comment', 'reply', 'review' ] ) )
|
||||
{
|
||||
if( static::$canBeExtended and !( $member instanceof Group ) and $permCheck = PermissionsExtension::can( $permission, $this, $member ) )
|
||||
{
|
||||
return ( $permCheck === PermissionsExtension::PERM_ALLOW );
|
||||
}
|
||||
}
|
||||
|
||||
$_key = md5( $permission . ( $member ? ( ( $member instanceof Group ) ? $member->g_id : $member->member_id . '-' . $member->member_group_id ) : Member::loggedIn()->member_id . '-' . Member::loggedIn()->member_group_id ) . (int) $considerPostBeforeRegistering );
|
||||
|
||||
if( isset( $this->cachedPermissionChecks[ $_key ] ) )
|
||||
@@ -3547,6 +3587,21 @@ abstract class Model extends ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete Node Groups */
|
||||
if( IPS::classUsesTrait( $this, Grouping::class ) )
|
||||
{
|
||||
Db::i()->delete( 'core_node_groups_nodes', [
|
||||
[ 'node_id=?', $this->id ],
|
||||
[ Db::i()->in( 'group_id', array_keys( static::availableNodeGroups() ) ) ]
|
||||
]);
|
||||
}
|
||||
|
||||
/* Pending view updates */
|
||||
if( IPS::classUsesTrait( get_called_class(), ViewUpdates::class ) )
|
||||
{
|
||||
Db::i()->delete( 'core_view_updates', [ 'classname=? and id=?', get_called_class(), $this->_id ] );
|
||||
}
|
||||
|
||||
parent::delete();
|
||||
|
||||
Event::fire( 'onDelete', $this );
|
||||
@@ -3651,6 +3706,47 @@ abstract class Model extends ActiveRecord
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Follow this object
|
||||
*
|
||||
* @param string $frequency ( 'none', 'immediate', 'daily', 'weekly' )
|
||||
* @param bool $public
|
||||
* @param Member|null $member
|
||||
* @return void
|
||||
*/
|
||||
public function follow( string $frequency, bool $public=true, ?Member $member=null ) : void
|
||||
{
|
||||
if( isset( static::$contentItemClass ) )
|
||||
{
|
||||
$itemClass = static::$contentItemClass;
|
||||
if( IPS::classUsesTrait( $itemClass, Followable::class ) )
|
||||
{
|
||||
$itemClass::staticFollow( $this, $frequency, $public, $member );
|
||||
|
||||
/* Achievements */
|
||||
Member::loggedIn()->achievementAction( 'core', 'FollowNode', $this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfollow a node
|
||||
*
|
||||
* @param Member|null $member
|
||||
* @return void
|
||||
*/
|
||||
public function unfollow( ?Member $member=null ) : void
|
||||
{
|
||||
if( isset( static::$contentItemClass ) )
|
||||
{
|
||||
$itemClass = static::$contentItemClass;
|
||||
if( IPS::classUsesTrait( $itemClass, Followable::class ) )
|
||||
{
|
||||
$itemClass::containerUnfollow( $this, $member );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* !ACP forms */
|
||||
|
||||
/**
|
||||
@@ -3681,6 +3777,24 @@ abstract class Model extends ActiveRecord
|
||||
{
|
||||
$this->addBadgeFieldsToForm( $form, $this->getRecordBadge() );
|
||||
}
|
||||
|
||||
/* If the form initially had one tab, and now it has additional tabs (because of extensions),
|
||||
make sure that the first tab has a key and is not an empty string */
|
||||
$tabs = array_keys( $form->elements );
|
||||
if( count( $tabs ) > 1 and $tabs[0] == '' )
|
||||
{
|
||||
$originalElements = $form->elements;
|
||||
$form->elements = [
|
||||
'__default_tab_settings' => $originalElements['']
|
||||
];
|
||||
foreach( $originalElements as $k => $v )
|
||||
{
|
||||
if( $k != '' )
|
||||
{
|
||||
$form->elements[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4219,4 +4333,77 @@ abstract class Model extends ActiveRecord
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise IDs from stored data, which may be a string, array, numeric or even a node group
|
||||
*
|
||||
* @param mixed $ids
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeIds( mixed $ids ): array
|
||||
{
|
||||
/* Is this a comma-separated list? */
|
||||
if( is_string( $ids ) and mb_strpos( $ids, ',' ) !== false )
|
||||
{
|
||||
$ids = array_filter( explode( ',', $ids ) );
|
||||
}
|
||||
|
||||
if( is_array( $ids ) )
|
||||
{
|
||||
foreach( $ids as $id )
|
||||
{
|
||||
if ( ! is_numeric( $id ) and mb_substr( $id, 0, 1 ) === 'g' )
|
||||
{
|
||||
/* Is this a node group? */
|
||||
if( IPS::classUsesTrait( static::class, Grouping::class ) )
|
||||
{
|
||||
$groupId = mb_substr( $id, 1, 1 );
|
||||
$group = static::availableNodeGroups();
|
||||
|
||||
if( isset( $group[ $groupId ] ) )
|
||||
{
|
||||
/* Yeah, so grab the real IDs */
|
||||
$ids = array_merge( $ids, $group[ $groupId ]->nodes );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
else if( is_numeric( $ids ) )
|
||||
{
|
||||
return array( $ids );
|
||||
}
|
||||
else if( is_string( $ids ) )
|
||||
{
|
||||
if ( mb_substr( $ids, 0, 1 ) == 'g' )
|
||||
{
|
||||
/* Is this a node group? */
|
||||
if( IPS::classUsesTrait( static::class, Grouping::class ) )
|
||||
{
|
||||
$groupId = mb_substr( $ids, 1, 1 );
|
||||
$group = static::availableNodeGroups();
|
||||
|
||||
if( isset( $group[ $groupId ] ) )
|
||||
{
|
||||
/* Yeah, so grab the real IDs */
|
||||
return $group[ $groupId ]->nodes;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
return explode( ',', $ids );
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user