Version 5.0.0 beta 9

This commit is contained in:
Neo committed 2025-12-19 17:47:00 -08:00
1 parent 214f649f1d
commit 56979f8ee8
202 files changed
+4403 -1123

No files matched your search

+19 -12
View File
@@ -169,6 +169,11 @@ class Club extends ActiveRecord implements Embeddable
* @brief Status: leader
*/
const STATUS_LEADER = 'leader';
/**
* @brief Not actually a status, but used for member history
*/
const STATUS_LEFT = 'left';
/**
* @brief [ActiveRecord] Multiton Store
@@ -1308,18 +1313,6 @@ class Club extends ActiveRecord implements Embeddable
$save['joined'] = time();
}
/* Log to Member History */
if ( in_array( $status, array( Club::STATUS_MEMBER, Club::STATUS_BANNED ) ) )
{
$memberStatus = $this->memberStatus( $member, 2 );
/* Joining by invite */
if ( $memberStatus['status'] == Club::STATUS_INVITED )
{
$addedBy = Member::load( $memberStatus['invited_by'] );
}
$member->logHistory( 'core', 'club_membership', array('club_id' => $this->id, 'type' => $status ), $addedBy );
}
Db::i()->update( 'core_clubs_memberships', $save, array( 'club_id=? AND member_id=?', $this->id, $member->member_id ) );
$member->rebuildPermissionArray();
@@ -1335,6 +1328,17 @@ class Club extends ActiveRecord implements Embeddable
}
}
/* Log to Member History */
$memberStatus = $this->memberStatus( $member, 2 );
if( in_array( $memberStatus['status'], [ Club::STATUS_INVITED, Club::STATUS_INVITED_BYPASSING_PAYMENT, Club::STATUS_BANNED, Club::STATUS_MEMBER, Club::STATUS_DECLINED, Club::STATUS_REQUESTED ] ) )
{
if ( $memberStatus['status'] == Club::STATUS_INVITED )
{
$addedBy = Member::load( $memberStatus['invited_by'] );
}
$member->logHistory( 'core', 'club_membership', array('club_id' => $this->id, 'type' => $status ), $addedBy );
}
$params = [
'club' => $this,
'member' => $member,
@@ -1384,6 +1388,9 @@ class Club extends ActiveRecord implements Embeddable
*/
public function removeMember( Member $member ) : void
{
/* Get the member's current status */
$memberStatus = $this->memberStatus( $member );
Db::i()->delete( 'core_clubs_memberships', array( 'club_id=? AND member_id=?', $this->id, $member->member_id ) );
Webhook::fire( 'club_member_removed', ['club' => $this, 'member' => $member] );
+106 -1
View File
@@ -34,6 +34,7 @@ use IPS\core\ProfileFields\Api\Field;
use IPS\core\ProfileFields\Api\FieldGroup;
use IPS\core\Reports\Report;
use IPS\Data\Store;
use IPS\Db;
use IPS\Db\Select;
use IPS\Events\Event;
use IPS\Helpers\CoverPhoto;
@@ -56,6 +57,7 @@ use IPS\Member\UserMenu;
use IPS\Patterns\ActiveRecord;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Platform\Bridge;
use IPS\Settings;
use IPS\Text\Encrypt;
use IPS\Xml\SimpleXML;
use OutOfRangeException;
@@ -102,6 +104,11 @@ class Member extends ActiveRecord
*/
const SPAM_CHECK_DORMANT_THRESHOLD = 'P6M';
/**
* @brief Period for login after inactivity notification
*/
const LOGIN_INACTIVITY_NOTIFICATION = 'P6M';
/**
* @brief Application
*/
@@ -2987,6 +2994,42 @@ class Member extends ActiveRecord
return NULL;
}
/**
* Change the member's email address
*
* @param string $newEmail
* @return void
*/
public function changeEmail( string $newEmail ) : void
{
/* Disable syncing */
$profileSync = $this->profilesync;
if ( isset( $profileSync['email'] ) )
{
unset( $profileSync['email'] );
$this->profilesync = $profileSync;
$this->save();
}
/* Change the email */
$oldEmail = $this->email;
$this->email = $newEmail;
$this->save();
foreach ( Login::methods() as $method )
{
try
{
$method->changeEmail( $this, $oldEmail, $newEmail );
}
catch( BadMethodCallException $e ){}
}
$this->logHistory( 'core', 'email_change', array( 'old' => $oldEmail, 'new' => $newEmail, 'by' => 'manual' ) );
Db::i()->delete( 'core_validating', [ 'member_id=? and email_chg=?', $this->member_id, 1 ] );
Event::fire( 'onEmailChange', $this, array( $newEmail, $oldEmail ) );
}
/**
* @brief Cached notifications configuration
* @note This property is public so it can be populated en-masse in areas that may benefit from doing so
@@ -4965,7 +5008,7 @@ class Member extends ActiveRecord
/* Send email for validation */
if ( $validationType != 'admin' )
{
Email::buildFromTemplate( 'core', 'registration_validate', array( $this, $vid, $plainSecurityKey ), Email::TYPE_TRANSACTIONAL )->send( $this );
Email::buildFromTemplate( 'core', 'registration_validate', array( $this, $vid, $plainSecurityKey, '' ), Email::TYPE_TRANSACTIONAL )->send( $this );
}
/* Update core_post_before_registering */
@@ -6570,6 +6613,8 @@ class Member extends ActiveRecord
*/
public function recordLogin() : void
{
$this->sendLoginAfterInactivityNotification();
try
{
Db::i()->insert( 'core_members_logins', [ 'member_id' => $this->member_id, 'member_timestamp' => time(), 'member_date' => date( 'Y-m-d', DateTime::ts( time() )->getTimestamp() ) ] );
@@ -6577,6 +6622,66 @@ class Member extends ActiveRecord
catch( Exception $e ) { }
}
/**
* If required, send an email notification when signing in after a period of inactivity.
*
* @return bool
*/
public function sendLoginAfterInactivityNotification(): bool
{
if( !Settings::i()->login_after_inactivity_notification )
{
return false;
}
try
{
$lastLogin = Db::i()->select( 'member_timestamp', 'core_members_logins', [ 'member_id=?', $this->member_id ], 'member_timestamp DESC', 1 )->first();
}
catch( \UnderflowException $e )
{
/* This is the first login, or they haven't logged in since upgrading from < 106100 */
try
{
$lastLogin = Db::i()->select( 'MIN(upgrade_date)', 'core_upgrade_history', [ 'upgrade_app=? AND upgrade_version_id>=?', 'core', 106100 ] )->first();
}
catch( \UnderflowException $e )
{
/* This could be a new install, or IN_DEV where upgrade history isn't available */
return false;
}
}
$lastLoginObj = DateTime::ts( $lastLogin );
/* Likely to be the first login */
if( $this->joined > $lastLoginObj )
{
return false;
}
/* If this login is within the period, don't send an email */
if( $lastLoginObj > DateTime::create()->sub( new \DateInterval( static::LOGIN_INACTIVITY_NOTIFICATION ) ) )
{
return false;
}
/* Device data */
$device = Device::loadOrCreate( $this, false );
try
{
$location = GeoLocation::getRequesterLocation();
}
catch ( \Exception $e )
{
$location = NULL;
}
Email::buildFromTemplate( 'core', 'loginAfterInactivity', array( $this, $device, $location ), Email::TYPE_TRANSACTIONAL )->send( $this );
return true;
}
/**
* Webhook filters
*