Version 4.1.2

This commit is contained in:
Neo committed 2025-12-19 05:32:19 -08:00
1 parent 3ba79295ee
commit 28bd025b35
1131 files changed
+63658 -20579

No files matched your search

+357 -202
View File
@@ -94,6 +94,10 @@ class _Member extends \IPS\Patterns\ActiveRecord
'remove_gallery_upload' => 4, // Remove permission to upload images in Gallery
'no_report_count' => 8, // 1 means the report count will not show
'has_no_ignored_users' => 16, // If we know the user has no ignored users, we don't have to query for them
'must_reaccept_privacy' => 32, // 1 means the member needs to re-accept the privacy policy
'must_reaccept_terms' => 64, // 1 means the member needs to re-accept the registration terms
'email_notifications_once' => 128, // 1 means the member only wants one email per notification item until they revisit the community
'disable_notification_sounds' => 256 // 1 means notification sounds are disabled, 0 is enabled
)
)
);
@@ -347,7 +351,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
/* Run member sync, but not if the only change is the last_activity timestamp */
if( count( $changes ) > 1 OR !isset( $changes['last_activity'] ) )
{
$this->memberSync( 'onProfileUpdate', array( 'changes' => $changes ) );
$this->memberSync( 'onProfileUpdate', array( 'changes' => array_merge( $changes, $this->changedCustomFields ) ) );
}
}
@@ -386,6 +390,17 @@ class _Member extends \IPS\Patterns\ActiveRecord
*/
public $markers = array();
protected $markersResetTimes = array();
protected $haveAllMarkers = FALSE;
/**
* @brief Default stream ID
*/
protected $defaultStreamId = FALSE;
/**
* @brief Keep track of any changed profile fields
*/
public $changedCustomFields = array();
/**
* Get name, do not return "guest" name if not set
@@ -408,8 +423,8 @@ class _Member extends \IPS\Patterns\ActiveRecord
{
return \IPS\Member::loggedIn()->language()->addToStack('guest');
}
return $this->_data['name'];
return $this->member_id ? $this->_data['name'] : \IPS\Member::loggedIn()->language()->addToStack( 'guest_name_shown', NULL, array( 'sprintf' => array( $this->_data['name'] ) ) );
}
/**
@@ -546,8 +561,8 @@ class _Member extends \IPS\Patterns\ActiveRecord
/* Edited member, so clear widget caches (stats, widgets that contain photos, names and so on) */
\IPS\Widget::deleteCaches();
/* Send to the queue */
foreach ( \IPS\Content::routedClasses( FALSE, FALSE, FALSE ) as $class )
/* Send to the queue, include archived content */
foreach ( \IPS\Content::routedClasses( FALSE, TRUE, FALSE ) as $class )
{
if ( isset( $class::$databaseColumnMap['author'] ) and ( $action == 'delete' or in_array( 'IPS\Content\Hideable', class_implements( $class ) ) ) )
{
@@ -629,9 +644,9 @@ class _Member extends \IPS\Patterns\ActiveRecord
*/
public function get_group()
{
/* Load primary group */
if ( $this->_group === NULL )
{
/* Load primary group */
try
{
$group = \IPS\Member\Group::load( $this->_data['member_group_id'] );
@@ -642,138 +657,140 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
$this->_group = array_merge( $group->data(), $group->g_bitoptions->asArray() );
}
/* Merge in secondary group data */
if ( !empty( $this->_data['mgroup_others'] ) )
{
$groups = array_filter( explode( ',', $this->_data['mgroup_others'] ) );
$exclude = array();
$lessIsMore = array();
$neg1IsBest = array();
$zeroIsBest = array();
$callback = array();
/* Get the limits we need to work out from apps */
foreach ( \IPS\Application::allExtensions( 'core', 'GroupLimits', FALSE, 'core' ) as $key => $extension )
/* Merge in secondary group data */
if ( !empty( $this->_data['mgroup_others'] ) )
{
if( method_exists( $extension, 'getLimits' ) )
$groups = array_filter( explode( ',', $this->_data['mgroup_others'] ) );
$exclude = array();
$lessIsMore = array();
$neg1IsBest = array();
$zeroIsBest = array();
$callback = array();
/* Get the limits we need to work out from apps */
foreach ( \IPS\Application::allExtensions( 'core', 'GroupLimits', FALSE, 'core' ) as $key => $extension )
{
$appLimits = $extension->getLimits();
if( !empty( $appLimits['neg1IsBest'] ) )
if( method_exists( $extension, 'getLimits' ) )
{
$neg1IsBest = array_merge( $neg1IsBest, $appLimits['neg1IsBest'] );
}
$appLimits = $extension->getLimits();
if( !empty( $appLimits['zeroIsBest'] ) )
{
$zeroIsBest = array_merge( $zeroIsBest, $appLimits['zeroIsBest'] );
}
if( !empty( $appLimits['lessIsMore'] ) )
{
$lessIsMore = array_merge( $lessIsMore, $appLimits['lessIsMore'] );
}
if( !empty( $appLimits['exclude'] ) )
{
$exclude = array_merge( $exclude, $appLimits['exclude'] );
}
if( !empty( $appLimits['callback'] ) )
{
$callback = array_merge( $callback, $appLimits['callback'] );
}
}
}
/* Do the merging */
$skippedGroups = array();
foreach( $groups as $gid )
{
try
{
$group = \IPS\Member\Group::load( $gid );
}
catch( \OutOfRangeException $e )
{
$skippedGroups[] = $gid;
continue;
}
foreach( $group->_data as $k => $v )
{
if ( ! in_array( $k, $exclude ) )
{
if ( in_array( $k, $zeroIsBest ) )
if( !empty( $appLimits['neg1IsBest'] ) )
{
if ( empty( $this->_group[ $k ] ) )
{
continue;
}
else if( $v == 0 )
{
$this->_group[ $k ] = 0;
}
else if ( $v > $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
$neg1IsBest = array_merge( $neg1IsBest, $appLimits['neg1IsBest'] );
}
else if( in_array( $k, $neg1IsBest ) )
{
if ( $this->_group[ $k ] == -1 )
{
continue;
}
else if( $v == -1 )
{
$this->_group[ $k ] = -1;
}
else if ( $v > $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
}
else if ( in_array( $k, $lessIsMore ) )
if( !empty( $appLimits['zeroIsBest'] ) )
{
if ( $v < $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
$zeroIsBest = array_merge( $zeroIsBest, $appLimits['zeroIsBest'] );
}
else if ( array_key_exists( $k, $callback ) )
if( !empty( $appLimits['lessIsMore'] ) )
{
$result = call_user_func( $callback[ $k ], $this->_group, array_merge( $group->_data, $group->g_bitoptions->asArray() ), $k, $this->_data );
if( is_array( $result ) )
{
$this->_group = array_merge( $this->_group, $result );
}
else if( $result !== NULL )
{
$this->_group[ $k ] = $result;
}
$lessIsMore = array_merge( $lessIsMore, $appLimits['lessIsMore'] );
}
else
if( !empty( $appLimits['exclude'] ) )
{
if ( !isset( $this->_group[ $k ] ) OR $v > $this->_group[ $k ] )
$exclude = array_merge( $exclude, $appLimits['exclude'] );
}
if( !empty( $appLimits['callback'] ) )
{
$callback = array_merge( $callback, $appLimits['callback'] );
}
}
}
/* Do the merging */
$skippedGroups = array();
foreach( $groups as $gid )
{
try
{
$group = \IPS\Member\Group::load( $gid );
}
catch( \OutOfRangeException $e )
{
$skippedGroups[] = $gid;
continue;
}
$_data = array_merge( $group->_data, $group->g_bitoptions->asArray() );
foreach( $_data as $k => $v )
{
if ( ! in_array( $k, $exclude ) )
{
if ( in_array( $k, $zeroIsBest ) )
{
$this->_group[ $k ] = $v;
if ( empty( $this->_group[ $k ] ) )
{
continue;
}
else if( $v == 0 )
{
$this->_group[ $k ] = 0;
}
else if ( $v > $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
}
else if( in_array( $k, $neg1IsBest ) )
{
if ( $this->_group[ $k ] == -1 )
{
continue;
}
else if( $v == -1 )
{
$this->_group[ $k ] = -1;
}
else if ( $v > $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
}
else if ( in_array( $k, $lessIsMore ) )
{
if ( $v < $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
}
else if ( array_key_exists( $k, $callback ) )
{
$result = call_user_func( $callback[ $k ], $this->_group, $_data, $k, $this->_data );
if( is_array( $result ) )
{
$this->_group = array_merge( $this->_group, $result );
}
else if( $result !== NULL )
{
$this->_group[ $k ] = $result;
}
}
else
{
if ( !isset( $this->_group[ $k ] ) OR $v > $this->_group[ $k ] )
{
$this->_group[ $k ] = $v;
}
}
}
}
}
}
if( count( $skippedGroups ) )
{
$this->mgroup_others = implode( ',', array_diff( $groups, $skippedGroups ) );
parent::save();
if( count( $skippedGroups ) )
{
$this->mgroup_others = implode( ',', array_diff( $groups, $skippedGroups ) );
parent::save();
}
}
}
@@ -967,59 +984,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
*/
public function get_photo( $thumb=TRUE )
{
$url = NULL;
if ( mb_substr( $this->pp_photo_type, 0, 5 ) === 'sync-' or $this->pp_photo_type === 'custom' )
{
try
{
if ( !$this->pp_main_photo )
{
return \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' );
}
return \IPS\File::get( 'core_Profile', ( $thumb and $this->pp_thumb_photo ) ? $this->pp_thumb_photo : $this->pp_main_photo )->url;
}
catch ( \InvalidArgumentException $e ) { }
}
elseif ( $this->pp_photo_type === 'gravatar' )
{
$url = \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' );
if ( \IPS\IN_DEV ) // Gravatar will error for localhost URLs. We'll assume anyone on localhost is IN_DEV. This way also allows us to easily see what is loading from Gravatar.
{
$url = '';
}
$photoVars = explode( ':', $this->group['g_photo_max_vars'] );
$url = \IPS\Http\Url::external( "https://secure.gravatar.com/avatar/" . md5( trim( mb_strtolower( $this->pp_gravatar ?: $this->email ) ) ) . ( $photoVars[0] ? ( "?size=" . min( $photoVars[1], $photoVars[2] ) ) : '' ) . "&d=" . urlencode( $url ) );
if ( \IPS\Dispatcher::hasInstance() AND \IPS\Dispatcher::i()->controllerLocation === 'admin' )
{
return $url->makeSafeForAcp( TRUE );
}
else
{
return $url;
}
}
elseif( $this->pp_photo_type and $this->pp_photo_type != 'none' )
{
/* This allows an app (such as Gallery) to set the pp_photo_type to a storage container to support custom images without duplicating them */
try
{
return \IPS\File::get( $this->pp_photo_type, $this->pp_main_photo )->url;
}
catch ( \InvalidArgumentException $e )
{
/* If there was an exception, clear these values out - most likely the image or storage container is no longer valid */
$this->pp_photo_type = NULL;
$this->pp_main_photo = NULL;
$this->save();
}
}
if ( !$url )
{
return \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' );
}
return static::photoUrl( $this->_data, $thumb );
}
/**
@@ -1197,6 +1162,51 @@ class _Member extends \IPS\Patterns\ActiveRecord
$this->_data['members_day_posts'] = implode( ',', $value );
}
/**
* Get member's default stream
*
* @return int|null
*/
public function get_defaultStream()
{
if ( $this->defaultStreamId === FALSE )
{
if ( $this->member_streams and $streams = json_decode( $this->member_streams, TRUE ) and count( $streams ) )
{
$this->defaultStreamId = ( isset( $streams['default'] ) ? $streams['default'] : NULL );
}
else
{
$this->defaultStreamId = NULL;
}
}
return $this->defaultStreamId;
}
/**
* Set member's default stream
*
* @param null|int $value Null or stream ID. 0 is for 'all activity'
* @return void
*/
public function set_defaultStream( $value )
{
if ( $this->member_streams and $streams = json_decode( $this->member_streams, TRUE ) and count( $streams ) )
{
$streams['default'] = $value;
}
else
{
$streams = array( 'streams' => array(), 'default' => $value );
}
$this->member_streams = json_encode( $streams );
$this->save();
$this->defaultStreamId = $value;
}
/**
* Get member location
@@ -1311,6 +1321,95 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
$this->failed_login_count = $highest;
}
/* !Photos */
/**
* Columns needed to build photos
*
* @return array
*/
public static function columnsForPhoto()
{
$return = array( 'member_id', 'name', 'members_seo_name', 'member_group_id', 'pp_photo_type', 'pp_main_photo', 'pp_thumb_photo' );
if ( true or \IPS\Settings::i()->allow_gravatars )
{
$return[] = 'pp_gravatar';
$return[] = 'email';
}
return $return;
}
/**
* Get photo from data
*
* @param array $memberData Array of member data, must include values for at least the keys returned by columnsForPhoto()
* @param bool $thumb Use thumbnail?
* @return string
*/
public static function photoUrl( $memberData, $thumb = TRUE )
{
$url = NULL;
/* Either uploaded or synced from social media */
if ( $memberData['pp_main_photo'] and ( mb_substr( $memberData['pp_photo_type'], 0, 5 ) === 'sync-' or $memberData['pp_photo_type'] === 'custom' ) )
{
try
{
return (string) \IPS\File::get( 'core_Profile', ( $thumb and $memberData['pp_thumb_photo'] ) ? $memberData['pp_thumb_photo'] : $memberData['pp_main_photo'] )->url;
}
catch ( \InvalidArgumentException $e ) { }
}
/* Gravatar */
elseif ( \IPS\Settings::i()->allow_gravatars and $memberData['pp_photo_type'] === 'gravatar' )
{
/* Default URL we send to Gravatar for it to fallback for. Gravatar will error for localhost URLs, so if IN_DEV, don't send this (this way also allows us to easily see what is loading from Gravatar). */
$defaultUrl = \IPS\IN_DEV ? '' : \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' );
/* We need to know how big the photo can be */
$photoVars = explode( ':', \IPS\Member::load( $memberData['member_id'] )->group['g_photo_max_vars'] );
/* Construct the URL */
$url = \IPS\Http\Url::external( "https://secure.gravatar.com/avatar/" . md5( trim( mb_strtolower( $memberData['pp_gravatar'] ?: $memberData['email'] ) ) ) )->setQueryString( array(
'd' => $defaultUrl
) );
/* If we're in the ACP, munge because this is an external resource */
if ( \IPS\Dispatcher::hasInstance() AND \IPS\Dispatcher::i()->controllerLocation === 'admin' )
{
$url = $url->makeSafeForAcp( TRUE );
}
/* Return */
return (string) $url;
}
/* Other - This allows an app (such as Gallery) to set the pp_photo_type to a storage container to support custom images without duplicating them */
elseif( $memberData['pp_photo_type'] and $memberData['pp_photo_type'] != 'none' )
{
try
{
return (string) \IPS\File::get( $memberData['pp_photo_type'], $memberData['pp_main_photo'] )->url;
}
catch ( \InvalidArgumentException $e )
{
/* If there was an exception, clear these values out - most likely the image or storage container is no longer valid */
$member = \IPS\Member::load( $memberData['member_id'] );
$member->pp_photo_type = NULL;
$member->pp_main_photo = NULL;
$member->save();
}
}
/* Still here? Return default photo */
if ( !$url )
{
return \IPS\Theme::i()->resource( 'default_photo.png', 'core', 'global' );
}
}
/* !Get Calculated Properties */
@@ -1705,7 +1804,10 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
else
{
$return[ $ip ] = $data;
if ( $ip )
{
$return[ $ip ] = $data;
}
}
}
}
@@ -1736,7 +1838,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
*/
public function markersItems( $app, $key )
{
if ( !isset( $this->markers[ $app ][ $key ] ) )
if ( !isset( $this->markers[ $app ] ) or !array_key_exists( $key, $this->markers[ $app ] ) )
{
try
{
@@ -1745,74 +1847,105 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
catch ( \UnderflowException $e )
{
return array();
$this->markers[ $app ][ $key ] = NULL;
}
}
return json_decode( $this->markers[ $app ][ $key ]['item_read_array'], TRUE );
return $this->markers[ $app ][ $key ] ? json_decode( $this->markers[ $app ][ $key ]['item_read_array'], TRUE ) : array();
}
/**
* Get read/unread markers for containers
*
* @param string $app Application key
* @param string|NULL $app Application key or NULL for all applications
* @return array
*/
public function markersResetTimes( $app )
{
if ( !isset( $this->markersResetTimes[ $app ] ) )
if ( ( !$app and !$this->haveAllMarkers ) or ( $app and !isset( $this->markersResetTimes[ $app ] ) ) )
{
try
{
$this->markersResetTimes[ $app ] = array();
foreach ( \IPS\Db::i()->select( '*', 'core_item_markers', array( 'item_member_id=? AND item_app=?', $this->member_id, $app ) ) as $row )
$where = array( array( 'item_member_id=?', $this->member_id ) );
if ( $app )
{
$this->markersResetTimes[ $app ] = array();
$where[] = array( 'item_app=?', $app );
}
else
{
$this->markersResetTimes = array();
}
foreach ( \IPS\Db::i()->select( '*', 'core_item_markers', $where ) as $row )
{
if( !is_array( $this->markersResetTimes[ $app ] ) )
if( !isset( $this->markersResetTimes[ $row['item_app'] ] ) or !is_array( $this->markersResetTimes[ $row['item_app'] ] ) )
{
$this->markersResetTimes[ $app ] = array();
$this->markersResetTimes[ $row['item_app'] ] = array();
}
if ( $row['item_app_key_1'] )
{
if ( $row['item_app_key_2'] )
{
if( !isset( $this->markersResetTimes[ $app ][ $row['item_app_key_1'] ] ) OR !is_array( $this->markersResetTimes[ $app ][ $row['item_app_key_1'] ] ) )
if( !isset( $this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ] ) OR !is_array( $this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ] ) )
{
$this->markersResetTimes[ $app ][ $row['item_app_key_1'] ] = array();
$this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ] = array();
}
if ( $row['item_app_key_3'] )
{
if( !isset( $this->markersResetTimes[ $app ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] ) OR !is_array( $this->markersResetTimes[ $app ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] ) )
if( !isset( $this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] ) OR !is_array( $this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] ) )
{
$this->markersResetTimes[ $app ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] = array();
$this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] = array();
}
$this->markersResetTimes[ $app ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ][ $row['item_app_key_3'] ] = $row['item_global_reset'];
$this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ][ $row['item_app_key_3'] ] = $row['item_global_reset'];
}
else
{
$this->markersResetTimes[ $app ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] = $row['item_global_reset'];
$this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ][ $row['item_app_key_2'] ] = $row['item_global_reset'];
}
}
else
{
$this->markersResetTimes[ $app ][ $row['item_app_key_1'] ] = $row['item_global_reset'];
$this->markersResetTimes[ $row['item_app'] ][ $row['item_app_key_1'] ] = $row['item_global_reset'];
}
}
else
{
$this->markersResetTimes[ $app ] = $row['item_global_reset'];
$this->markersResetTimes[ $row['item_app'] ] = $row['item_global_reset'];
}
$this->markers[ $app ][ $row['item_key'] ] = $row;
$this->markers[ $row['item_app'] ][ $row['item_key'] ] = $row;
}
if ( !$app )
{
$this->haveAllMarkers = TRUE;
}
}
catch ( \UnderflowException $e )
{
$this->markersResetTimes[ $app ] = NULL;
if ( $app )
{
$this->markersResetTimes[ $app ] = NULL;
}
else
{
$this->markersResetTimes = array();
}
}
}
return $this->markersResetTimes[ $app ];
if ( $app )
{
return $this->markersResetTimes[ $app ];
}
else
{
return $this->markersResetTimes;
}
}
/**
@@ -2158,7 +2291,19 @@ class _Member extends \IPS\Patterns\ActiveRecord
/* If it's an array, combine the values */
elseif ( is_array( $this->modPermissions[ $k ] ) AND is_array( $v ) )
{
$this->modPermissions[ $k ] = array_merge( $this->modPermissions[ $k ], $v );
foreach( $v as $_k => $_v )
{
/* If this key isn't set yet, then use this value */
if( !isset( $this->modPermissions[ $k ][ $_k ] ) )
{
$this->modPermissions[ $k ][ $_k ] = $_v;
}
/* Otherwise, we only set the value if it's better than what is already set */
elseif ( $_v == -1 or ( $this->modPermissions[ $k ][ $_k ] != -1 and $_v > $this->modPermissions[ $k ][ $_k ] ) )
{
$this->modPermissions[ $k ][ $_k ] = $_v;
}
}
}
/* If it's a number, they get the higher one, or -1 is best */
@@ -2172,7 +2317,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
}
}
/* Return */
return $this->modPermissions;
}
@@ -2254,7 +2399,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
}
}
if ( isset( $this->ignorePreferences[ $member->member_id ] ) )
{
return (bool) $this->ignorePreferences[ $member->member_id ][ 'ignore_' . $type ];
@@ -2270,7 +2415,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
*/
public function createMenu()
{
if ( $this->create_menu === NULL or \IPS\IN_DEV )
if ( $this->create_menu === NULL or ( \IPS\IN_DEV and !\IPS\DEV_USE_MENU_CACHE ) )
{
$createMenu = array();
foreach ( \IPS\Application::allExtensions( 'core', 'CreateMenu', $this ) as $ext )
@@ -2355,9 +2500,9 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
/**
* HTML for search results
* Get HTML for search result display
*
* @return string
* @return callable
*/
public function searchResultHtml()
{
@@ -2768,6 +2913,11 @@ class _Member extends \IPS\Patterns\ActiveRecord
$this->save();
}
/**
* @brief Posts Per Day Storage
*/
protected $_ppdLimit = NULL;
/**
* Check posts per day to see if this member can post.
*
@@ -2775,6 +2925,11 @@ class _Member extends \IPS\Patterns\ActiveRecord
*/
public function checkPostsPerDay()
{
/* Fetch our PPD limit - we should only need to do this once */
if ( $this->_ppdLimit === NULL )
{
$this->_ppdLimit = $this->group['g_ppd_limit'];
}
/* We can't actually check guests as we can't store how often they have posted - simply counting content is not viable */
if ( ! $this->member_id )
{
@@ -2782,7 +2937,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
/* Is there any limit at all? */
if ( ! $this->group['g_ppd_limit'] )
if ( ! $this->_ppdLimit )
{
return TRUE;
}
@@ -2806,7 +2961,7 @@ class _Member extends \IPS\Patterns\ActiveRecord
}
/* Still within 24 hours... have we hit the limit? */
if ( $count > $this->group['g_ppd_limit'] )
if ( $count >= $this->_ppdLimit )
{
return FALSE;
}