Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

+461 -39
View File
@@ -26,10 +26,15 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
const TYPE_OPEN = 'open';
const TYPE_CLOSED = 'closed';
const TYPE_PRIVATE = 'private';
const TYPE_READONLY = 'readonly';
const STATUS_MEMBER = 'member';
const STATUS_INVITED = 'invited';
const STATUS_INVITED_BYPASSING_PAYMENT = 'invited_bypassing_payment';
const STATUS_REQUESTED = 'requested';
const STATUS_WAITING_PAYMENT = 'payment_pending';
const STATUS_EXPIRED = 'expired';
const STATUS_EXPIRED_MODERATOR = 'expired_moderator';
const STATUS_DECLINED = 'declined';
const STATUS_BANNED = 'banned';
const STATUS_MODERATOR = 'moderator';
@@ -45,6 +50,11 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
*/
public static $databaseTable = 'core_clubs';
/**
* @brief Use a default cover photo
*/
public static $coverPhotoDefault = true;
/* !Fetch Clubs */
/**
@@ -72,10 +82,10 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
* @param \IPS\Member $member The member to base permission off or NULL for all clubs
* @param int $limit Number to get
* @param string $sortOption The sort option ('last_activity', 'members', 'content' or 'created')
* @param bool|\IPS\Member $mineOnly Limit to clubs a particular member has joined (TRUE to use the same value as $member)
* @param bool|\IPS\Member|array $mineOnly Limit to clubs a particular member has joined (TRUE to use the same value as $member). Can also provide an array as array( 'member' => \IPS\Member, 'statuses' => array( STATUS_MEMBER... ) ) to limit to certain member statuses
* @param array $filters Custom field filters
* @param mixed $extraWhere Additional WHERE clause
* @return \IPS\Patterns\ActiveRecordIterator
* @return \IPS\Patterns\ActiveRecordIterator|array
*/
public static function clubs( \IPS\Member $member = NULL, $limit, $sortOption, $mineOnly=FALSE, $filters=array(), $extraWhere=NULL )
{
@@ -95,7 +105,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
if ( $member->member_id )
{
$joins['membership'] = array( array( 'core_clubs_memberships', 'membership' ), array( 'membership.club_id=core_clubs.id AND membership.member_id=?', $member->member_id ) );
$where[] = array( "( type<>? OR membership.status IN('" . static::STATUS_MEMBER . "','" . static::STATUS_MODERATOR . "','" . static::STATUS_LEADER . "') )", static::TYPE_PRIVATE );
$where[] = array( "( type<>? OR membership.status IN('" . static::STATUS_MEMBER . "','" . static::STATUS_MODERATOR . "','" . static::STATUS_LEADER . "','" . static::STATUS_EXPIRED . "','" . static::STATUS_EXPIRED_MODERATOR . "') )", static::TYPE_PRIVATE );
}
else
{
@@ -106,7 +116,16 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
/* Restrict to clubs we have joined */
if ( $mineOnly )
{
$mineOnly = ( $mineOnly === TRUE ) ? $member : $mineOnly;
if ( is_array( $mineOnly ) )
{
$statuses = $mineOnly['statuses'];
$mineOnly = $mineOnly['member'];
}
else
{
$mineOnly = ( $mineOnly === TRUE ) ? $member : $mineOnly;
$statuses = array( static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER, static::STATUS_EXPIRED, static::STATUS_EXPIRED_MODERATOR );
}
if ( !$mineOnly->member_id )
{
return array();
@@ -114,12 +133,12 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
if ( $member and $mineOnly->member_id === $member->member_id and isset( $joins['membership'] ) )
{
$where[] = array( "membership.status IN('" . static::STATUS_MEMBER . "','" . static::STATUS_MODERATOR . "','" . static::STATUS_LEADER . "')" );
$where[] = array( "membership.status IN('" . static::STATUS_MEMBER . "','" . static::STATUS_MODERATOR . "','" . static::STATUS_LEADER . "','" . static::STATUS_EXPIRED . "','" . static::STATUS_EXPIRED_MODERATOR . "')" );
}
else
{
$joins['others_membership'] = array( array( 'core_clubs_memberships', 'others_membership' ), array( 'others_membership.club_id=core_clubs.id AND others_membership.member_id=?', $mineOnly->member_id ) );
$where[] = array( "others_membership.status IN('" . static::STATUS_MEMBER . "','" . static::STATUS_MODERATOR . "','" . static::STATUS_LEADER . "')" );
$where[] = array( "others_membership.status IN('" . static::STATUS_MEMBER . "','" . static::STATUS_MODERATOR . "','" . static::STATUS_LEADER . "','" . static::STATUS_EXPIRED . "','" . static::STATUS_EXPIRED_MODERATOR . "')" );
}
}
@@ -131,7 +150,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
{
if ( is_array( $v ) )
{
$where[] = array( \IPS\Db::i()->in( "field_{$k}", $v ) );
$where[] = array( \IPS\Db::i()->findInSet( "field_{$k}", $v ) );
}
else
{
@@ -279,12 +298,21 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
if ( $acp or ( $new and count( $availableTypes ) > 1 ) )
{
$form->add( new \IPS\Helpers\Form\Radio( 'club_type', $this->type, TRUE, array( 'options' => $new ? $availableTypes : array(
\IPS\Member\Club::TYPE_PUBLIC => 'club_type_' . \IPS\Member\Club::TYPE_PUBLIC,
\IPS\Member\Club::TYPE_OPEN => 'club_type_' . \IPS\Member\Club::TYPE_OPEN,
\IPS\Member\Club::TYPE_CLOSED => 'club_type_' . \IPS\Member\Club::TYPE_CLOSED,
\IPS\Member\Club::TYPE_PRIVATE => 'club_type_' . \IPS\Member\Club::TYPE_PRIVATE,
) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'club_type', $this->type, TRUE, array(
'options' => $new ? $availableTypes : array(
\IPS\Member\Club::TYPE_PUBLIC => 'club_type_' . \IPS\Member\Club::TYPE_PUBLIC,
\IPS\Member\Club::TYPE_OPEN => 'club_type_' . \IPS\Member\Club::TYPE_OPEN,
\IPS\Member\Club::TYPE_CLOSED => 'club_type_' . \IPS\Member\Club::TYPE_CLOSED,
\IPS\Member\Club::TYPE_PRIVATE => 'club_type_' . \IPS\Member\Club::TYPE_PRIVATE,
\IPS\Member\Club::TYPE_READONLY => 'club_type_' . \IPS\Member\Club::TYPE_READONLY,
),
'toggles' => array(
\IPS\Member\Club::TYPE_OPEN => array( 'club_membership_fee' ),
\IPS\Member\Club::TYPE_CLOSED => array( 'club_membership_fee' ),
\IPS\Member\Club::TYPE_PRIVATE => array( 'club_membership_fee' ),
\IPS\Member\Club::TYPE_READONLY => array( 'club_membership_fee' ),
)
) ) );
if ( $acp )
{
@@ -294,6 +322,63 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
$form->add( new \IPS\Helpers\Form\TextArea( 'club_about', $this->about ) );
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on and \IPS\Member::loggedIn()->group['gbw_paid_clubs'] )
{
$form->add( new \IPS\Helpers\Form\Radio( 'club_membership_fee', ( $this->id and $this->fee ) ? 'paid' : 'free', TRUE, array(
'options' => array(
'free' => 'club_membership_free',
'paid' => 'club_membership_paid'
),
'toggles' => array(
'paid' => array( 'club_fee', 'club_renewals' )
)
), NULL, NULL, NULL, 'club_membership_fee' ) );
$commissionBlurb = NULL;
$fees = NULL;
if ( $_fees = \IPS\Settings::i()->clubs_paid_transfee )
{
$fees = array();
foreach ( $_fees as $fee )
{
$fees[] = (string) ( new \IPS\nexus\Money( $fee['amount'], $fee['currency'] ) );
}
$fees = \IPS\Member::loggedIn()->language()->formatList( $fees, \IPS\Member::loggedIn()->language()->get('or_list_format') );
}
if ( \IPS\Settings::i()->clubs_paid_commission and $fees )
{
$commissionBlurb = \IPS\Member::loggedIn()->language()->addToStack( 'club_fee_desc_both', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->clubs_paid_commission, $fees ) ) );
}
elseif ( \IPS\Settings::i()->clubs_paid_commission )
{
$commissionBlurb = \IPS\Member::loggedIn()->language()->addToStack('club_fee_desc_percent', FALSE, array( 'sprintf' => \IPS\Settings::i()->clubs_paid_commission ) );
}
elseif ( $fees )
{
$commissionBlurb = \IPS\Member::loggedIn()->language()->addToStack('club_fee_desc_fee', FALSE, array( 'sprintf' => $fees ) );
}
\IPS\Member::loggedIn()->language()->words['club_fee_desc'] = $commissionBlurb;
$form->add( new \IPS\nexus\Form\Money( 'club_fee', $this->id ? json_decode( $this->fee, TRUE ) : array(), NULL, array(), NULL, NULL, NULL, 'club_fee' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'club_renewals', $this->id ? ( $this->renewal_term ? 1 : 0 ) : 0, TRUE, array(
'options' => array( 0 => 'club_renewals_off', 1 => 'club_renewals_on' ),
'toggles' => array( 1 => array( 'club_renewal_term' ) )
), NULL, NULL, NULL, 'club_renewals' ) );
\IPS\Member::loggedIn()->language()->words['club_renewal_term_desc'] = $commissionBlurb;
$renewTermForEdit = NULL;
if ( $this->id and $this->renewal_term )
{
$renewPrices = array();
foreach ( json_decode( $this->renewal_price, TRUE ) as $currency => $data )
{
$renewPrices[ $currency ] = new \IPS\nexus\Money( $data['amount'], $currency );
}
$renewTermForEdit = new \IPS\nexus\Purchase\RenewalTerm( $renewPrices, new \DateInterval( 'P' . $this->renewal_term . mb_strtoupper( $this->renewal_units ) ) );
}
$form->add( new \IPS\nexus\Form\RenewalTerm( 'club_renewal_term', $renewTermForEdit, NULL, array( 'allCurrencies' => TRUE ), NULL, NULL, NULL, 'club_renewal_term' ) );
}
$form->add( new \IPS\Helpers\Form\Upload( 'club_profile_photo', $this->profile_photo ? \IPS\File::get( 'core_Clubs', $this->profile_photo ) : NULL, FALSE, array( 'storageExtension' => 'core_Clubs', 'image' => array( 'maxWidth' => 200, 'maxHeight' => 200 ) ) ) );
if ( \IPS\Settings::i()->clubs_locations )
@@ -310,7 +395,13 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
if ( $values = $form->values() )
{
$this->name = $values['club_name'];
/* If there is only one type available, set it. */
if( count( $availableTypes ) == 1 )
{
$values['club_type'] = key( $availableTypes );
}
$needToUpdatePermissions = FALSE;
if ( $acp )
{
@@ -355,6 +446,36 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
$this->location_long = NULL;
}
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on and \IPS\Member::loggedIn()->group['gbw_paid_clubs'] )
{
switch ( $values['club_membership_fee'] )
{
case 'free':
$this->fee = NULL;
$this->renewal_term = 0;
$this->renewal_units = NULL;
$this->renewal_price = NULL;
break;
case 'paid':
$this->fee = json_encode( $values['club_fee'] );
if ( $values['club_renewals'] and $values['club_renewal_term'] )
{
$term = $values['club_renewal_term']->getTerm();
$this->renewal_term = $term['term'];
$this->renewal_units = $term['unit'];
$this->renewal_price = json_encode( $values['club_renewal_term']->cost );
}
else
{
$this->renewal_term = 0;
$this->renewal_units = NULL;
$this->renewal_price = NULL;
}
break;
}
}
$this->save();
if ( $new )
@@ -369,7 +490,15 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
if ( isset( $values["core_clubfield_{$field->id}"] ) )
{
$helper = $field->buildHelper();
$customFieldValues[ "field_{$field->id}" ] = $helper::stringValue( $values["core_clubfield_{$field->id}"] );
if ( $helper instanceof \IPS\Helpers\Form\Upload )
{
$customFieldValues[ "field_{$field->id}" ] = (string) $values["core_clubfield_{$field->id}"];
}
else
{
$customFieldValues[ "field_{$field->id}" ] = $helper::stringValue( $values["core_clubfield_{$field->id}"] );
}
if ( $field->type === 'Editor' )
{
@@ -396,7 +525,47 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
catch ( \Exception $e ) { }
}
}
if( $new and \IPS\Settings::i()->clubs_require_approval and !$this->approved )
{
/* Send notification to mods */
$moderators = array( 'm' => array(), 'g' => array() );
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
{
$canView = FALSE;
if ( $mod['perms'] == '*' )
{
$canView = TRUE;
}
if ( $canView === FALSE )
{
$perms = json_decode( $mod['perms'], TRUE );
if ( isset( $perms['can_access_all_clubs'] ) AND $perms['can_access_all_clubs'] === TRUE )
{
$canView = TRUE;
}
}
if ( $canView === TRUE )
{
$moderators[ $mod['type'] ][] = $mod['id'];
}
}
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'unapproved_club', $this, array( $this ) );
foreach ( \IPS\Db::i()->select( '*', 'core_members', ( count( $moderators['m'] ) ? \IPS\Db::i()->in( 'member_id', $moderators['m'] ) . ' OR ' : '' ) . \IPS\Db::i()->in( 'member_group_id', $moderators['g'] ) . ' OR ' . \IPS\Db::i()->findInSet( 'mgroup_others', $moderators['g'] ) ) as $member )
{
if( $member['member_id'] != \IPS\Member::loggedIn()->member_id )
{
$notification->recipients->attach( \IPS\Member::constructFromData( $member ) );
}
}
if( count( $notification->recipients ) )
{
$notification->send();
}
}
return NULL;
}
@@ -440,8 +609,19 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
}
$photo->editable = $this->isLeader();
$photo->object = $this;
return $photo;
}
/**
* Produce a random hex color for a background
*
* @return string
*/
public function coverPhotoBackgroundColor()
{
return $this->staticCoverPhotoBackgroundColor( $this->name );
}
/**
* Location
@@ -456,6 +636,137 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
}
return NULL;
}
/**
* Is paid?
*
* @return string|NULL
*/
public function isPaid()
{
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on and $this->fee )
{
return TRUE;
}
return FALSE;
}
/**
* Message to explain paid club joining process
*
* @return string
*/
public function memberFeeMessage()
{
if ( $this->type === static::TYPE_CLOSED )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'club_closed_join_fee', FALSE, array( 'sprintf' => array( $this->priceBlurb() ) ) );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( 'club_open_join_fee', FALSE, array( 'sprintf' => array( $this->priceBlurb() ) ) );
}
}
/**
* Joining fee
*
* @param string|NULL $currency Desired currency, or NULL to choose based on member's chosen currency
* @return \IPS\nexus\Money|NULL
*/
public function joiningFee( $currency = NULL )
{
if ( $this->isPaid() )
{
if ( !$currency )
{
$currency = ( isset( $_SESSION['currency'] ) and in_array( $_SESSION['currency'], \IPS\nexus\Money::currencies() ) ) ? $_SESSION['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency();
}
$costs = json_decode( $this->fee, TRUE );
if ( is_array( $costs ) and isset( $costs[ $currency ]['amount'] ) and $costs[ $currency ]['amount'] )
{
return new \IPS\nexus\Money( $costs[ $currency ]['amount'], $currency );
}
}
return NULL;
}
/**
* Joining fee
*
* @param string|NULL $currency Desired currency, or NULL to choose based on member's chosen currency
* @return \IPS\nexus\Money|NULL
* @throws \OutOfRangeException
*/
public function renewalTerm( $currency = NULL )
{
if ( $this->renewal_price and $renewalPrices = json_decode( $this->renewal_price, TRUE ) )
{
if ( !$currency )
{
$currency = ( isset( $_SESSION['currency'] ) and in_array( $_SESSION['currency'], \IPS\nexus\Money::currencies() ) ) ? $_SESSION['currency'] : \IPS\nexus\Customer::loggedIn()->defaultCurrency();
}
if ( isset( $renewalPrices[ $currency ] ) )
{
return new \IPS\nexus\Purchase\RenewalTerm( new \IPS\nexus\Money( $renewalPrices[ $currency ]['amount'], $currency ), new \DateInterval( 'P' . $this->renewal_term . mb_strtoupper( $this->renewal_units ) ) );
}
else
{
throw new \OutOfRangeException;
}
}
return NULL;
}
/**
* Price Blurb
*
* @return string|NULL
*/
public function priceBlurb()
{
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on )
{
if ( $this->isPaid() )
{
if ( $fee = $this->joiningFee() )
{
try
{
$renewalTerm = $this->renewalTerm( $fee->currency );
if ( $renewalTerm->cost->amount == $fee->amount )
{
return $renewalTerm;
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( 'club_fee_plus_renewal', FALSE, array( 'sprintf' => array( $fee, $renewalTerm ) ) );
}
}
catch ( \OutOfRangeException $e )
{
return \IPS\Member::loggedIn()->language()->addToStack('club_paid_unavailable');
}
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('club_paid_unavailable');
}
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack('club_membership_free');
}
}
return NULL;
}
/* !Manage Memberships */
@@ -465,7 +776,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
* @param array $statuses The membership statuses to get
* @param int $limit Number to get
* @param string $order ORDER BY clause
* @param int $returnType 0 = core_clubs_memberships rows, 1 = core_clubs_memberships plus \IPS\Member::columnsForPhoto(), 2 = full core_members rows, 3 = same as 1 but also getting name of adder/invitee, 4 = count only
* @param int $returnType 0 = core_clubs_memberships rows, 1 = core_clubs_memberships plus \IPS\Member::columnsForPhoto(), 2 = full core_members rows, 3 = same as 1 but also getting name of adder/invitee, 4 = count only, 5 = same as 3 but also getting expire date
* @return \IPS\Db\Select|int
*/
public function members( $statuses = array( 'member', 'moderator', 'leader' ), $limit = 25, $order = 'core_clubs_memberships.joined ASC', $returnType = 1 )
@@ -483,29 +794,39 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
else
{
$columns = 'core_clubs_memberships.member_id,core_clubs_memberships.joined,core_clubs_memberships.status,core_clubs_memberships.added_by,core_clubs_memberships.invited_by';
if ( $returnType === 1 or $returnType === 3 )
if ( $returnType === 1 or $returnType === 3 or $returnType === 5 )
{
$columns .= ',' . implode( ',', array_map( function( $column ) {
return 'core_members.' . $column;
}, \IPS\Member::columnsForPhoto() ) );
}
if ( $returnType === 3 )
if ( $returnType === 3 or $returnType === 5 )
{
$columns .= ',added_by.name,invited_by.name';
if ( $returnType === 5 and \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->isPaid() and $this->renewal_price )
{
$columns .= ',nexus_purchases.ps_active,nexus_purchases.ps_expire';
}
}
}
$select = \IPS\Db::i()->select( $columns, 'core_clubs_memberships', array( array( 'club_id=?', $this->id ), array( \IPS\Db::i()->in( 'status', $statuses ) ) ), $order, $limit, NULL, NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS + \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS );
}
if ( $returnType === 1 or $returnType === 2 or $returnType === 3 )
if ( $returnType === 1 or $returnType === 2 or $returnType === 3 or $returnType === 5 )
{
$select->join( 'core_members', 'core_members.member_id=core_clubs_memberships.member_id' );
}
if ( $returnType === 3 )
if ( $returnType === 3 or $returnType === 5 )
{
$select->join( array( 'core_members', 'added_by' ), 'added_by.member_id=core_clubs_memberships.added_by' );
$select->join( array( 'core_members', 'invited_by' ), 'invited_by.member_id=core_clubs_memberships.invited_by' );
if ( $returnType === 5 and \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->isPaid() and $this->renewal_price )
{
$select->join( 'nexus_purchases', array( 'ps_app=? AND ps_type=? AND ps_member=core_clubs_memberships.member_id AND ps_item_id=? AND ps_cancelled=0', 'core', 'club', $this->id ) );
}
}
return $select;
@@ -556,6 +877,11 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
) );
$member->rebuildPermissionArray();
if ( \IPS\Settings::i()->club_nodes_in_apps )
{
$member->create_menu = NULL;
$member->save();
}
}
catch ( \IPS\Db\Exception $e )
{
@@ -573,10 +899,15 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
{
$save['joined'] = time();
}
\IPS\Db::i()->update( 'core_clubs_memberships', $save, array( 'club_id=? AND member_id=?', $this->id, $member->member_id ) );
$member->rebuildPermissionArray();
if ( \IPS\Settings::i()->club_nodes_in_apps )
{
$member->create_menu = NULL;
$member->save();
}
}
else
{
@@ -599,7 +930,13 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
public function removeMember( \IPS\Member $member )
{
\IPS\Db::i()->delete( 'core_clubs_memberships', array( 'club_id=? AND member_id=?', $this->id, $member->member_id ) );
$member->rebuildPermissionArray();
if ( \IPS\Settings::i()->club_nodes_in_apps )
{
$member->create_menu = NULL;
$member->save();
}
}
/**
@@ -609,7 +946,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
*/
public function recountMembers()
{
$this->members = \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs_memberships', array( 'club_id=? AND ( status=? OR status=? OR status=? )', $this->id, static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER ) );
$this->members = \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs_memberships', array( 'club_id=? AND ( status=? OR status=? OR status=? OR status=? OR status=? )', $this->id, static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER, static::STATUS_EXPIRED, static::STATUS_EXPIRED_MODERATOR ) );
$this->save();
}
@@ -641,6 +978,11 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
return array_unique( $return );
}
/**
* @brief Cached nodes
*/
protected $cachedNodes = NULL;
/**
* Get Node names and URLs
@@ -649,25 +991,53 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
*/
public function nodes()
{
$return = array();
foreach ( \IPS\Db::i()->select( '*', 'core_clubs_node_map', array( 'club_id=?', $this->id ) ) as $row )
if( $this->cachedNodes === NULL )
{
$class = $row['node_class'];
$this->cachedNodes = array();
$return[ $row['id'] ] = array(
'name' => $row['name'],
'url' => \IPS\Http\Url::internal( $class::$urlBase . $row['node_id'], 'front', $class::$urlTemplate, array( \IPS\Http\Url\Friendly::seoTitle( $row['name'] ) ) ),
'node_class' => $row['node_class'],
'node_id' => $row['node_id'],
);
foreach ( \IPS\Db::i()->select( '*', 'core_clubs_node_map', array( 'club_id=?', $this->id ) ) as $row )
{
$class = $row['node_class'];
$classBits = explode( '\\', $class );
if( !\IPS\Application::load( $classBits[1] )->_enabled )
{
continue;
}
$this->cachedNodes[ $row['id'] ] = array(
'name' => $row['name'],
'url' => \IPS\Http\Url::internal( $class::$urlBase . $row['node_id'], 'front', $class::$urlTemplate, array( \IPS\Http\Url\Friendly::seoTitle( $row['name'] ) ) ),
'node_class' => $row['node_class'],
'node_id' => $row['node_id'],
);
}
}
return $return;
return $this->cachedNodes;
}
/* !Permissions */
/**
* Load and check permissions
*
* @param mixed $id ID
* @return static
* @throws \OutOfRangeException
*/
public static function loadAndCheckPerms( $id )
{
$obj = static::load( $id );
if ( !$obj->canView() )
{
throw new \OutOfRangeException;
}
return $obj;
}
/**
* Can a member see this club and who's in it?
*
@@ -677,6 +1047,12 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
public function canView( \IPS\Member $member = NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
/* If we can't access the module, stop here */
if ( !$member->canAccessModule( \IPS\Application\Module::get( 'core', 'clubs', 'front' ) ) )
{
return FALSE;
}
/* If it's not approved, only moderators and the person who created it can see it */
if ( \IPS\Settings::i()->clubs_require_approval and !$this->approved )
@@ -697,7 +1073,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
}
/* Otherwise, only if they're a member or have been invited */
return in_array( $this->memberStatus( $member ), array( static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER, static::STATUS_INVITED ) );
return in_array( $this->memberStatus( $member ), array( static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER, static::STATUS_INVITED, static::STATUS_INVITED_BYPASSING_PAYMENT, static::STATUS_EXPIRED, static::STATUS_EXPIRED_MODERATOR ) );
}
/**
@@ -729,7 +1105,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
/* If they're already a member, or have aleready asked to join, they can't join again */
$memberStatus = $this->memberStatus( $member );
if ( in_array( $memberStatus, array( static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER, static::STATUS_REQUESTED, static::STATUS_DECLINED ) ) )
if ( in_array( $memberStatus, array( static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER, static::STATUS_REQUESTED, static::STATUS_DECLINED, static::STATUS_EXPIRED, static::STATUS_EXPIRED_MODERATOR ) ) )
{
return FALSE;
}
@@ -740,10 +1116,10 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
return FALSE;
}
/* If it's private, they have to be invited */
if ( $this->type === static::TYPE_PRIVATE )
/* If it's private or read-only, they have to be invited */
if ( $this->type === static::TYPE_PRIVATE or $this->type === static::TYPE_READONLY )
{
return $memberStatus === static::STATUS_INVITED;
return in_array( $memberStatus, array( static::STATUS_INVITED, static::STATUS_INVITED_BYPASSING_PAYMENT ) );
}
/* Otherwise they can join */
@@ -762,6 +1138,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
{
case static::TYPE_PUBLIC:
case static::TYPE_OPEN:
case static::TYPE_READONLY:
return TRUE;
case static::TYPE_CLOSED:
@@ -787,6 +1164,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
case static::TYPE_OPEN:
case static::TYPE_CLOSED:
case static::TYPE_PRIVATE:
case static::TYPE_READONLY:
$member = $member ?: \IPS\Member::loggedIn();
return $member->modPermission('can_access_all_clubs') or in_array( $this->memberStatus( $member ), array( static::STATUS_MEMBER, static::STATUS_MODERATOR, static::STATUS_LEADER ) );
}
@@ -816,6 +1194,7 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
case static::TYPE_CLOSED:
case static::TYPE_PRIVATE:
case static::TYPE_READONLY:
return $this->isLeader( $member );
}
}
@@ -888,6 +1267,49 @@ class _Club extends \IPS\Patterns\ActiveRecord implements \IPS\Content\Embeddabl
return $this->_memberStatuses[ $member->member_id ];
}
/* ! Following */
const FOLLOW_PUBLIC = 1;
const FOLLOW_ANONYMOUS = 2;
/**
* @brief Cache for current follow data, used on "My Followed Content" screen
*/
public $_followData;
/**
* @brief Application
*/
public static $application = 'core';
/**
* Container Follower Count
*
* @return int
*/
public function followerCount()
{
return \IPS\Db::i()->select( 'COUNT(*)', 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', 'core', 'club', $this->id ) )->first();
}
/**
* Followers
*
* @param int $privacy static::FOLLOW_PUBLIC + static::FOLLOW_ANONYMOUS
* @param array $frequencyTypes array( 'immediate', 'daily', 'weekly' )
* @param \IPS\DateTime|int|NULL $date Only users who started following before this date will be returned. NULL for no restriction
* @param int|array $limit LIMIT clause
* @param string $order Column to order by
* @param int $flags Flags to pass to select (e.g. \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS)
* @param int
* @return \IPS\Db\Select|NULL
* @throws \BadMethodCallException
*/
public function followers( $privacy=3, $frequencyTypes=array( 'immediate', 'daily', 'weekly' ), $date=NULL, $limit=array( 0, 25 ), $order=NULL, $flags=\IPS\Db::SELECT_SQL_CALC_FOUND_ROWS )
{
return static::_followers( 'club', $this->id, $privacy, $frequencyTypes, $date, $limit, $order, $flags );
}
/* ! Utility */
/**
+1 -1
View File
@@ -112,7 +112,7 @@ class _CustomField extends \IPS\CustomField
/**
* @brief [CustomField] Upload Storage Extension
*/
public static $uploadStorageExtension = 'core_';
public static $uploadStorageExtension = 'core_ClubField';
/**
* Get fields
+33 -10
View File
@@ -112,8 +112,8 @@ class _Device extends \IPS\Patterns\ActiveRecord
throw new \OutOfRangeException;
}
/* Validate login key is valid */
if ( !\IPS\Login::compareHashes( (string) $device->login_key, (string) $loginKey ) )
/* Validate login key is valid - if there is no login_key set for the device, it is because the device has been deauthorized */
if ( !$device->login_key OR !\IPS\Login::compareHashes( (string) $device->login_key, (string) $loginKey ) )
{
throw new \OutOfRangeException;
}
@@ -154,12 +154,12 @@ class _Device extends \IPS\Patterns\ActiveRecord
/**
* Update after logging in / automatic authentication with current request's user agent / IP address, etc.
*
* @param bool|null $rememberMe Remember me? NULL can be provided if the login is being processed from somewhere that doesn't ask
* @param string $loginHandler The login handler which processed the login, or NULL if updating an existing login. Can also be empty string for logins that weren't processed by any handler (such as after registration or using the lost password feature)
* @param bool $refreshLoginKey If login key should be refreshed (FALSE for automatic logins which will need the same login key subsequently)
* @param bool|null $rememberMe Remember me? NULL can be provided if the login is being processed from somewhere that doesn't ask
* @param \IPS\Login\Handler $loginHandler The login handler which processed the login, or NULL if updating an existing login. Can also be empty string for logins that weren't processed by any handler (such as after registration or using the lost password feature)
* @param bool $refreshLoginKey If login key should be refreshed (FALSE for automatic logins which will need the same login key subsequently)
* @return void
*/
public function updateAfterAuthentication( $rememberMe, $loginHandler=NULL, $refreshLoginKey=TRUE )
public function updateAfterAuthentication( $rememberMe, \IPS\Login\Handler $loginHandler=NULL, $refreshLoginKey=TRUE )
{
$this->user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL;
if ( $refreshLoginKey )
@@ -169,7 +169,7 @@ class _Device extends \IPS\Patterns\ActiveRecord
$this->last_seen = time();
if ( $loginHandler !== NULL )
{
$this->login_handler = $loginHandler;
$this->login_handler = $loginHandler->id;
}
$this->save();
@@ -218,6 +218,27 @@ class _Device extends \IPS\Patterns\ActiveRecord
return \IPS\Http\UserAgent::parse( $this->user_agent );
}
/**
* Get login method
*
* @return \IPS\Login\Handler|NULL
*/
public function loginMethod()
{
if ( is_numeric( $this->login_handler ) )
{
try
{
return \IPS\Login\Handler::load( $this->login_handler );
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
}
return NULL;
}
/**
* Send email to user notifying them about the new device
*
@@ -225,10 +246,10 @@ class _Device extends \IPS\Patterns\ActiveRecord
*/
protected function sendNewDeviceEmail()
{
$member = \IPS\Member::load( $this->member_id );
if ( \IPS\Settings::i()->new_device_email )
{
$member = \IPS\Member::load( $this->member_id );
{
try
{
$location = \IPS\GeoLocation::getByIp( \IPS\Request::i()->ipAddress() );
@@ -240,6 +261,8 @@ class _Device extends \IPS\Patterns\ActiveRecord
\IPS\Email::buildFromTemplate( 'core', 'new_device', array( $member, $this, $location ) )->send( $member );
}
$member->logHistory( 'core', 'login', array( 'type' => 'new_device', 'device' => $this->device_key ), FALSE );
}
/**
+27 -3
View File
@@ -79,7 +79,9 @@ class _Group extends \IPS\Patterns\ActiveRecord
'gbw_post_highlight' => 1, // 1 means on, 0 means off
'gbw_hide_group' => 2, // Hide this group on the front end in search and similar areas: 1 is on, 0 is off
// 4 is deprecated (previously gbw_lock_unlock_own)
'gbw_promote' => 8 // Allow users in this group to promote to facebook/twitter
'gbw_promote' => 8, // Allow users in this group to promote to facebook/twitter
'gbw_immune_auto_mod' => 16, // Users in this group can not be auto moderated
'gbw_paid_clubs' => 32 // Users in this group can create paid clubs
)
)
);
@@ -183,6 +185,7 @@ class _Group extends \IPS\Patterns\ActiveRecord
public function __clone()
{
$oldId = $this->g_id;
$oldGroup = $this;
parent::__clone();
/* Rebuild permission indexes */
@@ -208,6 +211,16 @@ class _Group extends \IPS\Patterns\ActiveRecord
\IPS\Db::i()->update( 'core_permission_index', $index, array( 'perm_id = ?', $index['perm_id'] ) );
}
$extensions = \IPS\Application::allExtensions( 'core', 'GroupForm', FALSE, 'core', 'GroupSettings', TRUE );
/* Process each extension */
foreach ( $extensions as $class )
{
if( method_exists( $class, 'cloneGroup' ) )
{
$class->cloneGroup( $oldGroup, $this );
}
}
\IPS\Lang::saveCustom( 'core', "core_group_{$this->g_id}", iterator_to_array( \IPS\Db::i()->select( '*', 'core_sys_lang_words', array( 'word_key=?', "core_group_{$oldId}" ) )->setKeyField('lang_id')->setValueField('word_custom') ) );
/* Clear application and module store so that permissions are correctly rebuilt */
@@ -286,7 +299,7 @@ class _Group extends \IPS\Patterns\ActiveRecord
*/
public function formatName( $name )
{
return ( $this->prefix . htmlspecialchars( $name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . $this->suffix );
return ( $this->prefix . htmlspecialchars( $name, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . $this->suffix );
}
/**
@@ -340,6 +353,16 @@ class _Group extends \IPS\Patterns\ActiveRecord
$group->save();
}
}
$extensions = \IPS\Application::allExtensions( 'core', 'GroupForm', FALSE, 'core', 'GroupSettings', TRUE );
/* Process each extension */
foreach ( $extensions as $class )
{
if( method_exists( $class, 'delete' ) )
{
$class->delete( $this );
}
}
parent::delete();
\IPS\Lang::deleteCustom( 'core', 'core_group_' . $this->g_id );
@@ -355,12 +378,13 @@ class _Group extends \IPS\Patterns\ActiveRecord
/**
* Get output for API
*
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
* @return array
* @apiresponse int id ID number
* @apiresponse string name Name
* @apiresponse string formattedName Name with formatting
*/
public function apiOutput()
public function apiOutput( \IPS\Member $authorizedMember = NULL )
{
return array(
'id' => $this->g_id,
+48 -1
View File
@@ -338,6 +338,11 @@ class _GroupPromotion extends \IPS\Node\Model
*/
protected static $extensions = NULL;
/**
* @brief Flag to indicate whether or not to check secondary groups
*/
public $memberFilterCheckSecondaryGroups = FALSE;
/**
* Check if a member matches the rule
*
@@ -357,7 +362,7 @@ class _GroupPromotion extends \IPS\Node\Model
if( isset( static::$extensions[ $key ] ) )
{
/* Ask the extension if this member matches the defined rule...if not, just return FALSE now */
if( !static::$extensions[ $key ]->matches( $member, $filter ) )
if( !static::$extensions[ $key ]->matches( $member, $filter, $this ) )
{
return FALSE;
}
@@ -367,4 +372,46 @@ class _GroupPromotion extends \IPS\Node\Model
/* If we are still here, then the rule matched */
return TRUE;
}
/**
* Return a warning if this promotion uses not existing groups
*
* @return string|NULL
*/
public function get__description()
{
$action = $this->_actions;
$showWarning = FALSE;
if ( $action['primary_group'] )
{
try
{
$group = \IPS\Member\Group::load( $action['primary_group'] );
}
catch ( \OutOfRangeException $e )
{
$showWarning = TRUE;
}
}
if ( count( $action['secondary_group'] ) )
{
foreach ( $action['secondary_group'] as $key => $group )
{
try
{
$group = \IPS\Member\Group::load( $group );
}
catch ( \OutOfRangeException $e )
{
$showWarning = TRUE;
}
}
}
if ( $showWarning )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'grouppromotion_warning' );
}
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ class _History extends \IPS\Helpers\Table\Db
}
/* This is here specifically so that log_type is always shown first, if required */
$this->include = array_merge( $this->include, array( 'log_date', 'log_data' ) );
$this->include = array_merge( $this->include, array( 'log_id', 'log_date', 'log_data' ) );
if ( $showIp )
{
+13 -13
View File
@@ -28,9 +28,9 @@ class _LetterPhoto
protected $fileStorageClass = 'core_Profile';
/**
* @brief Member name
* @brief Member object
*/
protected $name = NULL;
protected $member = NULL;
/**
* @brief Text size
@@ -40,12 +40,12 @@ class _LetterPhoto
/**
* Create a new photo object
*
* @param string $name Member's name
* @param \IPS\Member $member Member object
* @return void
*/
public function __construct( $name='' )
public function __construct( $member )
{
$this->name = $name;
$this->member = $member;
}
/**
@@ -68,7 +68,7 @@ class _LetterPhoto
$this->textSize = ( ( $maxWidth / 2 ) / $letterCount );
/* If we don't have a name, there's nothing to create */
if( !$this->name )
if( !$this->member->name )
{
return NULL;
}
@@ -76,7 +76,7 @@ class _LetterPhoto
/* Get the first character of the name...if we can't detect it, there's again nothing to convert */
$letters = $this->getLetters( $letterCount );
if( !$letters )
if( $letters === NULL )
{
return NULL;
}
@@ -93,7 +93,7 @@ class _LetterPhoto
/* Save the image and return it */
try
{
return \IPS\File::create( $this->fileStorageClass, $letters . '.png', (string) $image, NULL, TRUE );
return \IPS\File::create( $this->fileStorageClass, $letters . '_member_' . $this->member->member_id . '.png', (string) $image, NULL, TRUE, NULL, FALSE );
}
catch( \Exception $e )
{
@@ -111,10 +111,10 @@ class _LetterPhoto
*/
protected function getLetters( $letters=1 )
{
$name = str_replace( array( '<', '>', '=', '-', '+', '"', "'" ), '', $this->name );
$name = str_replace( array( '<', '>', '=', '-', '+', '"', "'" ), '', $this->member->name );
$name = preg_replace( "/(\pP)+/u", '', trim( $name ) );
return mb_strtoupper( mb_substr( $name, 0, $letters ) );
return $name ? mb_strtoupper( mb_substr( $name, 0, $letters ) ) : NULL;
}
/**
@@ -137,7 +137,7 @@ class _LetterPhoto
*
* @return array (RGB value)
*/
protected function generateColorCode()
public function generateColorCode()
{
/* If we've already generated a hue on this page load, use the golden ratio to find a number sufficiently distinct */
if( static::$lastHue )
@@ -154,7 +154,7 @@ class _LetterPhoto
return $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue );
}
$hue = ( ( ord( \mb_strtolower( $this->name ) ) - 97 ) / 25.0 ) + 0.25;
$hue = ( ( ord( \mb_strtolower( $this->member->name ) ) - 97 ) / 25.0 ) + 0.25;
$hue *= 1.61803398875;
$hue *= (float) ( '1.' . rand() ) / 1;
@@ -225,7 +225,7 @@ class _LetterPhoto
}
}
return array_map( function( $value ) { return $value * 256.0; }, $rgb );
return array_map( function( $value ) { return round( $value * 256.0 ); }, $rgb );
}
/**
+919 -358
View File
File diff suppressed because it is too large. Load diff
+123 -15
View File
@@ -20,12 +20,17 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Profile Step Model
*/
class _ProfileStep extends \IPS\Patterns\ActiveRecord
class _ProfileStep extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Multiton Map
*/
protected static $multitonMap = array();
/**
* @brief [ActiveRecord] Database Table
@@ -41,6 +46,26 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'step_';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'profile_completion';
/**
* @brief [Node] Sortable
*/
public static $nodeSortable = TRUE;
/**
* @brief [Node] Positon Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'profile_step_title_';
/**
* Load Record
@@ -57,14 +82,11 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
{
if ( $idField === NULL AND $extraWhereClause === NULL )
{
if ( !isset( \IPS\Data\Store::i()->profileSteps ) )
{
\IPS\Data\Store::i()->profileSteps = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profile_steps' )->setKeyField( 'step_id' ) );
}
$steps = static::getStore();
if ( isset( \IPS\Data\Store::i()->profileSteps[ $id ] ) )
if ( isset( $steps[ $id ] ) )
{
return static::constructFromData( \IPS\Data\Store::i()->profileSteps[ $id ] );
return static::constructFromData( $steps[ $id ] );
}
else
{
@@ -76,6 +98,63 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
return parent::load( $id, $idField, $extraWhereClause );
}
}
/**
* [Node] Return the custom badge for each row
*
* @return NULL|array Null for no badge, or an array of badge data (0 => CSS class type, 1 => language string, 2 => optional raw HTML to show instead of language string)
*/
protected function get__badge()
{
if( $this->required )
{
return array( 0 => 'positive ipsPos_right', 1 => 'required' );
}
return parent::get__badge();
}
/**
* Get data store
*
* @return array
* @note Note that all records are returned, even disabled promotion rules. Enable status needs to be checked in userland code when appropriate.
*/
public static function getStore()
{
if ( !isset( \IPS\Data\Store::i()->profileSteps ) )
{
\IPS\Data\Store::i()->profileSteps = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profile_steps', NULL, "step_position ASC" )->setKeyField( 'step_id' ) );
}
return \IPS\Data\Store::i()->profileSteps;
}
/**
* Fetch All Root Nodes
*
* @param string|NULL $permissionCheck The permission key to check for or NULl to not check permissions
* @param \IPS\Member|NULL $member The member to check permissions for or NULL for the currently logged in member
* @param mixed $where Additional WHERE clause
* @return array
*/
public static function roots( $permissionCheck='view', $member=NULL, $where=array() )
{
if ( !count( $where ) )
{
$return = array();
foreach( static::getStore() AS $node )
{
$return[ $node['step_id'] ] = static::constructFromData( $node );
}
return $return;
}
else
{
return parent::roots( $permissionCheck, $member, $where );
}
}
/**
* Save Changed Columns
@@ -176,6 +255,8 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
}
}
$steps = static::setOrder( $steps );
foreach( $steps as $key => $object )
{
if ( $nextOneIsIt )
@@ -200,13 +281,9 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
*/
public static function loadAll()
{
if ( !isset( \IPS\Data\Store::i()->profileSteps ) )
{
\IPS\Data\Store::i()->profileSteps = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profile_steps' )->setKeyField( 'step_id' ) );
}
$return = array();
foreach( \IPS\Data\Store::i()->profileSteps AS $id => $data )
foreach( static::getStore() AS $id => $data )
{
$return[ $id ] = static::constructFromData( $data );
}
@@ -449,6 +526,16 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
if ( !$this->id )
{
/* Set initial position to the end of the list and save initial data */
try
{
$this->position = \IPS\Db::i()->select( 'MAX(step_position)', 'core_profile_steps' )->first() + 1;
}
catch( \Exception $e )
{
$this->position = 1;
}
$this->save();
}
@@ -577,13 +664,13 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
* @param \IPS\Application $app The application being deleted
* @return void
*/
public function deleteByApplication( \IPS\Application $app )
public static function deleteByApplication( \IPS\Application $app )
{
$iterator = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_profile_steps' ), '\IPS\Member\ProfileStep' );
foreach( $iterator as $step )
{
list( $application, $extension ) = explode( '_', $this->_data['extension'] );
list( $application, $extension ) = explode( '_', $step->_data['extension'] );
if ( $application == $app->directory )
{
@@ -591,4 +678,25 @@ class _ProfileStep extends \IPS\Patterns\ActiveRecord
}
}
}
/**
* Given an array of wizard steps, reorder them based on AdminCP order
*
* @param array $steps Wizard steps
* @return array
*/
public static function setOrder( $steps )
{
$finalSteps = array();
foreach( array_keys( static::loadAll() ) as $id )
{
if( isset( $steps['profile_step_title_' . $id ] ) )
{
$finalSteps['profile_step_title_' . $id ] = $steps['profile_step_title_' . $id ];
}
}
return $finalSteps;
}
}