Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

File diff suppressed because it is too large. Load diff
+5 -28
View File
@@ -12,7 +12,7 @@
namespace IPS\Member\Club;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -129,7 +129,7 @@ class _CustomField extends \IPS\CustomField
foreach ( \IPS\Db::i()->select( '*', 'core_clubs_fields', NULL, 'f_position' ) as $row )
{
$fields[ $row['f_id'] ] = $row;
if ( $row['f_filterable'] and in_array( $row['f_type'], array( 'Checkbox', 'CheckboxSet', 'Radio', 'Select', 'YesNo' ) ) )
if ( $row['f_filterable'] and \in_array( $row['f_type'], array( 'Checkbox', 'CheckboxSet', 'Radio', 'Select', 'YesNo' ) ) )
{
$filterable = TRUE;
}
@@ -175,34 +175,11 @@ class _CustomField extends \IPS\CustomField
unset( $form->elements['']['pf_search_type_on_off'] );
unset( $form->elements['']['pf_format'] );
}
/**
* [ActiveRecord] Save Record
*
* @return void
* @brief [ActiveRecord] Caches
* @note Defined cache keys will be cleared automatically as needed
*/
public function save()
{
$return = parent::save();
unset( \IPS\Data\Store::i()->clubFields );
return $return;
}
/**
* [ActiveRecord] Delete Record
*
* @return void
*/
public function delete()
{
$return = parent::delete();
unset( \IPS\Data\Store::i()->clubFields );
return $return;
}
protected $caches = array( 'clubFields' );
/**
* [Node] Format form values from add/edit form for save
+339
View File
@@ -0,0 +1,339 @@
<?php
/**
* @brief Club Page Model
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 13 Feb 2017
*/
namespace IPS\Member\Club;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Club Page Model
*/
class _Page extends \IPS\Patterns\ActiveRecord
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'core_club_pages';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'page_';
/**
* @brief Club Store
*/
protected static $clubs = array();
/**
* Get Club
*
* @return \IPS\Member\Club
*/
public function get_club(): \IPS\Member\Club
{
if ( !isset( static::$clubs[ $this->_data['club'] ] ) )
{
static::$clubs[ $this->_data['club'] ] = \IPS\Member\Club::load( $this->_data['club'] );
}
return static::$clubs[ $this->_data['club'] ];
}
/**
* Set Club
*
* @param \IPS\Member\Club $club The club
* @return void
*/
public function set_club( \IPS\Member\Club $club ): void
{
$this->_data['club'] = $club->id;
unset( static::$clubs[ $club->id ] );
}
/**
* Get Title
*
* @return string
*/
public function get_title(): string
{
if ( !$this->_data['seo_title'] )
{
$this->seo_title = \IPS\Http\Url\Friendly::seoTitle( $this->_data['title'] );
$this->save();
}
return $this->_data['title'];
}
/**
* Set Title
*
* @param string $title The page title
* @return void
*/
public function set_title( string $title ): void
{
$this->_data['title'] = $title;
$this->_data['seo_title'] = \IPS\Http\Url\Friendly::seoTitle( $title );
}
/**
* Set who can view this page
*
* @param array|NULL $value The value to set
* @return void
*/
public function set_can_view( ?array $value ): void
{
if ( \is_array( $value ) )
{
$this->_data['can_view'] = implode( ',', $value );
}
else
{
$this->_data['can_view'] = NULL;
}
}
/**
* Get who can view this page
*
* @return array|NULL
*/
public function get_can_view(): ?array
{
return $this->_data['can_view'] ? explode( ',', $this->_data['can_view'] ) : NULL;
}
/**
* Form
*
* @param \IPS\Helpers\Form $form Form Object
* @param \IPS\Member\Club $club Club this page belongs too.
* @param \IPS\Member\Club\Page|NULL $current If we are editing, the current page.
* @return void
*/
public static function form( \IPS\Helpers\Form $form, \IPS\Member\Club $club, ?\IPS\Member\Club\Page $current = NULL ): void
{
$form->hiddenValues['page_club'] = $club->id;
$form->add( new \IPS\Helpers\Form\Text( 'club_page_title', ( $current ) ? $current->title : NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Editor( 'club_page_content', ( $current ) ? $current->content : NULL, TRUE, array(
'app' => 'core',
'key' => 'ClubPage',
'autoSaveKey' => ( $current ) ? "club-page-{$current->id}" : "club-page-new",
'attachIds' => ( $current ) ? array( $current->id, NULL, NULL ) : NULL
) ) );
if ( $club->type !== \IPS\Member\Club::TYPE_PUBLIC )
{
$defaults = array( 'member', 'moderator' );
if ( $club->type !== \IPS\Member\Club::TYPE_PRIVATE )
{
$defaults[] = 'nonmember';
}
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'page_can_view', ( $current AND $current->can_view ) ? $current->can_view : $defaults, FALSE, array( 'options' => array(
'nonmember' => 'club_page_nonmembers',
'member' => 'club_page_members',
'moderator' => 'club_page_moderators'
) ) ) );
}
}
/**
* Format Form Values
*
* @param $values array Values
* @return void
*/
public function formatFormValues( array $values ): void
{
$this->club = \IPS\Member\Club::load( $values['page_club'] );
$this->title = $values['club_page_title'];
$this->content = $values['club_page_content'];
if ( array_key_exists( 'page_can_view', $values ) )
{
$this->can_view = $values['page_can_view'];
}
else
{
$this->can_view = NULL;
}
}
/**
* URL
*
* @param NULL|string $action Value for the "do" parameter, or NULL for no action.
* @return \IPS\Http\Url\Friendly
*/
public function url( ?string $action = NULL ): \IPS\Http\Url\Internal
{
$return = \IPS\Http\Url::internal( "app=core&module=clubs&controller=page&id={$this->id}", 'front', 'clubs_page', array( $this->seo_title ) );
if ( $action )
{
$return = $return->setQueryString( 'do', $action );
}
return $return;
}
/**
* Load and check permissions
*
* @param int $id ID of the page to load
* @param \IPS\Member|NULL $member Optional member to check against
* @return \IPS\Member\Club\Page
* @throws \OutOfRangeException
*/
public static function loadAndCheckPerms( int $id, ?\IPS\Member $member = NULL ): \IPS\Member\Club\Page
{
$page = static::load( $id );
if ( !$page->canView( $member ) )
{
throw new \OutOfRangeException;
}
return $page;
}
/**
* Can view this page
*
* @param \IPS\Member|NULL $member The member trying to view the page.
* @return bool
*/
public function canView( ?\IPS\Member $member = NULL ): bool
{
$member = $member ?: \IPS\Member::loggedIn();
/* If NULL, everyone can view */
if ( $this->can_view === NULL )
{
return TRUE;
}
/* Site moderators can see everything */
if ( $member->modPermission('can_access_all_clubs') )
{
return TRUE;
}
/* 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->club->approved )
{
return ( $member->modPermission('can_access_all_clubs') or ( $this->club->owner AND $member->member_id == $this->club->owner->member_id ) );
}
/* Owner or leader? */
if ( $member->member_id === $this->club->owner->member_id OR $this->club->memberStatus( $member ) === \IPS\Member\Club::STATUS_LEADER )
{
return TRUE;
}
/* Moderators? */
if ( \in_array( 'moderator', $this->can_view ) AND $this->club->memberStatus( $member ) === \IPS\Member\Club::STATUS_MODERATOR )
{
return TRUE;
}
/* Members */
if ( \in_array( 'member', $this->can_view ) AND \in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
return TRUE;
}
if ( \in_array( 'nonmember', $this->can_view ) AND $this->club->memberStatus( $member ) === NULL )
{
return TRUE;
}
/* Still here? Nothing worked */
return FALSE;
}
/**
* Can Add a page
*
* @param \IPS\Member\Club $club The club the page will be added too.
* @param \IPS\Member|NULL $member The member adding the page.
* @return bool
*/
public static function canAdd( \IPS\Member\Club $club, ?\IPS\Member $member = NULL ): bool
{
$member = $member ?: \IPS\Member::loggedIn();
return $club->owner->member_id === $member->member_id OR $club->isLeader( $member );
}
/**
* Can edit this page
*
* @param \IPS\Member|NULL $member The member editing the page.
* @return bool
* @note Functionally, this is no different from canAdd, however it's been abstracted out for third parties.
*/
public function canEdit( ?\IPS\Member $member = NULL ): bool
{
return static::canAdd( $this->club, $member );
}
/**
* Can delete this page
*
* @param \IPS\Member|NULL
* @return bool
* @note Functionally, this is no different from canAdd, however it's been abstracted out for third parties.
*/
public function canDelete( ?\IPS\Member $member = NULL ): bool
{
return static::canAdd( $this->club, $member );
}
/**
* Delete
*
* @param bool $updateClub Update club tabs
* @return void
*/
public function delete( $updateClub=TRUE )
{
\IPS\File::unclaimAttachments( 'core_ClubPage', $this->id );
if( $updateClub === TRUE )
{
$tabs = @json_decode( $this->club->menu_tabs, TRUE );
if ( \count( $tabs ) )
{
if ( isset( $tabs['page-' . $this->id] ) )
{
unset( $tabs['page-' . $this->id] );
$this->club->menu_tabs = json_encode( $tabs );
$this->club->save();
}
}
}
parent::delete();
}
}
+54
View File
@@ -0,0 +1,54 @@
<?php
/**
* @brief Poll model for clubs
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 1 Oct 2018
*/
namespace IPS\Member\Club;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Poll Model
*/
class _Poll extends \IPS\Poll
{
/**
* @brief Club this poll exists within
*/
public $club = NULL;
/**
* Member can vote?
*
* @param \IPS\Member|NULL $member Member or NULL for currently logged in member
* @return void
*/
public function canVote( \IPS\Member $member = NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
if( !parent::canVote( $member ) )
{
return FALSE;
}
/* This poll exists in a club, so make sure we have access to the club in order to vote */
if( $this->club )
{
/* The canPost() method simply checks our club membership status (not actual posting privileges) and is appropriate here */
return $this->club->canPost();
}
return TRUE;
}
}
View File
Whitespace-only changes.
+13 -7
View File
@@ -11,7 +11,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -22,6 +22,9 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _Device extends \IPS\Patterns\ActiveRecord
{
/**
* @brief Login keys are valid for 3 months
*/
const LOGIN_KEY_VALIDITY = 'P3M';
/**
@@ -48,7 +51,7 @@ class _Device extends \IPS\Patterns\ActiveRecord
* Load device for current request, or create one if there isn't one
*
* @param \IPS\Member $member The member being authenticated
* @param bool $sendNewDeviceEmail If true, and the associated setting is enabled, and this is a new device, an email will be sent to the member. Only set to FALSE if the user is registering where the email would be redundant.
* @param bool $sendNewDeviceEmail If true, and the associated setting is enabled, and this is a new device, an email will be sent to the member. Only set to FALSE if the user is registering and while the MFA where the email would be redundant.
* @return \IPS\Member\Device
*/
public static function loadOrCreate( \IPS\Member $member, $sendNewDeviceEmail=TRUE )
@@ -182,16 +185,19 @@ class _Device extends \IPS\Patterns\ActiveRecord
if ( $rememberMe === NULL )
{
\IPS\Request::i()->setCookie( 'member_id', $this->member_id, $cookieExpiration );
\IPS\Request::i()->setCookie( 'loggedIn', 1, $cookieExpiration, FALSE );
}
elseif ( $rememberMe === TRUE )
{
\IPS\Request::i()->setCookie( 'member_id', $this->member_id, $cookieExpiration );
\IPS\Request::i()->setCookie( 'login_key', $this->login_key, $cookieExpiration );
\IPS\Request::i()->setCookie( 'loggedIn', 1, $cookieExpiration, FALSE );
}
else
{
\IPS\Request::i()->setCookie( 'member_id', $this->member_id, NULL ); // Just tells the guest caching mechanism that we are logged in, so it can expire on the session end
\IPS\Request::i()->setCookie( 'login_key', NULL ); // Clear it in case they previously had chosen "Remember Me"
\IPS\Request::i()->setCookie( 'loggedIn', 1, $cookieExpiration, FALSE );
}
}
}
@@ -215,11 +221,11 @@ class _Device extends \IPS\Patterns\ActiveRecord
/**
* Get user agent data
*
* @return \IPS\Http\UserAgent
* @return \IPS\Http\Useragent
*/
public function userAgent()
{
return \IPS\Http\UserAgent::parse( $this->user_agent );
return \IPS\Http\Useragent::parse( $this->user_agent );
}
/**
@@ -229,7 +235,7 @@ class _Device extends \IPS\Patterns\ActiveRecord
*/
public function loginMethod()
{
if ( is_numeric( $this->login_handler ) )
if ( \is_numeric( $this->login_handler ) )
{
try
{
@@ -251,7 +257,7 @@ class _Device extends \IPS\Patterns\ActiveRecord
protected function sendNewDeviceEmail()
{
$member = \IPS\Member::load( $this->member_id );
if ( \IPS\Settings::i()->new_device_email )
{
try
@@ -266,7 +272,7 @@ 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 );
$member->logHistory( 'core', 'login', array( 'type' => 'new_device', 'device' => $this->device_key, 'user_agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : NULL ), FALSE );
}
/**
+51 -42
View File
@@ -11,7 +11,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -87,41 +87,34 @@ class _Group extends \IPS\Patterns\ActiveRecord
);
/**
* Load Record
*
* @see \IPS\Db::build
* @param int|string $id ID
* @param string $idField The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details)
* @return static
* @throws \InvalidArgumentException
* @throws \OutOfRangeException
* @brief [ActiveRecord] Attempt to load from cache
* @note If this is set to TRUE you MUST define a getStore() method to return the objects from cache
*/
public static function load( $id, $idField=NULL, $extraWhereClause=NULL )
protected static $loadFromCache = TRUE;
/**
* Group datastore
*
* @return array
* @deprecated
*/
protected static function groupStore()
{
if ( ( $idField === NULL or $idField === 'g_id' ) and $extraWhereClause === NULL )
{
$groups = static::groupStore();
if ( isset( $groups[ $id ] ) )
{
return parent::constructFromData( $groups[ $id ] );
}
}
return parent::load( $id, $idField, $extraWhereClause );
return static::getStore();
}
/**
* Group datastore
*
* @return array
*/
protected static function groupStore()
public static function getStore()
{
if ( !isset( \IPS\Data\Store::i()->groups ) )
{
\IPS\Data\Store::i()->groups = iterator_to_array( \IPS\Db::i()->select( 'core_groups.*', 'core_groups', NULL, 'core_sys_lang_words.word_custom' )->join( 'core_sys_lang_words', array( "lang_id=? AND word_app=? AND word_key=CONCAT( 'core_group_', core_groups.g_id )", \IPS\Member::loggedIn()->language()->id, 'core' ) )->setKeyField( 'g_id' ) );
\IPS\Data\Store::i()->groups = iterator_to_array( \IPS\Db::i()->select( '*', 'core_groups' )->setKeyField( 'g_id' ) );
}
return \IPS\Data\Store::i()->groups;
}
@@ -135,14 +128,14 @@ class _Group extends \IPS\Patterns\ActiveRecord
*
* @param bool $showAdminGroups Show admin groups. Used to restrict admin groups from being available when you cannot add/edit members in them.
* @param bool $showGuestGroups Show guest groups. Used to remove the guest group from the available groups returned.
* @param bool $hideGroups If the group is set not to not be available to filter by, should we hide them?
* @param bool $hideForFiltering If the group is set not to not be available to filter by, should we hide them?
* @return array
*/
public static function groups( $showAdminGroups=TRUE, $showGuestGroups=TRUE, $hideForFiltering=FALSE )
{
if ( !static::$allGroups )
{
static::$allGroups = iterator_to_array( new \IPS\Patterns\ActiveRecordIterator( new \ArrayIterator( static::groupStore() ), 'IPS\Member\Group' ) );
static::$allGroups = iterator_to_array( new \IPS\Patterns\ActiveRecordIterator( new \ArrayIterator( static::getStore() ), 'IPS\Member\Group' ) );
}
$groups = static::$allGroups;
@@ -174,6 +167,30 @@ class _Group extends \IPS\Patterns\ActiveRecord
}
}
/* If we have a dispatcher instance, sort the groups alphabetically */
if( \IPS\Dispatcher::hasInstance() )
{
/* Get all of the group names in one query */
$sortedGroupIds = array();
foreach( \IPS\Db::i()->select( '*', 'core_sys_lang_words', array( 'word_key LIKE ? AND lang_id=?', 'core_group_%', \IPS\Member::loggedIn()->language()->id ), 'word_custom ASC' ) as $lang )
{
$sortedGroupIds[] = \str_replace( 'core_group_', '', $lang['word_key'] );
}
$finalGroups = array();
foreach( $sortedGroupIds as $groupId )
{
if( isset( $groups[ $groupId ] ) )
{
$finalGroups[ $groupId ] = $groups[ $groupId ];
}
}
$groups = $finalGroups;
}
return $groups;
}
@@ -201,7 +218,7 @@ class _Group extends \IPS\Patterns\ActiveRecord
foreach( $perms as $key )
{
$groups = explode( ",", $index[$key] );
if( in_array( $oldId, $groups ) and !in_array( $this->g_id, $groups ) )
if( \in_array( $oldId, $groups ) and !\in_array( $this->g_id, $groups ) )
{
$groups[] = $this->g_id;
}
@@ -295,6 +312,7 @@ class _Group extends \IPS\Patterns\ActiveRecord
/**
* Format Name
*
* @param string $name The name to format
* @return string
*/
public function formatName( $name )
@@ -312,18 +330,13 @@ class _Group extends \IPS\Patterns\ActiveRecord
{
return $module->can( 'view', $this );
}
/**
* [ActiveRecord] Save Changed Columns
*
* @return void
* @brief [ActiveRecord] Caches
* @note Defined cache keys will be cleared automatically as needed
*/
function save()
{
parent::save();
unset( \IPS\Data\Store::i()->groups );
}
protected $caches = array( 'groups', 'moderators', 'administrators' );
/**
* [ActiveRecord] Delete Record
*
@@ -331,7 +344,7 @@ class _Group extends \IPS\Patterns\ActiveRecord
*/
public function delete()
{
if ( in_array( $this->g_id, array( \IPS\Settings::i()->guest_group, \IPS\Settings::i()->member_group, \IPS\Settings::i()->admin_group ) ) )
if ( \in_array( $this->g_id, array( \IPS\Settings::i()->guest_group, \IPS\Settings::i()->member_group, \IPS\Settings::i()->admin_group ) ) )
{
throw new \InvalidArgumentException;
}
@@ -366,10 +379,6 @@ class _Group extends \IPS\Patterns\ActiveRecord
parent::delete();
\IPS\Lang::deleteCustom( 'core', 'core_group_' . $this->g_id );
unset( \IPS\Data\Store::i()->groups );
unset( \IPS\Data\Store::i()->moderators );
unset( \IPS\Data\Store::i()->administrators );
/* Update Core Leaders */
\IPS\core\StaffDirectory\User::updateEmptySetting();
+15 -67
View File
@@ -11,7 +11,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -75,7 +75,7 @@ class _GroupPromotion extends \IPS\Node\Model
/**
* Form
*
* @param \IPS\Helpers\Form The form
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
@@ -197,7 +197,7 @@ class _GroupPromotion extends \IPS\Node\Model
/* Now we have to remove any fields that aren't valid... */
foreach( $values as $k => $v )
{
if( !in_array( $k, array( 'promote_enabled', 'promote_filters', 'promote_actions', 'promote_position' ) ) )
if( !\in_array( $k, array( 'promote_enabled', 'promote_filters', 'promote_actions', 'promote_position' ) ) )
{
unset( $values[ $k ] );
}
@@ -232,11 +232,12 @@ class _GroupPromotion extends \IPS\Node\Model
* @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
* @param array|NULL $limit Limit/offset to use, or NULL for no limit (default)
* @return array
*/
public static function roots( $permissionCheck='view', $member=NULL, $where=array() )
public static function roots( $permissionCheck='view', $member=NULL, $where=array(), $limit=NULL )
{
if ( !count( $where ) )
if ( !\count( $where ) )
{
$return = array();
foreach( static::getStore() AS $node )
@@ -248,22 +249,10 @@ class _GroupPromotion extends \IPS\Node\Model
}
else
{
return parent::roots( $permissionCheck, $member, $where );
return parent::roots( $permissionCheck, $member, $where, $limit );
}
}
/**
* Set Enabled
*
* @return void
*/
public function set__enabled( $enabled )
{
parent::set__enabled( $enabled );
unset( \IPS\Data\Store::i()->group_promotions );
}
/**
* Get data store
*
@@ -281,57 +270,16 @@ class _GroupPromotion extends \IPS\Node\Model
}
/**
* Load Record
*
* @see \IPS\Db::build
* @param int|string $id ID
* @param string $idField The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details)
* @return static
* @throws \InvalidArgumentException
* @throws \OutOfRangeException
* @brief [ActiveRecord] Caches
* @note Defined cache keys will be cleared automatically as needed
*/
public static function load( $id, $idField=NULL, $extraWhereClause=NULL )
{
if ( ( $idField === NULL or $idField === 'promote_id' ) and $extraWhereClause === NULL )
{
$promotions = static::getStore();
if ( isset( $promotions[ $id ] ) )
{
return static::constructFromData( $promotions[ $id ] );
}
else
{
throw new \OutOfRangeException;
}
}
return parent::load( $id, $idField, $extraWhereClause );
}
protected $caches = array( 'group_promotions' );
/**
* [ActiveRecord] Delete
*
* @return void
* @brief [ActiveRecord] Attempt to load from cache
* @note If this is set to TRUE you MUST define a getStore() method to return the objects from cache
*/
public function delete()
{
parent::delete();
unset( \IPS\Data\Store::i()->group_promotions );
}
/**
* [ActiveRecord] Save Changed Columns
*
* @return void
*/
public function save()
{
parent::save();
unset( \IPS\Data\Store::i()->group_promotions );
}
protected static $loadFromCache = TRUE;
/**
* @brief Cache extensions so we only need to load them once
@@ -394,7 +342,7 @@ class _GroupPromotion extends \IPS\Node\Model
$showWarning = TRUE;
}
}
if ( count( $action['secondary_group'] ) )
if ( \count( $action['secondary_group'] ) )
{
foreach ( $action['secondary_group'] as $key => $group )
{
+41 -8
View File
@@ -12,7 +12,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -34,7 +34,9 @@ class _History extends \IPS\Helpers\Table\Db
* @param \IPS\Http\Url $url The URL the table will be displayed on
* @param mixed $where WHERE clause
* @param bool $showIp If the IP address column should be included
* @param bool $showMember If the customer column should show
* @param bool $showMember If the customer column should show
* @param bool $showApp If the app column should show
* @param bool $showType If the type column should show
* @return void
*/
public function __construct( \IPS\Http\Url $url, $where, $showIp=TRUE, $showMember=FALSE, $showApp=TRUE, $showType=FALSE )
@@ -81,6 +83,15 @@ class _History extends \IPS\Helpers\Table\Db
{
foreach( $extension->getTypes() as $type )
{
if ( $type === 'oauth' and \IPS\Db::i()->select( 'COUNT(*)', 'core_oauth_clients', array( \IPS\Db::i()->findInSet( 'oauth_grant_types', array( 'authorization_code', 'implicit', 'password' ) ) ) )->first() === 1 )
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_oauth_clients', array( \IPS\Db::i()->findInSet( 'oauth_grant_types', array( 'authorization_code', 'implicit', 'password' ) ) ) ), 'IPS\Api\OAuthClient' ) as $client )
{
$options[ $type ] = $client->_title;
continue 2;
}
}
$options[ $type ] = 'log_type_title_' . $type;
}
}
@@ -98,9 +109,16 @@ class _History extends \IPS\Helpers\Table\Db
$this->parsers = array(
'log_type' => function( $val, $row ) use ( $extensions )
{
if( method_exists( $extensions[ $row['log_app'] ], 'parseLogType' ) )
try
{
return $extensions[ $row['log_app'] ]->parseLogType( $val, $row );
if( method_exists( $extensions[ $row['log_app'] ], 'parseLogType' ) )
{
return $extensions[ $row['log_app'] ]->parseLogType( $val, $row );
}
}
catch( \Throwable $e )
{
\IPS\Log::log( $e, 'member_history' );
}
return $val;
@@ -115,9 +133,16 @@ class _History extends \IPS\Helpers\Table\Db
},
'log_member'=> function( $val, $row ) use ( $extensions )
{
if( method_exists( $extensions[ $row['log_app'] ], 'parseLogMember' ) )
try
{
return $extensions[ $row['log_app'] ]->parseLogMember( $val, $row );
if( method_exists( $extensions[ $row['log_app'] ], 'parseLogMember' ) )
{
return $extensions[ $row['log_app'] ]->parseLogMember( $val, $row );
}
}
catch( \Throwable $e )
{
\IPS\Log::log( $e, 'member_history' );
}
$member = \IPS\Member::load( $val );
@@ -125,9 +150,17 @@ class _History extends \IPS\Helpers\Table\Db
},
'log_data' => function( $val, $row ) use ( $extensions )
{
if( method_exists( $extensions[ $row['log_app'] ], 'parseLogData' ) )
try
{
return $extensions[ $row['log_app'] ]->parseLogData( $val, $row );
if( method_exists( $extensions[ $row['log_app'] ], 'parseLogData' ) )
{
return $extensions[ $row['log_app'] ]->parseLogData( $val, $row );
}
}
catch( \Throwable $e )
{
\IPS\Log::log( $e, 'member_history' );
return $val; # Return the value so the admin may have some clue as to what the log entry was for
}
return '';
+16 -158
View File
@@ -11,7 +11,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -23,98 +23,19 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
class _LetterPhoto
{
/**
* @brief File storage class to use
* @brief Member name
*/
protected $fileStorageClass = 'core_Profile';
/**
* @brief Member object
*/
protected $member = NULL;
/**
* @brief Text size
*/
protected $textSize = 75;
protected $memberName = NULL;
/**
* Create a new photo object
*
* @param \IPS\Member $member Member object
* @param string $name Member name
* @return void
*/
public function __construct( $member )
public function __construct( $name )
{
$this->member = $member;
}
/**
* Create the photo
*
* @param int $maxWidth Max width
* @param int $maxHeight Max height
* @param int $letterCount How many letters to use
* @return \IPS\Http\Url|NULL
*/
public function create( $maxWidth, $maxHeight, $letterCount=1 )
{
/* If we don't have any sizes, we can't generate a proper image */
if( !$maxWidth OR !$maxHeight )
{
return NULL;
}
/* Set the font size to 1/2 of the $maxWidth and $maxHeight (which should be the same value) */
$this->textSize = ( ( $maxWidth / 2 ) / $letterCount );
/* If we don't have a name, there's nothing to create */
if( !$this->member->name )
{
return NULL;
}
/* 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 === NULL )
{
return NULL;
}
/* Now we have to generate the background color we will be using */
$rgbColor = $this->generateColorCode();
/* Create the image */
$image = \IPS\Image::newImageCanvas( $maxWidth, $maxHeight, $rgbColor );
/* Draw the text on the image */
$image->write( $letters, $this->getFont( $letters ), $this->textSize );
/* Save the image and return it */
try
{
return \IPS\File::create( $this->fileStorageClass, $letters . '_member_' . $this->member->member_id . '.png', (string) $image, NULL, TRUE, NULL, FALSE );
}
catch( \Exception $e )
{
\IPS\Log::debug( $e, 'letter_photo' );
return NULL;
}
}
/**
* Return the first X non-punctuation characters of the name
*
* @param int $letters Number of letters to return
* @return string|NULL
*/
protected function getLetters( $letters=1 )
{
$name = str_replace( array( '<', '>', '=', '-', '+', '"', "'" ), '', $this->member->name );
$name = preg_replace( "/(\pP)+/u", '', trim( $name ) );
return $name ? mb_strtoupper( mb_substr( $name, 0, $letters ) ) : NULL;
$this->memberName = $name;
}
/**
@@ -133,9 +54,9 @@ class _LetterPhoto
protected static $lastHue = NULL;
/**
* Return a unique color code based on the name.
* Return a unique hex color code based on the name.
*
* @return array (RGB value)
* @return string
*/
public function generateColorCode()
{
@@ -151,16 +72,16 @@ class _LetterPhoto
static::$lastHue = $hue;
return $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue );
return $this->convertRgbToHex( $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue ) );
}
$hue = ( ( ord( \mb_strtolower( $this->member->name ) ) - 97 ) / 25.0 ) + 0.25;
$hue = ( ( \ord( \mb_strtolower( $this->memberName ) ) - 97 ) / 25.0 ) + 0.25;
$hue *= 1.61803398875;
$hue *= (float) ( '1.' . rand() ) / 1;
if( rand( 0, 1 ) )
{
$float = (float) ( "1." . ord( array_rand( range( 'a', 'z' ) ) ) );
$float = (float) ( "1." . \ord( array_rand( range( 'a', 'z' ) ) ) );
$hue = abs( $float - $hue );
}
@@ -171,7 +92,7 @@ class _LetterPhoto
static::$lastHue = $hue;
return $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue );
return $this->convertRgbToHex( $this->convertHsvToRgb( $hue, $this->colorCodeSaturation, $this->colorCodeValue ) );
}
/**
@@ -229,76 +150,13 @@ class _LetterPhoto
}
/**
* Return a font file path to use
* Convert an RGB color value to hex
*
* @param string $string String we are going to write
* @param array $rgb RGB color values
* @return string
*/
protected function getFont( $string='' )
protected function convertRgbToHex( array $rgb )
{
$codePointMap = array(
'NotoSansArmenian-Regular.ttf' => array( 0x0530, 0x058F ),
'NotoSansHebrew-Regular.ttf' => array( 0x0590, 0x05FF ),
'NotoNaskhArabic-Regular.ttf' => array( 0x0600, 0x06FF ),
'NotoSansGeorgian-Regular.ttf' => array( 0x10A0, 0x10FF ),
'NotoSansThai-Regular.ttf' => array( 0x0E00, 0x0E7F ),
'NotoSansDevanagari-Regular.ttf' => array( 0x0900, 0x097F ),
'BMDOHYEON.ttf' => array(
array( 0xAC00, 0xD7A3 ),
array( 0x1100, 0x11FF ),
array( 0x3130, 0x318F ),
array( 0xA960, 0xA97F ),
array( 0xD7B0, 0xD7FF )
),
'HanaMinA.ttf' => array(
array( 0x4E00, 0x9FFF ),
array( 0x3400, 0x4DB5 ),
array( 0x3040, 0x309F ),
array( 0x30A0, 0x30FF ),
array( 0xFF00, 0xFFEF ),
array( 0xF900, 0xFAD9 ),
array( 0x20000, 0x2A6D6 ),
array( 0x2A700, 0x2B734 ),
array( 0x2B740, 0x2B81D ),
array( 0x2B820, 0x2CEA1 ),
array( 0x2F800, 0x2FA1D )
),
);
/* Get all characters */
$characters = preg_split( '//u', $string, null, PREG_SPLIT_NO_EMPTY );
/* Loop over all characters. If any character is in a range defined above, use that font.
Technically you could have a Korean character and an Arabic character in the same string, but the probability of that occurring
is sufficiently rare that we will use the first font defined above which support latin ranges already */
foreach( $characters as $character )
{
$decValue = unpack( 'N', mb_convert_encoding( $character, 'UCS-4BE', 'UTF-8' ) );
$decValue = $decValue[1];
foreach( $codePointMap as $fontFile => $range )
{
if( is_array( $range[0] ) )
{
foreach( $range as $subRange )
{
if( $decValue > ( $subRange[0] ) AND $decValue < ( $subRange[1] ) )
{
return \IPS\ROOT_PATH . '/system/3rd_party/Fonts/' . $fontFile;
}
}
}
else
{
if( $decValue > ( $range[0] ) AND $decValue < ( $range[1] ) )
{
return \IPS\ROOT_PATH . '/system/3rd_party/Fonts/' . $fontFile;
}
}
}
}
/* Fallback for the majority of languages */
return \IPS\ROOT_PATH . '/system/3rd_party/Fonts/NotoSans-Regular.ttf';
return sprintf( "%02x%02x%02x", $rgb[0], $rgb[1], $rgb[2] );
}
}
+1075 -509
View File
File diff suppressed because it is too large. Load diff
+68 -71
View File
@@ -11,7 +11,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -66,38 +66,6 @@ class _ProfileStep extends \IPS\Node\Model
* @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
*
* @see \IPS\Db::build
* @param int|string $id ID
* @param string $idField The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details) - if used will cause multiton store to be skipped and a query always ran
* @return static
* @throws \InvalidArgumentException
* @throws \OutOfRangeException
*/
public static function load( $id, $idField=NULL, $extraWhereClause=NULL )
{
if ( $idField === NULL AND $extraWhereClause === NULL )
{
$steps = static::getStore();
if ( isset( $steps[ $id ] ) )
{
return static::constructFromData( $steps[ $id ] );
}
else
{
throw new \OutOfRangeException;
}
}
else
{
return parent::load( $id, $idField, $extraWhereClause );
}
}
/**
* [Node] Return the custom badge for each row
@@ -136,11 +104,12 @@ class _ProfileStep extends \IPS\Node\Model
* @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
* @param array|NULL $limit Limit/offset to use, or NULL for no limit (default)
* @return array
*/
public static function roots( $permissionCheck='view', $member=NULL, $where=array() )
public static function roots( $permissionCheck='view', $member=NULL, $where=array(), $limit=NULL )
{
if ( !count( $where ) )
if ( !\count( $where ) )
{
$return = array();
foreach( static::getStore() AS $node )
@@ -152,22 +121,22 @@ class _ProfileStep extends \IPS\Node\Model
}
else
{
return parent::roots( $permissionCheck, $member, $where );
return parent::roots( $permissionCheck, $member, $where, $limit );
}
}
/**
* Save Changed Columns
*
* @return void
* @brief [ActiveRecord] Caches
* @note Defined cache keys will be cleared automatically as needed
*/
public function save()
{
parent::save();
unset( \IPS\Data\Store::i()->profileSteps );
}
protected $caches = array( 'profileSteps' );
/**
* @brief [ActiveRecord] Attempt to load from cache
* @note If this is set to TRUE you MUST define a getStore() method to return the objects from cache
*/
protected static $loadFromCache = TRUE;
/**
* [ActiveRecord] Delete Record
*
@@ -184,8 +153,8 @@ class _ProfileStep extends \IPS\Node\Model
\IPS\Lang::deleteCustom( 'core', 'profile_step_text_' . $this->id );
parent::delete();
unset( \IPS\Data\Store::i()->profileSteps );
\IPS\Db::i()->delete( 'core_profile_completion', array( 'step_id=?', $this->id ) );
}
/**
@@ -196,7 +165,7 @@ class _ProfileStep extends \IPS\Node\Model
public function get_subcompletion_act()
{
$return = ! empty( $this->_data['subcompletion_act'] ) ? json_decode( $this->_data['subcompletion_act'], TRUE ) : array();
if ( ! is_array( $return ) and ! empty( $this->_data['subcompletion_act'] ) )
if ( ! \is_array( $return ) and ! empty( $this->_data['subcompletion_act'] ) )
{
$return = array( $this->_data['subcompletion_act'] );
}
@@ -207,12 +176,12 @@ class _ProfileStep extends \IPS\Node\Model
/**
* Set the "subcompletion_act" field
*
* @param string|array $value
* @return void
* @param string|array $value Value of field
* @return void
*/
public function set_subcompletion_act( $value )
{
$this->_data['subcompletion_act'] = ( is_array( $value ) ? json_encode( $value ) : $value );
$this->_data['subcompletion_act'] = ( \is_array( $value ) ? json_encode( $value ) : $value );
}
/**
@@ -226,7 +195,7 @@ class _ProfileStep extends \IPS\Node\Model
foreach( static::loadAll() as $id => $object )
{
if ( $object->id !== $this->id and count( $object->subcompletion_act ) )
if ( $object->id !== $this->id and \count( $object->subcompletion_act ) )
{
foreach( $object->subcompletion_act as $item )
{
@@ -241,7 +210,7 @@ class _ProfileStep extends \IPS\Node\Model
/**
* Return the next step
*
* @return int
* @return int|string
*/
public function getNextStep()
{
@@ -249,13 +218,13 @@ class _ProfileStep extends \IPS\Node\Model
$steps = array();
foreach( \IPS\Application::allExtensions( 'core', 'ProfileSteps' ) AS $extension )
{
if ( method_exists( $extension, 'wizard') AND count( $extension::wizard() ) )
if ( method_exists( $extension, 'wizard') AND \is_array( $extension::wizard() ) AND \count( $extension::wizard() ) )
{
$steps = array_merge( $steps, $extension::wizard() );
}
}
$steps = static::setOrder( $steps );
$steps = static::setOrder( $steps, FALSE );
foreach( $steps as $key => $object )
{
@@ -356,7 +325,7 @@ class _ProfileStep extends \IPS\Node\Model
* Can the actions have multiple choices?
*
* @param string $action Action key (basic_profile, etc)
* @return boolean
* @return boolean|null
*/
public static function actionMultipleChoice( $action )
{
@@ -432,7 +401,7 @@ class _ProfileStep extends \IPS\Node\Model
}
}
if ( count( $lang ) )
if ( \count( $lang ) )
{
$result = \IPS\Member::loggedIn()->language()->get( 'complete_profile_' . $this->completion_act ) . ' (' . \IPS\Member::loggedIn()->language()->formatList( $lang ) . ')';
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $result );
@@ -460,7 +429,7 @@ class _ProfileStep extends \IPS\Node\Model
/**
* Has a specific step been completed?
*
* @param \IPS\Member|NULL The member to check, or NULL for currently logged in
* @param \IPS\Member|NULL $member The member to check, or NULL for currently logged in
* @return bool
*/
public function completed( \IPS\Member $member = NULL )
@@ -470,17 +439,23 @@ class _ProfileStep extends \IPS\Node\Model
}
/**
* @brief Can add cache
* @brief Can add cache
*/
protected static $canAdd = NULL;
/**
* Can add new steps
*
* @return param
* @return bool|int
*/
public function canAdd()
{
/* We can't add children, so just return now */
if( $this->id )
{
return FALSE;
}
if ( static::$canAdd === NULL )
{
$actions = static::actions();
@@ -512,7 +487,7 @@ class _ProfileStep extends \IPS\Node\Model
/**
* Form
*
* @param \IPS\Helpers\Form Form
* @param \IPS\Helpers\Form $form Form
* @return void
*/
public function form( &$form )
@@ -544,8 +519,18 @@ class _ProfileStep extends \IPS\Node\Model
$disabled = $usedSubActions[ $key ];
}
$formClass = static::actionMultipleChoice( $key ) ? '\IPS\Helpers\Form\CheckboxSet' : '\IPS\Helpers\Form\Select';
$subActionFormElements[] = new $formClass( 'profile_step_subaction_' . $key, $this->subcompletion_act, TRUE, array( 'options' => $subActions[ $key ], 'disabled' => $disabled ), NULL, NULL, NULL, 'profile_step_subaction_' . $key );
$choiceType = static::actionMultipleChoice( $key );
if( $choiceType === NULL )
{
$subActionFormElements[] = new \IPS\Helpers\Form\Translatable( 'profile_step_subaction_' . $key, $this->subcompletion_act, TRUE, array( 'app' => 'core', 'editor' => array( 'app' => 'core', 'key' => 'ProfileSteps', 'autoSaveKey' => 'core-step-' . $key . ( $this->id ?: 0 ) ) ), NULL, NULL, NULL, 'profile_step_subaction_' . $key );
}
else
{
$formClass = $choiceType ? '\IPS\Helpers\Form\CheckboxSet' : '\IPS\Helpers\Form\Select';
$subActionFormElements[] = new $formClass( 'profile_step_subaction_' . $key, $this->subcompletion_act, TRUE, array( 'options' => $subActions[ $key ], 'disabled' => $disabled ), NULL, NULL, NULL, 'profile_step_subaction_' . $key );
}
$toggles[ $key ][] = 'profile_step_subaction_' . $key;
}
}
@@ -567,7 +552,7 @@ class _ProfileStep extends \IPS\Node\Model
/**
* Format Form Values
* @param array Values
* @param array $values Values
* @return array
*/
public function formatFormValues( $values )
@@ -631,7 +616,7 @@ class _ProfileStep extends \IPS\Node\Model
if ( array_key_exists( 'step_title', $return ) )
{
if ( is_array( $return['step_title'] ) )
if ( \is_array( $return['step_title'] ) )
{
foreach( $return['step_title'] AS $lang => $text )
{
@@ -666,7 +651,7 @@ class _ProfileStep extends \IPS\Node\Model
/**
* Find extension key from action key
*
* @param string The action key
* @param string $key The action key
* @return string The extension key
* @throws \OutOfBoundsException
*/
@@ -690,7 +675,7 @@ class _ProfileStep extends \IPS\Node\Model
* Resync
* Triggered when something happens externally that may affect these fields (such as a field being deleted, etc)
*
* return @void
* @return void
*/
public static function resync()
{
@@ -733,18 +718,30 @@ class _ProfileStep extends \IPS\Node\Model
* Given an array of wizard steps, reorder them based on AdminCP order
*
* @param array $steps Wizard steps
* @param bool $countExtra Include extra steps
* @return array
*/
public static function setOrder( $steps )
public static function setOrder( $steps, $countExtra = TRUE )
{
$finalSteps = array();
foreach( array_keys( static::loadAll() ) as $id )
$profileSteps = static::loadAll();
foreach( $profileSteps as $id => $profileStep )
{
if( isset( $steps['profile_step_title_' . $id ] ) )
{
$finalSteps['profile_step_title_' . $id ] = $steps['profile_step_title_' . $id ];
}
if ( $countExtra and method_exists( $profileStep->extension, 'extraStep') )
{
$extension = $profileStep->extension;
if( \count( $extension::extraStep() ) and isset( $steps[ $extension::extraStepTitle() ] ) )
{
$finalSteps[ $extension::extraStepTitle() ] = $steps[ $extension::extraStepTitle() ];
}
}
}
return $finalSteps;
+1 -1
View File
@@ -11,7 +11,7 @@
namespace IPS\Member;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;