Version 4.7.0

This commit is contained in:
Neo committed 2025-12-19 16:00:35 -08:00
1 parent 517a5e1f70
commit 8ba7d43898
1933 files changed
+65613 -11332

No files matched your search

@@ -68,6 +68,7 @@ class _Badge extends \IPS\Node\Model
'app' => 'core',
'module' => 'achievements',
'prefix' => 'badges_',
'all' => 'badges_manage',
);
/**
@@ -135,8 +136,11 @@ class _Badge extends \IPS\Node\Model
*/
public function form( &$form )
{
/* Allow SVGs without the obscure hash removing the file extension */
\IPS\File::$safeFileExtensions[] = 'svg';
$form->add( new \IPS\Helpers\Form\Translatable( 'badge_name', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? "core_badges_{$this->id}" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Upload( 'badge_image', $this->image ? \IPS\File::get( 'core_Badges', $this->image ) : NULL, TRUE, array( 'obscure' => FALSE, 'checkImage' => TRUE, 'allowedFileTypes' => array_merge( \IPS\Image::$imageExtensions, ['svg'] ), 'storageExtension' => 'core_Badges', 'allowStockPhotos' => FALSE ), function( $val ) {
$form->add( new \IPS\Helpers\Form\Upload( 'badge_image', $this->image ? \IPS\File::get( 'core_Badges', $this->image ) : NULL, TRUE, array( 'obscure' => TRUE, 'checkImage' => TRUE, 'allowedFileTypes' => array_merge( \IPS\Image::supportedExtensions(), ['svg'] ), 'storageExtension' => 'core_Badges', 'allowStockPhotos' => FALSE ), function( $val ) {
if( !$val )
{
throw new \DomainException('achievements_bad_image');
@@ -228,12 +232,47 @@ class _Badge extends \IPS\Node\Model
return FALSE;
}
$stats = $this->getBadgeStats();
return ( 100 / $stats['memberCount'] * $stats['badgeCount'][ $this->id ] ) < \IPS\Settings::i()->rare_badge_percent;
}
/**
* Return number of people who have this badge
*
* @param bool|null $roundUp Round number to nearest 100 to be less specific
* @return int
*/
public function ownedByCount( bool $roundUp=FALSE )
{
if ( $stats = $this->getBadgeStats() and isset( $stats['badgeCount'][ $this->id ] ) )
{
if ( $roundUp )
{
return ceil( $stats['badgeCount'][$this->id] / 100 ) * 100;
}
else
{
return $stats['badgeCount'][ $this->id ];
}
}
return NULL;
}
/**
* Get statistics for this badge
*
* @return array|null
*/
public function getBadgeStats(): ?array
{
/* Fetch the counts we need from the datastore. If they are old or non-existent, refresh and store in datastore for next time. */
$stats = NULL;
if( isset( \IPS\Data\Store::i()->badgeRarityStats ) )
if( isset( \IPS\Data\Store::i()->badgeStats ) )
{
$stats = json_decode( \IPS\Data\Store::i()->badgeRarityStats, true );
$stats = json_decode( \IPS\Data\Store::i()->badgeStats, true );
if( !isset( $stats['expiration'] ) OR time() > $stats['expiration'] OR !isset( $stats['badgeCount'][ $this->id ] ) )
{
@@ -243,21 +282,38 @@ class _Badge extends \IPS\Node\Model
if( $stats === NULL )
{
$exclude = json_decode( \IPS\Settings::i()->rules_exclude_groups, TRUE );
$where = [ [ 'completed=?', true ] ];
$subQuery = NULL;
if ( \is_array( $exclude ) and \count( $exclude ) )
{
$subQuery = \IPS\Db::i()->select( 'member_id', 'core_members', [ \IPS\Db::i()->in( 'member_group_id', $exclude ) ] );
$where[] = [ \IPS\Db::i()->in( 'member_group_id', $exclude, TRUE ) ];
}
$stats = array(
'expiration' => time() + 3600, // Cache for 60 minutes
'memberCount' => \IPS\Db::i()->select( 'COUNT(*)', 'core_members', [ 'completed=?', true ] )->first(),
'expiration' => time() + ( 3600 * 6 ), // Cache for 6 hours
'memberCount' => \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $where )->first(),
'badgeCount' => array(),
);
foreach( \IPS\Db::i()->select( 'id', 'core_badges' ) as $badgeId )
{
$stats['badgeCount'][ $badgeId ] = \IPS\Db::i()->select( 'COUNT(*)', 'core_member_badges', [ 'badge=?', $badgeId ] )->first();
$where = [ [ 'badge=?', $badgeId ] ];
if ( \is_array( $exclude ) and \count( $exclude ) )
{
$where[] = [ \IPS\Db::i()->in( 'core_member_badges.member', $subQuery, TRUE ) ];
}
$stats['badgeCount'][ $badgeId ] = \IPS\Db::i()->select( 'COUNT(*)', 'core_member_badges', $where )->first();
}
\IPS\Data\Store::i()->badgeRarityStats = json_encode( $stats );
\IPS\Data\Store::i()->badgeStats = json_encode( $stats );
}
return ( 100 / $stats['memberCount'] * $stats['badgeCount'][ $this->id ] ) < \IPS\Settings::i()->rare_badge_percent;
return $stats;
}
/**
@@ -444,4 +500,24 @@ class _Badge extends \IPS\Node\Model
}
}
}
/**
* Get output for API
*
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
* @return array
* @apiresponse int id ID number
* @apiresponse string name Name
* @apiresponse array statistcs Badge Statistics
*/
public function apiOutput( \IPS\Member $authorizedMember = NULL )
{
$return = array(
'id' => $this->id,
'name' => $this->_title,
'statistics' => $this->getBadgeStats(),
);
return $return;
}
}