Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
+865
-89
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -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
@@ -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();
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user