Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -11,35 +11,63 @@
|
||||
namespace IPS\core\modules\admin\achievements;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\Application;
|
||||
use IPS\core\Achievements\Badge;
|
||||
use IPS\core\Achievements\Rule;
|
||||
use IPS\core\CustomBadge;
|
||||
use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\File;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Upload;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Controller;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Theme;
|
||||
use IPS\Xml\SimpleXML;
|
||||
use OutOfRangeException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function mb_substr;
|
||||
use const IPS\Helpers\Table\SEARCH_DATE_RANGE;
|
||||
use const IPS\TEMP_DIRECTORY;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement badges
|
||||
*/
|
||||
class _badges extends \IPS\Node\Controller
|
||||
class badges extends Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
public static bool $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Node Class
|
||||
*/
|
||||
protected $nodeClass = 'IPS\core\Achievements\Badge';
|
||||
protected string $nodeClass = 'IPS\core\Achievements\Badge';
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
public function execute() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'badges_manage' );
|
||||
Dispatcher::i()->checkAcpPermission( 'badges_manage' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
@@ -48,34 +76,35 @@ class _badges extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
protected function manage() : void
|
||||
{
|
||||
if( $data = \IPS\core\Achievements\Rule::getRebuildProgress() )
|
||||
if( $data = Rule::getRebuildProgress() )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'achievements' )->rebuildProgress( $data, TRUE );
|
||||
Output::i()->output .= Theme::i()->getTemplate( 'achievements' )->rebuildProgress( $data, TRUE );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sidebar['actions']['export'] = array(
|
||||
Output::i()->sidebar['actions']['export'] = array(
|
||||
'primary' => false,
|
||||
'icon' => 'cloud-download',
|
||||
'link' => \IPS\Http\Url::internal('app=core&module=achievements&controller=badges&do=exportForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_export') ),
|
||||
'link' => Url::internal('app=core&module=achievements&controller=badges&do=exportForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('acp_achievements_export') ),
|
||||
'title' => 'acp_achievements_export',
|
||||
);
|
||||
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'achievements', 'badges_manage' ) )
|
||||
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'achievements', 'badges_manage' ) )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['import'] = array(
|
||||
Output::i()->sidebar['actions']['import'] = array(
|
||||
'primary' => false,
|
||||
'icon' => 'cloud-upload',
|
||||
'link' => \IPS\Http\Url::internal('app=core&module=achievements&controller=badges&do=importForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_import') ),
|
||||
'link' => Url::internal('app=core&module=achievements&controller=badges&do=importForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('acp_achievements_import') ),
|
||||
'title' => 'acp_achievements_import',
|
||||
);
|
||||
}
|
||||
|
||||
Output::i()->output .= Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'cheev_badges_blurb' );
|
||||
|
||||
return parent::manage();
|
||||
parent::manage();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,13 +113,13 @@ class _badges extends \IPS\Node\Controller
|
||||
* @param object $node Node returned from $nodeClass::load()
|
||||
* @return NULL|string
|
||||
*/
|
||||
public function _getRowHtml( $node )
|
||||
public function _getRowHtml( object $node ): ?string
|
||||
{
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_member_badges', [ 'badge=?', $node->id ] )->first();
|
||||
$count = Db::i()->select( 'COUNT(*)', 'core_member_badges', [ 'badge=?', $node->id ] )->first();
|
||||
|
||||
$url = \IPS\Http\Url::internal("app=core&module=achievements&controller=badges&do=view&id={$node->id}");
|
||||
$url = Url::internal("app=core&module=achievements&controller=badges&do=view&id={$node->id}");
|
||||
|
||||
return \IPS\Theme::i()->getTemplate('achievements')->memberCount( $url, $count );
|
||||
return Theme::i()->getTemplate('achievements')->memberCount( $url, $count );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,11 +127,11 @@ class _badges extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function view()
|
||||
public function view() : void
|
||||
{
|
||||
$badge = \IPS\core\Achievements\Badge::load( \IPS\Request::i()->id );
|
||||
$badge = Badge::load( Request::i()->id );
|
||||
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_member_badges', \IPS\Http\Url::internal("app=core&module=achievements&controller=badges&do=view&id={$badge->id}"), [ 'badge=?', $badge->id ] );
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_member_badges', Url::internal("app=core&module=achievements&controller=badges&do=view&id={$badge->id}"), [ 'badge=?', $badge->id ] );
|
||||
$table->joins[] = [
|
||||
'select' => 'action,identifier',
|
||||
'from' => 'core_achievements_log',
|
||||
@@ -114,13 +143,13 @@ class _badges extends \IPS\Node\Controller
|
||||
$table->sortBy = $table->sortBy ?: 'datetime';
|
||||
|
||||
$table->advancedSearch = array(
|
||||
'datetime' => \IPS\Helpers\Table\SEARCH_DATE_RANGE,
|
||||
'datetime' => SEARCH_DATE_RANGE,
|
||||
);
|
||||
|
||||
$table->parsers = array(
|
||||
'member' => function ( $val, $row )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $val ) );
|
||||
return Theme::i()->getTemplate( 'global', 'core' )->userLink( Member::load( $val ) );
|
||||
},
|
||||
'action_log' => function( $val, $row ) {
|
||||
try
|
||||
@@ -128,17 +157,17 @@ class _badges extends \IPS\Node\Controller
|
||||
if ( $row['action'] )
|
||||
{
|
||||
$exploded = explode( '_', $row['action'] );
|
||||
$extension = \IPS\Application::load( $exploded[0] )->extensions( 'core', 'AchievementAction' )[ $exploded[1] ];
|
||||
$extension = Application::load( $exploded[0] )->extensions( 'core', 'AchievementAction' )[ $exploded[1] ];
|
||||
return $extension->logRow( $row['identifier'], explode( ',', $row['actor'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
catch( OutOfRangeException $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('unknown');
|
||||
return Member::loggedIn()->language()->addToStack('unknown');
|
||||
}
|
||||
},
|
||||
'rule' => function( $val, $row ) {
|
||||
@@ -147,28 +176,28 @@ class _badges extends \IPS\Node\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
$rule = \IPS\core\Achievements\Rule::load( $val );
|
||||
$rule = Rule::load( $val );
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
catch ( OutOfRangeException $e ) { }
|
||||
}
|
||||
|
||||
if ( $rule )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( \IPS\Http\Url::internal("app=core&module=achievements&controller=rules&do=form&id={$rule->id}"), FALSE, $rule->extension()->ruleDescription( $rule ), TRUE, FALSE, FALSE, TRUE );
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( Url::internal("app=core&module=achievements&controller=rules&do=form&id={$rule->id}"), FALSE, $rule->extension()->ruleDescription( $rule ), TRUE, FALSE, FALSE, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('unknown');
|
||||
return Member::loggedIn()->language()->addToStack('unknown');
|
||||
}
|
||||
},
|
||||
'datetime' => function( $val )
|
||||
{
|
||||
return \IPS\DateTime::ts( $val );
|
||||
return DateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
\IPS\Output::i()->title = $badge->_title;
|
||||
\IPS\Output::i()->output = $table;
|
||||
Output::i()->title = $badge->_title;
|
||||
Output::i()->output = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,53 +205,53 @@ class _badges extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function exportForm()
|
||||
public function exportForm() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'badges_manage' );
|
||||
$assignedBadges = \IPS\core\Achievements\Badge::getAssignedBadgeIds();
|
||||
Dispatcher::i()->checkAcpPermission( 'badges_manage' );
|
||||
$assignedBadges = Badge::getAssignedBadgeIds();
|
||||
|
||||
$where = NULL;
|
||||
if ( \count( $assignedBadges ) )
|
||||
if ( count( $assignedBadges ) )
|
||||
{
|
||||
$where = [ \IPS\Db::i()->in( '`id`', $assignedBadges, TRUE ) ];
|
||||
$where = [ Db::i()->in( '`id`', $assignedBadges, TRUE ) ];
|
||||
}
|
||||
|
||||
$exportableBadges = \IPS\Db::i()->select( 'COUNT(*)', 'core_badges', $where )->first();
|
||||
$exportableBadges = Db::i()->select( 'COUNT(*)', 'core_badges', $where )->first();
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'achievements' )->badgeExport( $exportableBadges );
|
||||
Output::i()->output = Theme::i()->getTemplate( 'achievements' )->badgeExport( $exportableBadges );
|
||||
}
|
||||
|
||||
/**
|
||||
* Export ranks with images as an XML file (XML is better at potentially large values from raw image data)
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function export()
|
||||
public function export() : void
|
||||
{
|
||||
$xml = \IPS\Xml\SimpleXML::create('badges');
|
||||
$xml = SimpleXML::create('badges');
|
||||
|
||||
$langs = [];
|
||||
foreach( \IPS\Db::i()->select('word_key, word_default', 'core_sys_lang_words', [ "lang_id=? AND word_key LIKE 'core_badges_%'", \IPS\Member::loggedIn()->language()->id ] ) as $row )
|
||||
foreach( Db::i()->select('word_key, word_default', 'core_sys_lang_words', [ "lang_id=? AND word_key LIKE 'core_badges_%'", Member::loggedIn()->language()->id ] ) as $row )
|
||||
{
|
||||
$langs[ \mb_substr( $row['word_key'], 12 ) ] = $row['word_default'];
|
||||
$langs[ mb_substr( $row['word_key'], 12 ) ] = $row['word_default'];
|
||||
}
|
||||
|
||||
$assignedBadges = \IPS\core\Achievements\Badge::getAssignedBadgeIds();
|
||||
$assignedBadges = Badge::getAssignedBadgeIds();
|
||||
|
||||
$where = NULL;
|
||||
if ( \count( $assignedBadges ) )
|
||||
if ( count( $assignedBadges ) )
|
||||
{
|
||||
$where = [ \IPS\Db::i()->in( '`id`', $assignedBadges, TRUE ) ];
|
||||
$where = [ Db::i()->in( '`id`', $assignedBadges, TRUE ) ];
|
||||
}
|
||||
|
||||
/* Ranks */
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_badges', $where ) as $badge )
|
||||
foreach ( Db::i()->select( '*', 'core_badges', $where ) as $badge )
|
||||
{
|
||||
try
|
||||
{
|
||||
$icon = \IPS\File::get( 'core_Badges', $badge['image'] );
|
||||
$icon = File::get( 'core_Badges', $badge['image'] );
|
||||
|
||||
$forXml = [
|
||||
'manually_awarded' => $badge['manually_awarded'],
|
||||
@@ -233,12 +262,12 @@ class _badges extends \IPS\Node\Controller
|
||||
|
||||
$xml->addChild( 'badge', $forXml );
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
catch( Exception $e ) { }
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__exported_badges' );
|
||||
Session::i()->log( 'acplogs__exported_badges' );
|
||||
|
||||
\IPS\Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "Achievement_Badges.xml" ) ) );
|
||||
Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( 'Content-Disposition' => Output::getContentDisposition( 'attachment', "Achievement_Badges.xml" ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,27 +275,27 @@ class _badges extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function import()
|
||||
public function import() : void
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
Session::i()->csrfCheck();
|
||||
|
||||
if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key )
|
||||
if ( !file_exists( Request::i()->file ) or md5_file( Request::i()->file ) !== Request::i()->key )
|
||||
{
|
||||
\IPS\Output::i()->error( 'generic_error', '3C130/1', 500, '' );
|
||||
Output::i()->error( 'generic_error', '3C130/1', 500, '' );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
\IPS\core\Achievements\Badge::importXml( \IPS\Request::i()->file, ( ! empty( \IPS\Request::i()->wipe ) ) );
|
||||
Badge::importXml( Request::i()->file, ( ! empty( Request::i()->wipe ) ) );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( $e->getMessage(), '2C422/1', 403, '' );
|
||||
Output::i()->error( $e->getMessage(), '2C422/1', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__imported_badges' );
|
||||
Session::i()->log( 'acplogs__imported_badges' );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=badges' ), 'completed' );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=badges' ), 'completed' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,24 +303,41 @@ class _badges extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function importForm()
|
||||
public function importForm() : void
|
||||
{
|
||||
$form = new \IPS\Helpers\Form( 'form', 'acp_achievements_import' );
|
||||
$form = new Form( 'form', 'acp_achievements_import' );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'acp_achievements_import_option_badge_wipe', 0, FALSE, [], NULL, NULL, NULL, 'acp_achievements_import_option_rule_wipe' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'acp_achievements_import_xml', NULL, FALSE, [ 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ], NULL, NULL, NULL, 'acp_achievements_import_xml' ) );
|
||||
$form->add( new YesNo( 'acp_achievements_import_option_badge_wipe', 0, FALSE, [], NULL, NULL, NULL, 'acp_achievements_import_option_rule_wipe' ) );
|
||||
$form->add( new Upload( 'acp_achievements_import_xml', NULL, FALSE, [ 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ], NULL, NULL, NULL, 'acp_achievements_import_xml' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
/* Move it to a temporary location */
|
||||
$tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
$tempFile = tempnam( TEMP_DIRECTORY, 'IPS' );
|
||||
move_uploaded_file( $values['acp_achievements_import_xml'], $tempFile );
|
||||
|
||||
/* Initate a redirector */
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=badges&do=import' )->setQueryString( array('wipe' => $values['acp_achievements_import_option_badge_wipe'], 'file' => $tempFile, 'key' => md5_file( $tempFile )) )->csrf() );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=badges&do=import' )->setQueryString( array('wipe' => $values['acp_achievements_import_option_badge_wipe'], 'file' => $tempFile, 'key' => md5_file( $tempFile )) )->csrf() );
|
||||
}
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_import'), $form, FALSE );
|
||||
Output::i()->output = Theme::i()->getTemplate( 'global' )->block( Member::loggedIn()->language()->addToStack('acp_achievements_import'), $form, FALSE );
|
||||
}
|
||||
|
||||
|
||||
public function badgePreview() : void
|
||||
{
|
||||
header('content-type: image/svg+xml');
|
||||
echo new CustomBadge(
|
||||
Request::i()->shape ?: 'circle',
|
||||
Request::i()->foreground ?: '#fff',
|
||||
Request::i()->background ?: '#eeb95f',
|
||||
Request::i()->border ?: '#f7d36f',
|
||||
Request::i()->icon ?: null,
|
||||
(int) Request::i()->rotation ?: 0,
|
||||
(int) Request::i()->sides ?: 5,
|
||||
(int) Request::i()->numberoverlay ?: 0
|
||||
);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
@@ -11,40 +11,65 @@
|
||||
namespace IPS\core\modules\admin\achievements;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\core\Achievements\Rank;
|
||||
use IPS\core\Achievements\Rule;
|
||||
use IPS\Db;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\File;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Helpers\Form\Upload;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Controller;
|
||||
use IPS\Output;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Theme;
|
||||
use IPS\Xml\SimpleXML;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function intval;
|
||||
use function mb_substr;
|
||||
use const IPS\TEMP_DIRECTORY;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement ranks
|
||||
*/
|
||||
class _ranks extends \IPS\Node\Controller
|
||||
class ranks extends Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
public static bool $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* @brief Cached counts
|
||||
*/
|
||||
public static $counts = [];
|
||||
public static array $counts = [];
|
||||
|
||||
/**
|
||||
* Node Class
|
||||
*/
|
||||
protected $nodeClass = 'IPS\core\Achievements\Rank';
|
||||
protected string $nodeClass = 'IPS\core\Achievements\Rank';
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
public function execute() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'ranks_manage' );
|
||||
Dispatcher::i()->checkAcpPermission( 'ranks_manage' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
@@ -53,51 +78,48 @@ class _ranks extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
protected function manage() : void
|
||||
{
|
||||
/* If the members table is very large, this can take the whole thing down,
|
||||
so let's skip it. */
|
||||
if( !\IPS\Db::i()->recommendManualQuery( 'core_members' ) )
|
||||
static::$counts = [];
|
||||
$previousCount = NULL;
|
||||
|
||||
$allRanks = array_values( Rank::getStore() );
|
||||
$totalRanks = count( $allRanks );
|
||||
for ( $i = 0; $i < $totalRanks; $i++ )
|
||||
{
|
||||
static::$counts = [];
|
||||
$previousCount = NULL;
|
||||
|
||||
$allRanks = array_values( \IPS\core\Achievements\Rank::getStore() );
|
||||
$totalRanks = \count( $allRanks );
|
||||
for ( $i = 0; $i < $totalRanks; $i++ )
|
||||
$where = [];
|
||||
$where[] = [ 'achievements_points>=' . intval( $allRanks[ $i ]->points ) ];
|
||||
if ( isset( $allRanks[ $i + 1 ] ) )
|
||||
{
|
||||
$where = [];
|
||||
$where[] = [ 'achievements_points>=' . \intval( $allRanks[ $i ]->points ) ];
|
||||
if ( isset( $allRanks[ $i + 1 ] ) )
|
||||
{
|
||||
$where[] = [ 'achievements_points<' . \intval( $allRanks[ $i + 1 ]->points ) ];
|
||||
}
|
||||
static::$counts[ $allRanks[ $i ]->id ] = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $where )->first();
|
||||
$where[] = [ 'achievements_points<' . intval( $allRanks[ $i + 1 ]->points ) ];
|
||||
}
|
||||
static::$counts[ $allRanks[ $i ]->id ] = Db::i()->select( 'COUNT(*)', 'core_members', $where )->first();
|
||||
}
|
||||
|
||||
if( $data = \IPS\core\Achievements\Rule::getRebuildProgress() )
|
||||
if( $data = Rule::getRebuildProgress() )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'achievements' )->rebuildProgress( $data, TRUE );
|
||||
Output::i()->output .= Theme::i()->getTemplate( 'achievements' )->rebuildProgress( $data, TRUE );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sidebar['actions']['export'] = array(
|
||||
Output::i()->sidebar['actions']['export'] = array(
|
||||
'primary' => false,
|
||||
'icon' => 'cloud-download',
|
||||
'link' => \IPS\Http\Url::internal('app=core&module=achievements&controller=ranks&do=export'),
|
||||
'link' => Url::internal('app=core&module=achievements&controller=ranks&do=export'),
|
||||
'data' => [],
|
||||
'title' => 'acp_achievements_export',
|
||||
);
|
||||
|
||||
\IPS\Output::i()->sidebar['actions']['import'] = array(
|
||||
Output::i()->sidebar['actions']['import'] = array(
|
||||
'primary' => false,
|
||||
'icon' => 'cloud-upload',
|
||||
'link' => \IPS\Http\Url::internal('app=core&module=achievements&controller=ranks&do=importForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_import') ),
|
||||
'link' => Url::internal('app=core&module=achievements&controller=ranks&do=importForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('acp_achievements_import') ),
|
||||
'title' => 'acp_achievements_import',
|
||||
);
|
||||
|
||||
return parent::manage();
|
||||
Output::i()->output .= Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'cheev_ranks_blurb' );
|
||||
|
||||
parent::manage();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,11 +127,11 @@ class _ranks extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function importForm()
|
||||
public function importForm() : void
|
||||
{
|
||||
$form = new \IPS\Helpers\Form( 'form', 'acp_achievements_import' );
|
||||
$form = new Form( 'form', 'acp_achievements_import' );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'acp_achievements_import_option', 'replace', FALSE, [ 'options' =>
|
||||
$form->add( new Radio( 'acp_achievements_import_option', 'replace', FALSE, [ 'options' =>
|
||||
[
|
||||
'wipe' => 'acp_achievements_import_option_wipe',
|
||||
'replace' => 'acp_achievements_import_option_replace'
|
||||
@@ -117,28 +139,28 @@ class _ranks extends \IPS\Node\Controller
|
||||
'toggles' => [ 'wipe' => [ 'acp_achievements_import_option_wipe_sure' ] ]
|
||||
] ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'acp_achievements_import_option_wipe_sure', 0, FALSE, [], NULL, NULL, NULL, 'acp_achievements_import_option_wipe_sure' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'acp_achievements_import_xml', NULL, FALSE, [ 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ], NULL, NULL, NULL, 'acp_achievements_import_xml' ) );
|
||||
$form->add( new YesNo( 'acp_achievements_import_option_wipe_sure', 0, FALSE, [], NULL, NULL, NULL, 'acp_achievements_import_option_wipe_sure' ) );
|
||||
$form->add( new Upload( 'acp_achievements_import_xml', NULL, FALSE, [ 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ], NULL, NULL, NULL, 'acp_achievements_import_xml' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if ( $values['acp_achievements_import_option'] == 'wipe' and empty( $values['acp_achievements_import_option_wipe_sure'] ) )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'acp_achievements_import_error' );
|
||||
$form->error = Member::loggedIn()->language()->addToStack( 'acp_achievements_import_error' );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move it to a temporary location */
|
||||
$tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
$tempFile = tempnam( TEMP_DIRECTORY, 'IPS' );
|
||||
move_uploaded_file( $values['acp_achievements_import_xml'], $tempFile );
|
||||
|
||||
/* Initate a redirector */
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=ranks&do=import' )->setQueryString( array('option' => $values['acp_achievements_import_option'], 'file' => $tempFile, 'key' => md5_file( $tempFile )) )->csrf() );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=ranks&do=import' )->setQueryString( array('option' => $values['acp_achievements_import_option'], 'file' => $tempFile, 'key' => md5_file( $tempFile )) )->csrf() );
|
||||
}
|
||||
}
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_import'), $form, FALSE );
|
||||
Output::i()->output = Theme::i()->getTemplate( 'global' )->block( Member::loggedIn()->language()->addToStack('acp_achievements_import'), $form, FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,47 +168,47 @@ class _ranks extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function import()
|
||||
public function import() : void
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
Session::i()->csrfCheck();
|
||||
|
||||
if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key )
|
||||
if ( !file_exists( Request::i()->file ) or md5_file( Request::i()->file ) !== Request::i()->key )
|
||||
{
|
||||
\IPS\Output::i()->error( 'generic_error', '3C130/1', 500, '' );
|
||||
Output::i()->error( 'generic_error', '3C130/1', 500, '' );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
\IPS\core\Achievements\Rank::importXml( \IPS\Request::i()->file, \IPS\Request::i()->option );
|
||||
Rank::importXml( Request::i()->file, Request::i()->option );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( $e->getMessage(), '2C423/1', 403, '' );
|
||||
Output::i()->error( $e->getMessage(), '2C423/1', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__imported_ranks' );
|
||||
Session::i()->log( 'acplogs__imported_ranks' );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=ranks' ), 'completed' );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=ranks' ), 'completed' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Export ranks with images as an XML file (XML is better at potentially large values from raw image data)
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function export()
|
||||
public function export() : void
|
||||
{
|
||||
$xml = \IPS\Xml\SimpleXML::create('ranks');
|
||||
$xml = SimpleXML::create('ranks');
|
||||
$langs = [];
|
||||
|
||||
foreach( \IPS\Db::i()->select('word_key, word_default', 'core_sys_lang_words', [ "lang_id=? AND word_key LIKE 'core_member_rank_%'", \IPS\Member::loggedIn()->language()->id ] ) as $row )
|
||||
foreach( Db::i()->select('word_key, word_default', 'core_sys_lang_words', [ "lang_id=? AND word_key LIKE 'core_member_rank_%'", Member::loggedIn()->language()->id ] ) as $row )
|
||||
{
|
||||
$langs[ \mb_substr( $row['word_key'], 17 ) ] = $row['word_default'];
|
||||
$langs[ mb_substr( $row['word_key'], 17 ) ] = $row['word_default'];
|
||||
}
|
||||
|
||||
/* Ranks */
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_member_ranks') as $row )
|
||||
foreach ( Db::i()->select( '*', 'core_member_ranks') as $row )
|
||||
{
|
||||
$forXml = [
|
||||
'title' => $langs[$row['id']] ?? NULL,
|
||||
@@ -197,19 +219,19 @@ class _ranks extends \IPS\Node\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
$icon = \IPS\File::get( 'core_Ranks', $row['icon'] );
|
||||
$icon = File::get( 'core_Ranks', $row['icon'] );
|
||||
$forXml['icon_name'] = $icon->originalFilename;
|
||||
$forXml['icon_data'] = base64_encode( $icon->contents() );
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
catch( Exception $e ) { }
|
||||
}
|
||||
|
||||
$xml->addChild( 'rank', $forXml );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__exported_ranks' );
|
||||
Session::i()->log( 'acplogs__exported_ranks' );
|
||||
|
||||
\IPS\Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "Achievement_Ranks.xml" ) ) );
|
||||
Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( 'Content-Disposition' => Output::getContentDisposition( 'attachment', "Achievement_Ranks.xml" ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,16 +240,10 @@ class _ranks extends \IPS\Node\Controller
|
||||
* @param object $node Node returned from $nodeClass::load()
|
||||
* @return NULL|string
|
||||
*/
|
||||
public function _getRowHtml( $node )
|
||||
public function _getRowHtml( object $node ): ?string
|
||||
{
|
||||
/* If the counts are empty, then the table was too large, so ignore this. */
|
||||
if( empty( static::$counts ) )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
$url = \IPS\Http\Url::internal("app=core&module=members&controller=members&advanced_search_submitted=1&members_achievements_points={$node->id}")->csrf();
|
||||
$url = Url::internal("app=core&module=members&controller=members&advanced_search_submitted=1&members_achievements_points={$node->id}")->csrf();
|
||||
|
||||
return \IPS\Theme::i()->getTemplate('achievements')->memberCount( $url, static::$counts[ $node->id ] );
|
||||
return Theme::i()->getTemplate('achievements')->memberCount( $url, static::$counts[ $node->id ] );
|
||||
}
|
||||
}
|
||||
@@ -11,37 +11,60 @@
|
||||
namespace IPS\core\modules\admin\achievements;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use IPS\core\Achievements\Rule;
|
||||
use IPS\Db;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\File;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Upload;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Controller;
|
||||
use IPS\Output;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Request;
|
||||
use IPS\Session;
|
||||
use IPS\Theme;
|
||||
use IPS\Xml\SimpleXML;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function mb_substr;
|
||||
use const IPS\TEMP_DIRECTORY;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement rules
|
||||
*/
|
||||
class _rules extends \IPS\Node\Controller
|
||||
class rules extends Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
public static bool $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Node Class
|
||||
*/
|
||||
protected $nodeClass = 'IPS\core\Achievements\Rule';
|
||||
protected string $nodeClass = 'IPS\core\Achievements\Rule';
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
public function execute() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rules_manage' );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'achievements/achievements.css', 'core', 'admin' ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_members.js', 'core' ) );
|
||||
Dispatcher::i()->checkAcpPermission( 'rules_manage' );
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'achievements/achievements.css', 'core', 'admin' ) );
|
||||
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'admin_members.js', 'core' ) );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
@@ -50,79 +73,79 @@ class _rules extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
protected function manage() : void
|
||||
{
|
||||
$baseUrl = \IPS\Http\Url::internal('app=core&module=achievements&controller=rules');
|
||||
$baseUrl = Url::internal('app=core&module=achievements&controller=rules');
|
||||
$perPage = 25;
|
||||
$totalCount = \IPS\Db::i()->select( 'COUNT(*)', 'core_achievements_rules' )->first();
|
||||
$totalCount = Db::i()->select( 'COUNT(*)', 'core_achievements_rules' )->first();
|
||||
$totalPages = ceil( $totalCount / $perPage );
|
||||
$page = \IPS\Request::i()->page ?? 1;
|
||||
$page = Request::i()->page ?? 1;
|
||||
|
||||
$query = \IPS\Db::i()->select( '*', 'core_achievements_rules', NULL, 'action, milestone ASC', [ ( $perPage * ( $page - 1 ) ), $perPage ] );
|
||||
$rules = new \IPS\Patterns\ActiveRecordIterator( $query, 'IPS\core\Achievements\Rule' );
|
||||
$pagination = $totalPages > 1 ? \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, $totalPages, $page, $perPage ) : '';
|
||||
$query = Db::i()->select( '*', 'core_achievements_rules', NULL, 'action, milestone ASC', [ ( $perPage * ( $page - 1 ) ), $perPage ] );
|
||||
$rules = new ActiveRecordIterator( $query, 'IPS\core\Achievements\Rule' );
|
||||
$pagination = $totalPages > 1 ? Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, $totalPages, $page, $perPage ) : '';
|
||||
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
if( Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->json([
|
||||
'rows' => \IPS\Theme::i()->getTemplate( 'achievements' )->rulesListRows( $rules ),
|
||||
Output::i()->json([
|
||||
'rows' => Theme::i()->getTemplate( 'achievements' )->rulesListRows( $rules ),
|
||||
'pagination' => $pagination
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['export'] = array(
|
||||
Output::i()->sidebar['actions']['export'] = array(
|
||||
'primary' => false,
|
||||
'icon' => 'cloud-download',
|
||||
'link' => \IPS\Http\Url::internal('app=core&module=achievements&controller=rules&do=export'),
|
||||
'link' => Url::internal('app=core&module=achievements&controller=rules&do=export'),
|
||||
'data' => [],
|
||||
'title' => 'acp_achievements_export',
|
||||
);
|
||||
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'achievements', 'rules_add' ) )
|
||||
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'achievements', 'rules_add' ) )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['import'] = array(
|
||||
Output::i()->sidebar['actions']['import'] = array(
|
||||
'primary' => false,
|
||||
'icon' => 'cloud-upload',
|
||||
'link' => \IPS\Http\Url::internal('app=core&module=achievements&controller=rules&do=importForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_import') ),
|
||||
'link' => Url::internal('app=core&module=achievements&controller=rules&do=importForm'),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('acp_achievements_import') ),
|
||||
'title' => 'acp_achievements_import',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'achievements' )->rulesList( $rules, $pagination, $this->_getRootButtons() );
|
||||
Output::i()->output = Theme::i()->getTemplate( 'forms', 'core' )->blurb( 'cheev_rules_blurb' ) . Theme::i()->getTemplate( 'achievements' )->rulesList( $rules, $pagination, $this->_getRootButtons() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form as returned by _addEditForm()
|
||||
* @param Form $form The form as returned by _addEditForm()
|
||||
* @return string
|
||||
*/
|
||||
protected function _showForm( \IPS\Helpers\Form $form )
|
||||
protected function _showForm( Form $form ): string
|
||||
{
|
||||
\IPS\Output::i()->hiddenElements = array('acpHeader');
|
||||
Output::i()->hiddenElements = array('acpHeader');
|
||||
|
||||
if ( \IPS\Request::i()->id )
|
||||
if ( Request::i()->id )
|
||||
{
|
||||
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rules_edit' );
|
||||
Dispatcher::i()->checkAcpPermission( 'rules_edit' );
|
||||
try
|
||||
{
|
||||
$form->hiddenValues['rule_enabled'] = \IPS\core\Achievements\Rule::load( \IPS\Request::i()->id )->enabled;
|
||||
$form->hiddenValues['rule_enabled'] = Rule::load( Request::i()->id )->enabled;
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
catch( Exception $e ) { }
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rules_add' );
|
||||
Dispatcher::i()->checkAcpPermission( 'rules_add' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_achievements_rules');
|
||||
Output::i()->title = Member::loggedIn()->language()->addToStack('menu__core_achievements_rules');
|
||||
|
||||
return $form->customTemplate( [ \IPS\Theme::i()->getTemplate( 'achievements' ), 'rulesForm' ] );
|
||||
return $form->customTemplate( [ Theme::i()->getTemplate( 'achievements' ), 'rulesForm' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,32 +153,32 @@ class _rules extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function toggleEnabled()
|
||||
protected function toggleEnabled() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rules_edit' );
|
||||
Dispatcher::i()->checkAcpPermission( 'rules_edit' );
|
||||
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
Session::i()->csrfCheck();
|
||||
|
||||
try
|
||||
{
|
||||
$rule = \IPS\core\Achievements\Rule::load( \IPS\Request::i()->id );
|
||||
$rule->enabled = (int) \IPS\Request::i()->enable;
|
||||
$rule = Rule::load( Request::i()->id );
|
||||
$rule->enabled = (int) Request::i()->enable;
|
||||
$rule->save();
|
||||
|
||||
if ( \IPS\Request::i()->enable )
|
||||
if ( Request::i()->enable )
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplogs__rule_enabled', array( $rule->id => FALSE ) );
|
||||
Session::i()->log( 'acplogs__rule_enabled', array( $rule->id => FALSE ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplogs__rule_disabled', array( $rule->id => FALSE ) );
|
||||
Session::i()->log( 'acplogs__rule_disabled', array( $rule->id => FALSE ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=rules' ), 'updated' );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=rules' ), 'updated' );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2T353/3', 404, '' ); /* @todo error code */
|
||||
Output::i()->error( 'node_error', '2T353/3', 404, '' ); /* @todo error code */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,21 +186,21 @@ class _rules extends \IPS\Node\Controller
|
||||
* Export rules with badges as an XML file (XML is better at potentially large values from raw image data)
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function export()
|
||||
public function export() : void
|
||||
{
|
||||
$xml = \IPS\Xml\SimpleXML::create('rules');
|
||||
$xml = SimpleXML::create('rules');
|
||||
$badgeMap = [];
|
||||
|
||||
$langs = [];
|
||||
foreach( \IPS\Db::i()->select( 'word_key, word_default', 'core_sys_lang_words', [ 'lang_id=? AND (word_key LIKE \'core_award_subject_badge_%\' OR word_key LIKE \'core_award_other_badge_%\')', \IPS\Member::loggedIn()->language()->id ] ) as $row )
|
||||
foreach( Db::i()->select( 'word_key, word_default', 'core_sys_lang_words', [ 'lang_id=? AND (word_key LIKE \'core_award_subject_badge_%\' OR word_key LIKE \'core_award_other_badge_%\')', Member::loggedIn()->language()->id ] ) as $row )
|
||||
{
|
||||
$langs[ $row['word_key'] ] = $row['word_default'];
|
||||
}
|
||||
|
||||
/* Rules */
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_achievements_rules') as $row )
|
||||
foreach ( Db::i()->select( '*', 'core_achievements_rules') as $row )
|
||||
{
|
||||
$forXml = [];
|
||||
foreach( $row as $k => $v )
|
||||
@@ -214,19 +237,19 @@ class _rules extends \IPS\Node\Controller
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
if ( \count( $badgeMap ) )
|
||||
if ( count( $badgeMap ) )
|
||||
{
|
||||
$langs = [];
|
||||
foreach( \IPS\Db::i()->select('word_key, word_default', 'core_sys_lang_words', [ \IPS\Db::i()->like( 'word_key', 'core_badges_') ] ) as $row )
|
||||
foreach( Db::i()->select('word_key, word_default', 'core_sys_lang_words', [ Db::i()->like( 'word_key', 'core_badges_') ] ) as $row )
|
||||
{
|
||||
$langs[ \mb_substr( $row['word_key'], 12 ) ] = $row['word_default'];
|
||||
$langs[ mb_substr( $row['word_key'], 12 ) ] = $row['word_default'];
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select('*', 'core_badges', [ \IPS\Db::i()->in( '`id`', array_keys( $badgeMap ) ) ] ) as $badge )
|
||||
foreach( Db::i()->select('*', 'core_badges', [ Db::i()->in( '`id`', array_keys( $badgeMap ) ) ] ) as $badge )
|
||||
{
|
||||
try
|
||||
{
|
||||
$icon = \IPS\File::get( 'core_Badges', $badge['image'] );
|
||||
$icon = File::get( 'core_Badges', $badge['image'] );
|
||||
|
||||
$xml->addChild( 'badge', [
|
||||
'manually_awarded' => $badge['manually_awarded'],
|
||||
@@ -236,13 +259,13 @@ class _rules extends \IPS\Node\Controller
|
||||
'icon_data' => base64_encode( $icon->contents() )
|
||||
] );
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
catch( Exception $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__rules_exported' );
|
||||
Session::i()->log( 'acplogs__rules_exported' );
|
||||
|
||||
\IPS\Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "Achievement_Rules.xml" ) ) );
|
||||
Output::i()->sendOutput( $xml->asXML(), 200, 'application/xml', array( 'Content-Disposition' => Output::getContentDisposition( 'attachment', "Achievement_Rules.xml" ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,27 +273,27 @@ class _rules extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function importForm()
|
||||
public function importForm() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rules_add' );
|
||||
$form = new \IPS\Helpers\Form( 'form', 'acp_achievements_import' );
|
||||
Dispatcher::i()->checkAcpPermission( 'rules_add' );
|
||||
$form = new Form( 'form', 'acp_achievements_import' );
|
||||
|
||||
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack( 'acp_achievements_import_rules_message'), 'ipsMessage ipsMessage_info');
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'acp_achievements_import_option_rule_wipe', 0, FALSE, [], NULL, NULL, NULL, 'acp_achievements_import_option_rule_wipe' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'acp_achievements_import_xml', NULL, FALSE, [ 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ], NULL, NULL, NULL, 'acp_achievements_import_xml' ) );
|
||||
$form->addMessage( Member::loggedIn()->language()->addToStack( 'acp_achievements_import_rules_message'), 'ipsMessage ipsMessage--info');
|
||||
$form->add( new YesNo( 'acp_achievements_import_option_rule_wipe', 0, FALSE, [], NULL, NULL, NULL, 'acp_achievements_import_option_rule_wipe' ) );
|
||||
$form->add( new Upload( 'acp_achievements_import_xml', NULL, FALSE, [ 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ], NULL, NULL, NULL, 'acp_achievements_import_xml' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
/* Move it to a temporary location */
|
||||
$tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
$tempFile = tempnam( TEMP_DIRECTORY, 'IPS' );
|
||||
move_uploaded_file( $values['acp_achievements_import_xml'], $tempFile );
|
||||
|
||||
/* Initate a redirector */
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=rules&do=import' )->setQueryString( array('wipe' => $values['acp_achievements_import_option_rule_wipe'], 'file' => $tempFile, 'key' => md5_file( $tempFile )) )->csrf() );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=rules&do=import' )->setQueryString( array('wipe' => $values['acp_achievements_import_option_rule_wipe'], 'file' => $tempFile, 'key' => md5_file( $tempFile )) )->csrf() );
|
||||
}
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->block( \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_import'), $form, FALSE );
|
||||
Output::i()->output = Theme::i()->getTemplate( 'global' )->block( Member::loggedIn()->language()->addToStack('acp_achievements_import'), $form, FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,27 +301,27 @@ class _rules extends \IPS\Node\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function import()
|
||||
public function import() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rules_add' );
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
Dispatcher::i()->checkAcpPermission( 'rules_add' );
|
||||
Session::i()->csrfCheck();
|
||||
|
||||
if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key )
|
||||
if ( !file_exists( Request::i()->file ) or md5_file( Request::i()->file ) !== Request::i()->key )
|
||||
{
|
||||
\IPS\Output::i()->error( 'generic_error', '3C130/1', 500, '' );
|
||||
Output::i()->error( 'generic_error', '3C130/1', 500, '' );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
\IPS\core\Achievements\Rule::importXml( \IPS\Request::i()->file, ( ! empty( \IPS\Request::i()->wipe ) ) );
|
||||
Rule::importXml( Request::i()->file, ( ! empty( Request::i()->wipe ) ) );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
catch( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( $e->getMessage(), '2C424/1', 403, '' );
|
||||
Output::i()->error( $e->getMessage(), '2C424/1', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplogs__rules_imported' );
|
||||
Session::i()->log( 'acplogs__rules_imported' );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=rules' ), 'completed' );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=rules' ), 'completed' );
|
||||
}
|
||||
}
|
||||
@@ -11,25 +11,45 @@
|
||||
namespace IPS\core\modules\admin\achievements;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\core\Achievements\Rule;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\Dispatcher\Controller;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Checkbox;
|
||||
use IPS\Helpers\Form\CheckboxSet;
|
||||
use IPS\Helpers\Form\Date;
|
||||
use IPS\Helpers\Form\Interval;
|
||||
use IPS\Helpers\Form\Number;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Group;
|
||||
use IPS\Output;
|
||||
use IPS\Session;
|
||||
use IPS\Settings as SettingsClass;
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement settings
|
||||
*/
|
||||
class _settings extends \IPS\Dispatcher\Controller
|
||||
class settings extends Controller
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
public function execute() : void
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'settings_manage' );
|
||||
Dispatcher::i()->checkAcpPermission( 'settings_manage' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
@@ -38,45 +58,45 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
protected function manage() : void
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form = new Form;
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'achievements_enabled', \IPS\Settings::i()->achievements_enabled, FALSE, [ 'togglesOn' => [ 'rare_badge_percent', 'prune_points_log', 'rules_exclude_groups', 'achievements_recognize_max_per_user_day' ] ] ) );
|
||||
$form->add( new YesNo( 'achievements_enabled', SettingsClass::i()->achievements_enabled, FALSE, [ 'togglesOn' => [ 'rare_badge_percent', 'prune_points_log', 'rules_exclude_groups', 'achievements_recognize_max_per_user_day' ] ] ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'rare_badge_percent', \IPS\Settings::i()->rare_badge_percent, FALSE, [ 'decimals' => 1, 'unlimited' => 0, 'unlimitedLang' => 'never' ], NULL, \IPS\Member::loggedIn()->language()->addToStack('rare_badge_percent_prefix'), \IPS\Member::loggedIn()->language()->addToStack('rare_badge_percent_suffix'), 'rare_badge_percent' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Interval( 'prune_points_log', \IPS\Settings::i()->prune_points_log, FALSE, [ 'valueAs' => \IPS\Helpers\Form\Interval::DAYS, 'unlimited' => 0, 'unlimitedLang' => 'never' ], NULL, \IPS\Member::loggedIn()->language()->addToStack('after'), NULL, 'prune_points_log' ) );
|
||||
$groups = array_combine( array_keys( \IPS\Member\Group::groups( TRUE, FALSE ) ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups( TRUE, FALSE ) ) );
|
||||
$selectedGroups = json_decode( \IPS\Settings::i()->rules_exclude_groups, TRUE );
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'rules_exclude_groups', $selectedGroups, FALSE, array( 'options' => $groups, 'multiple' => true ), NULL, NULL, NULL, 'rules_exclude_groups' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'achievements_recognize_max_per_user_day', \IPS\Settings::i()->achievements_recognize_max_per_user_day, FALSE, [ 'unlimited' => -1 ], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievements_recognize_max_per_user_day_prefix'), \IPS\Member::loggedIn()->language()->addToStack('achievements_recognize_max_per_user_day_suffix'), 'achievements_recognize_max_per_user_day' ) );
|
||||
$form->add( new Number( 'rare_badge_percent', SettingsClass::i()->rare_badge_percent, FALSE, [ 'decimals' => 1, 'unlimited' => 0, 'unlimitedLang' => 'never' ], NULL, Member::loggedIn()->language()->addToStack('rare_badge_percent_prefix'), Member::loggedIn()->language()->addToStack('rare_badge_percent_suffix'), 'rare_badge_percent' ) );
|
||||
$form->add( new Interval( 'prune_points_log', SettingsClass::i()->prune_points_log, FALSE, [ 'valueAs' => Interval::DAYS, 'unlimited' => 0, 'unlimitedLang' => 'never' ], NULL, Member::loggedIn()->language()->addToStack('after'), NULL, 'prune_points_log' ) );
|
||||
$groups = array_combine( array_keys( Group::groups( TRUE, FALSE ) ), array_map( function( $_group ) { return (string) $_group; }, Group::groups( TRUE, FALSE ) ) );
|
||||
$selectedGroups = json_decode( SettingsClass::i()->rules_exclude_groups, TRUE );
|
||||
$form->add( new CheckboxSet( 'rules_exclude_groups', $selectedGroups, FALSE, array( 'options' => $groups, 'multiple' => true ), NULL, NULL, NULL, 'rules_exclude_groups' ) );
|
||||
$form->add( new Number( 'achievements_recognize_max_per_user_day', SettingsClass::i()->achievements_recognize_max_per_user_day, FALSE, [ 'unlimited' => -1 ], NULL, Member::loggedIn()->language()->addToStack('achievements_recognize_max_per_user_day_prefix'), Member::loggedIn()->language()->addToStack('achievements_recognize_max_per_user_day_suffix'), 'achievements_recognize_max_per_user_day' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$values['rules_exclude_groups'] = json_encode( $values['rules_exclude_groups'] );
|
||||
$form->saveAsSettings( $values );
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__achievement_settings' );
|
||||
Session::i()->log( 'acplog__achievement_settings' );
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->achievements_enabled )
|
||||
if ( SettingsClass::i()->achievements_enabled )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['rebuild'] = array(
|
||||
Output::i()->sidebar['actions']['rebuild'] = array(
|
||||
'primary' => true,
|
||||
'icon' => 'plus',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=achievements&controller=settings&do=rebuildForm' )->csrf(),
|
||||
'data' => array('ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack( 'acp_rebuild_achievements' )),
|
||||
'link' => Url::internal( 'app=core&module=achievements&controller=settings&do=rebuildForm' )->csrf(),
|
||||
'data' => array('ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'acp_rebuild_achievements' )),
|
||||
'title' => 'acp_rebuild_achievements',
|
||||
);
|
||||
}
|
||||
|
||||
if( $data = \IPS\core\Achievements\Rule::getRebuildProgress() )
|
||||
if( $data = Rule::getRebuildProgress() )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'achievements' )->rebuildProgress( $data, TRUE );
|
||||
Output::i()->output .= Theme::i()->getTemplate( 'achievements' )->rebuildProgress( $data, TRUE );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('achievements_settings');
|
||||
\IPS\Output::i()->output .= $form;
|
||||
Output::i()->title = Member::loggedIn()->language()->addToStack('achievements_settings');
|
||||
Output::i()->output .= $form;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,37 +104,37 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function rebuildForm()
|
||||
protected function rebuildForm() : void
|
||||
{
|
||||
if ( ! \IPS\Settings::i()->achievements_enabled )
|
||||
if ( ! SettingsClass::i()->achievements_enabled )
|
||||
{
|
||||
\IPS\Output::i()->error( 'achievements_not_enabled', '1C421/1', 403, '' );
|
||||
Output::i()->error( 'achievements_not_enabled', '1C421/1', 403, '' );
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'rebuild_form', 'acp_rebuild_achievements_rebuild');
|
||||
$form->addMessage('acp_rebuild_achievements_blurb', 'ipsMessage ipsMessage_info');
|
||||
$form->add( new \IPS\Helpers\Form\Checkbox( 'acp_rebuild_achievements_checkbox', FALSE, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Date( 'acp_rebuild_achievements_time', 0, TRUE, [ 'unlimited' => 0, 'unlimitedLang' => 'acp_rebuild_achievements_time_unlimited' ] ) );
|
||||
$form = new Form( 'rebuild_form', 'acp_rebuild_achievements_rebuild');
|
||||
$form->addMessage('acp_rebuild_achievements_blurb', 'ipsMessage ipsMessage--info');
|
||||
$form->add( new Checkbox( 'acp_rebuild_achievements_checkbox', FALSE, TRUE ) );
|
||||
$form->add( new Date( 'acp_rebuild_achievements_time', 0, TRUE, [ 'unlimited' => 0, 'unlimitedLang' => 'acp_rebuild_achievements_time_unlimited' ] ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if ( ! $values['acp_rebuild_achievements_checkbox'] )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack('acp_achievements_rebuild_not_checked');
|
||||
$form->error = Member::loggedIn()->language()->addToStack('acp_achievements_rebuild_not_checked');
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplogs__achievements_rebuild' );
|
||||
\IPS\core\Achievements\Rule::rebuildAllAchievements( $values['acp_rebuild_achievements_time'] ?: NULL );
|
||||
Session::i()->log( 'acplogs__achievements_rebuild' );
|
||||
Rule::rebuildAllAchievements( $values['acp_rebuild_achievements_time'] ?: NULL );
|
||||
|
||||
\IPS\Settings::i()->changeValues( array('achievements_rebuilding' => 1) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=achievements&controller=settings' ) );
|
||||
SettingsClass::i()->changeValues( array('achievements_rebuilding' => 1) );
|
||||
Output::i()->redirect( Url::internal( 'app=core&module=achievements&controller=settings' ) );
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->bypassCsrfKeyCheck = TRUE;
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('acp_rebuild_achievements');
|
||||
\IPS\Output::i()->output = $form;
|
||||
Output::i()->bypassCsrfKeyCheck = TRUE;
|
||||
Output::i()->title = Member::loggedIn()->language()->addToStack('acp_rebuild_achievements');
|
||||
Output::i()->output = $form;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user