Version 4.7.13
This commit is contained in:
1 parent
fd22d99e69
commit
7124a02564
954 files changed
+29277
-59308
No files matched your search
@@ -104,6 +104,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Session::i()->log( 'acplogs__achievements_rebuild' );
|
||||
\IPS\core\Achievements\Rule::rebuildAllAchievements( $values['acp_rebuild_achievements_time'] ?: NULL );
|
||||
|
||||
\IPS\Settings::i()->changeValues( array('achievements_rebuilding' => 1) );
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief ajax
|
||||
* @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 09 May 2023
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\activitystats;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ajax
|
||||
*/
|
||||
class _ajax extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
// This is the default method if no 'do' parameter is specified
|
||||
}
|
||||
|
||||
// Create new methods with the same name as the 'do' parameter which should execute it
|
||||
}
|
||||
@@ -51,25 +51,7 @@ class _communityactivity extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Callback(
|
||||
\IPS\Http\Url::internal( 'app=core&module=activitystats&controller=communityactivity' ),
|
||||
array( $this, 'getResults' ),
|
||||
'',
|
||||
array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
),
|
||||
'AreaChart',
|
||||
'weekly',
|
||||
array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P90D' ) ), 'end' => \IPS\DateTime::ts( time() ) )
|
||||
);
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('activity'), 'number', FALSE );
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('member_activity_timeperiod');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'CommunityActivity' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=communityactivity" ) );
|
||||
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -82,107 +64,5 @@ class _communityactivity extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->output .= (string) $chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the results
|
||||
*
|
||||
* @param \IPS\Helpers\Chart\Callback $chart Chart object
|
||||
* @return array
|
||||
*/
|
||||
public function getResults( $chart )
|
||||
{
|
||||
/* Get results */
|
||||
$results = array();
|
||||
|
||||
if ( \IPS\Settings::i()->search_method == 'mysql' )
|
||||
{
|
||||
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_search_index', 'index_date_updated', 'index_author', $chart ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter' ) as $contentRouter )
|
||||
{
|
||||
foreach ( $contentRouter->classes as $class )
|
||||
{
|
||||
if ( isset( $class::$databaseColumnMap['author'] ) )
|
||||
{
|
||||
$results = array_replace_recursive( $results, $this->getSqlResults(
|
||||
$class::$databaseTable,
|
||||
$class::$databasePrefix . ( isset( $class::$databaseColumnMap['updated'] ) ? $class::$databaseColumnMap['updated'] : $class::$databaseColumnMap['date'] ),
|
||||
$class::$databasePrefix . $class::$databaseColumnMap['author'],
|
||||
$chart
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_reputation_index', 'rep_date', 'member_id', $chart ) );
|
||||
$results = array_replace_recursive( $results, $this->getSqlResults( 'core_follow', 'follow_added', 'follow_member_id', $chart ) );
|
||||
|
||||
/* Reformat now */
|
||||
$finalResults = array();
|
||||
|
||||
foreach( $results as $date => $members )
|
||||
{
|
||||
$finalResults[ $date ] = array( 'time' => $date, \IPS\Member::loggedIn()->language()->get('activity') => \count( $members ) );
|
||||
}
|
||||
|
||||
return $finalResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SQL query/results
|
||||
*
|
||||
* @note Consolidated to reduce duplicated code
|
||||
* @param string $table Database table
|
||||
* @param string $date Date column
|
||||
* @param string $author Author column
|
||||
* @param object $chart Chart
|
||||
* @return array
|
||||
*/
|
||||
protected function getSqlResults( $table, $date, $author, $chart )
|
||||
{
|
||||
/* What's our SQL time? */
|
||||
switch ( $chart->timescale )
|
||||
{
|
||||
case 'daily':
|
||||
$timescale = '%Y-%c-%e';
|
||||
break;
|
||||
|
||||
case 'weekly':
|
||||
$timescale = '%x-%v';
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$timescale = '%Y-%c';
|
||||
break;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
$where = array( array( "{$date}>?", 0 ) );
|
||||
$where[] = array( "{$author}>?", 0 );
|
||||
if ( $chart->start )
|
||||
{
|
||||
$where[] = array( "{$date}>?", $chart->start->getTimestamp() );
|
||||
}
|
||||
if ( $chart->end )
|
||||
{
|
||||
$where[] = array( "{$date}<?", $chart->end->getTimestamp() );
|
||||
}
|
||||
|
||||
/* First we need to get search index activity */
|
||||
$fromUnixTime = "FROM_UNIXTIME( IFNULL( {$date}, 0 ) )";
|
||||
if ( !$chart->timezoneError and \IPS\Member::loggedIn()->timezone and \in_array( \IPS\Member::loggedIn()->timezone, \IPS\DateTime::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
$fromUnixTime = "CONVERT_TZ( {$fromUnixTime}, @@session.time_zone, '" . \IPS\Db::i()->escape_string( \IPS\Member::loggedIn()->timezone ) . "' )";
|
||||
}
|
||||
|
||||
$stmt = \IPS\Db::i()->select( "DATE_FORMAT( {$fromUnixTime}, '{$timescale}' ) AS time, {$author}", $table, $where, 'time ASC', NULL, array( $author, 'time' ) );
|
||||
|
||||
foreach( $stmt as $row )
|
||||
{
|
||||
$results[ $row['time'] ][ $row[ $author ] ] = 1;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,34 +46,7 @@ class _deletedcontent extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=deletedcontent' ), 'core_deletion_log', 'dellog_deleted_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'dellog_content_class', 'dellog_deleted_date' ), 'deletedcontent' );
|
||||
|
||||
$chart->groupBy = 'dellog_content_class';
|
||||
|
||||
$types = \IPS\Db::i()->select( 'DISTINCT(dellog_content_class)', 'core_deletion_log' );
|
||||
|
||||
foreach( $types as $class )
|
||||
{
|
||||
$lang = $class::$title;
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( $lang ), 'number', 'COUNT(*)', TRUE, $class );
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_deletedcontent_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
$chart->tableParsers = array(
|
||||
'dellog_deleted_date' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'DeletedContent' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=deletedcontent" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_deletedcontent');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
|
||||
@@ -59,68 +59,7 @@ class _emailstats extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$activeTab = $this->_getActiveTab();
|
||||
|
||||
/* Determine minimum date */
|
||||
$minimumDate = NULL;
|
||||
|
||||
if( \IPS\Settings::i()->prune_log_emailstats > 0 )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->prune_log_emailstats . 'D' ) );
|
||||
}
|
||||
|
||||
/* We can't retrieve any stats prior to the new tracking being implemented */
|
||||
try
|
||||
{
|
||||
$oldestLog = \IPS\Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'emails_sent' ) )->first();
|
||||
|
||||
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::ts( $oldestLog );
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* We have nothing tracked, set minimum date to today */
|
||||
$minimumDate = \IPS\DateTime::create();
|
||||
}
|
||||
|
||||
$startDate = \IPS\DateTime::ts( time() - ( 60 * 60 * 24 * 30 ) );
|
||||
|
||||
/* If our start date is older than our minimum date, use that as the start date instead */
|
||||
if ( $startDate->getTimestamp() < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$startDate = $minimumDate;
|
||||
}
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Callback(
|
||||
\IPS\Http\Url::internal( 'app=core&module=activitystats&controller=emailstats&tab=' . $activeTab ),
|
||||
array( $this, 'getResults' ),
|
||||
'',
|
||||
array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4,
|
||||
'height' => 450
|
||||
),
|
||||
'LineChart',
|
||||
'daily',
|
||||
array( 'start' => $startDate, 'end' => \IPS\DateTime::create() ),
|
||||
'',
|
||||
$minimumDate
|
||||
);
|
||||
|
||||
$chart->availableTypes = array( 'LineChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_emailstats_' . $activeTab);
|
||||
|
||||
/* Force the notice that the chart is displayed in the server time zone */
|
||||
$chart->timezoneError = TRUE;
|
||||
$chart->hideTimezoneLink = TRUE;
|
||||
|
||||
foreach( $this->_getEmailTypes() as $series )
|
||||
{
|
||||
$chart->addSeries( $series, 'number' );
|
||||
}
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', ( $activeTab === 'emails' ) ? 'Emails' : 'EmailClicks' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=emailstats&tab={$activeTab}" ) );
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -133,85 +72,6 @@ class _emailstats extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the results
|
||||
*
|
||||
* @param \IPS\Helpers\Chart\Callback $chart Chart object
|
||||
* @return array
|
||||
*/
|
||||
public function getResults( $chart )
|
||||
{
|
||||
$activeTab = $this->_getActiveTab();
|
||||
|
||||
$where = array( array( "time>?", 0 ) );
|
||||
|
||||
switch( $activeTab )
|
||||
{
|
||||
case 'emails':
|
||||
$where[] = array( 'type=?', 'emails_sent' );
|
||||
break;
|
||||
|
||||
case 'clicks':
|
||||
$where[] = array( 'type=?', 'email_clicks' );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $chart->start )
|
||||
{
|
||||
$where[] = array( "value_4>=?", $chart->start->format('Y-m-d') );
|
||||
}
|
||||
if ( $chart->end )
|
||||
{
|
||||
$where[] = array( "value_4<=?", $chart->end->format('Y-m-d') );
|
||||
}
|
||||
|
||||
$results = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_statistics', $where, 'value_4 ASC' ) as $row )
|
||||
{
|
||||
/* We need to use month/days NOT prefixed with '0' - i.e. 2019-2-12 instead of 2019-02-12 - to match the chart helper */
|
||||
$_date = new \IPS\DateTime( $row['value_4'] );
|
||||
|
||||
switch( $chart->timescale )
|
||||
{
|
||||
case 'daily':
|
||||
$_date = $_date->format( 'Y-n-j' );
|
||||
break;
|
||||
|
||||
case 'weekly':
|
||||
$_date = $_date->format( 'o-W' );
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$_date = $_date->format( 'Y-n' );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if( !isset( $results[ $_date ] ) )
|
||||
{
|
||||
$results[ $_date ] = array( 'time' => $_date );
|
||||
|
||||
foreach( $this->_getEmailTypes() as $series )
|
||||
{
|
||||
$results[ $_date ][ $series ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$lang = $row['extra_data'];
|
||||
|
||||
try
|
||||
{
|
||||
$lang = \IPS\Member::loggedIn()->language()->get( 'emailstats__' . $row['extra_data'] );
|
||||
}
|
||||
catch( \UnderflowException $e ){}
|
||||
|
||||
$results[ $_date ][ $lang ] += (int) $row['value_1'];
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active tab
|
||||
*
|
||||
@@ -219,7 +79,8 @@ class _emailstats extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function _getActiveTab()
|
||||
{
|
||||
return ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $this->_getAvailableTabs() ) ) ? \IPS\Request::i()->tab : 'emails';
|
||||
\IPS\Request::i()->tab ??= 'emails';
|
||||
return ( array_key_exists( \IPS\Request::i()->tab, $this->_getAvailableTabs() ) ) ? \IPS\Request::i()->tab : 'emails';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,37 +95,4 @@ class _emailstats extends \IPS\Dispatcher\Controller
|
||||
'clicks' => 'stats_emailstats_clicks',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached email types
|
||||
*/
|
||||
protected $_emailTypes = NULL;
|
||||
|
||||
/**
|
||||
* Get all possible email types logged
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getEmailTypes()
|
||||
{
|
||||
if( $this->_emailTypes === NULL )
|
||||
{
|
||||
$this->_emailTypes = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'extra_data', 'core_statistics', array( 'type=?', 'emails_sent' ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_DISTINCT ) as $series )
|
||||
{
|
||||
$lang = $series;
|
||||
|
||||
try
|
||||
{
|
||||
$lang = \IPS\Member::loggedIn()->language()->get( 'emailstats__' . $series );
|
||||
}
|
||||
catch( \UnderflowException $e ){}
|
||||
|
||||
$this->_emailTypes[] = $lang;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique( $this->_emailTypes );
|
||||
}
|
||||
}
|
||||
@@ -58,134 +58,100 @@ class _keywords extends \IPS\Dispatcher\Controller
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=keywords&do=settings' ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('settings') )
|
||||
);
|
||||
|
||||
/* Determine minimum date */
|
||||
$minimumDate = NULL;
|
||||
|
||||
if( \IPS\Settings::i()->stats_keywords_prune )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_keywords_prune . 'D' ) );
|
||||
}
|
||||
|
||||
/* Draw a chart */
|
||||
$options = json_decode( \IPS\Settings::i()->stats_keywords, true );
|
||||
|
||||
if( !\is_array( $options ) )
|
||||
{
|
||||
$options = array();
|
||||
}
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Database(
|
||||
\IPS\Http\Url::internal( 'app=core&module=activitystats&controller=keywords' ),
|
||||
'core_statistics',
|
||||
'time',
|
||||
'',
|
||||
array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde', '#b09be4', '#eec766', '#9fc973', '#e291bf', '#55c1a6', '#5fb9da' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
),
|
||||
'LineChart',
|
||||
'daily',
|
||||
array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P90D' ) ), 'end' => \IPS\DateTime::ts( time() ) ),
|
||||
array(),
|
||||
'',
|
||||
$minimumDate
|
||||
);
|
||||
$chart->where = array( array( 'type=?', 'keyword' ) );
|
||||
$chart->groupBy = 'value_4';
|
||||
|
||||
if ( \is_array( $options ) )
|
||||
{
|
||||
foreach( $options as $k => $v )
|
||||
{
|
||||
$chart->addSeries( $v, 'number', 'COUNT(*)' );
|
||||
}
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('keyword_usage_chart');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
|
||||
if( \IPS\Request::i()->noheader AND \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_statistics', \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=keywords' ), array( array( 'type=?', 'keyword' ) ) );
|
||||
$table->langPrefix = 'keywordstats_';
|
||||
$table->quickSearch = 'value_4';
|
||||
|
||||
/* Columns we need */
|
||||
$table->include = array( 'value_4', 'extra_data', 'author', 'time' );
|
||||
$table->mainColumn = 'value_4';
|
||||
$table->noSort = array( 'extra_data' );
|
||||
|
||||
$table->sortBy = $table->sortBy ?: 'time';
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
|
||||
/* Custom parsers */
|
||||
$table->parsers = array(
|
||||
'time' => function( $val, $row )
|
||||
{
|
||||
return \IPS\DateTime::ts( $val )->localeDate();
|
||||
},
|
||||
'author' => function( $val, $row )
|
||||
{
|
||||
$data = json_decode( $row['extra_data'], TRUE );
|
||||
|
||||
try
|
||||
{
|
||||
$class = $data['class'];
|
||||
|
||||
/* Check that the class exists */
|
||||
if( !class_exists( $class ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
$item = $class::load( $data['id'] );
|
||||
|
||||
return $item->author()->link();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'unknown' );
|
||||
}
|
||||
},
|
||||
'extra_data' => function( $val, $row )
|
||||
{
|
||||
$data = json_decode( $val, TRUE );
|
||||
|
||||
try
|
||||
{
|
||||
$class = $data['class'];
|
||||
|
||||
/* Check that the class exists */
|
||||
if( !class_exists( $class ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
$item = $class::load( $data['id'] );
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, ( $item instanceof \IPS\Content\Comment ) ? $item->item()->mapped('title') : $item->mapped('title'), TRUE );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'content_deleted' );
|
||||
}
|
||||
},
|
||||
$tabs = array(
|
||||
'time' => 'keywords_usage_over_time',
|
||||
'list' => 'keywords_usage_list',
|
||||
);
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_keywords');
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $table, TRUE, 'ipsPad ipsSpacer_top' );
|
||||
\IPS\Request::i()->tab ??= 'time';
|
||||
$activeTab = ( array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'time';
|
||||
|
||||
if ( $activeTab === 'time' )
|
||||
{
|
||||
$output = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Keywords' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=keywords&tab=time" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_statistics', \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=keywords&tab=list' ), array( array( 'type=?', 'keyword' ) ) );
|
||||
$table->langPrefix = 'keywordstats_';
|
||||
$table->quickSearch = 'value_4';
|
||||
|
||||
/* Columns we need */
|
||||
$table->include = array( 'value_4', 'extra_data', 'author', 'time' );
|
||||
$table->mainColumn = 'value_4';
|
||||
$table->noSort = array( 'extra_data' );
|
||||
|
||||
$table->sortBy = $table->sortBy ?: 'time';
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
|
||||
/* Custom parsers */
|
||||
$table->parsers = array(
|
||||
'time' => function( $val, $row )
|
||||
{
|
||||
return \IPS\DateTime::ts( $val )->localeDate();
|
||||
},
|
||||
'author' => function( $val, $row )
|
||||
{
|
||||
$data = json_decode( $row['extra_data'], TRUE );
|
||||
|
||||
try
|
||||
{
|
||||
$class = $data['class'];
|
||||
|
||||
/* Check that the class exists */
|
||||
if( !class_exists( $class ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
$item = $class::load( $data['id'] );
|
||||
|
||||
return $item->author()->link();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'unknown' );
|
||||
}
|
||||
},
|
||||
'extra_data' => function( $val, $row )
|
||||
{
|
||||
$data = json_decode( $val, TRUE );
|
||||
|
||||
try
|
||||
{
|
||||
$class = $data['class'];
|
||||
|
||||
/* Check that the class exists */
|
||||
if( !class_exists( $class ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
$item = $class::load( $data['id'] );
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, ( $item instanceof \IPS\Content\Comment ) ? $item->item()->mapped('title') : $item->mapped('title'), TRUE );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'content_deleted' );
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/* Display */
|
||||
$output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $table, TRUE, 'ipsPad ipsSpacer_top' );
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->output = (string) $output;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_keywords');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, (string) $output, \IPS\Http\Url::internal( "app=core&module=activitystats&controller=keywords" ), 'tab', '', 'ipsPad' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,4 +177,28 @@ class _keywords extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('settings');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'settings', $form, FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function rebuild()
|
||||
{
|
||||
if ( !\IPS\Settings::i()->stats_keywords )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_keywords_to_rebuild', '2C433/1', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
\IPS\Db::i()->delete( 'core_statistics', array( 'type=?', 'keyword' ) );
|
||||
foreach( \IPS\Content::routedClasses() AS $class )
|
||||
{
|
||||
\IPS\Task::queue( 'core', 'RebuildKeywords', array( 'class' => $class ) );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__statskeywords_rebuilt' );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=keywords' ), 'saved' );
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,8 @@ class _overview extends \IPS\core\modules\admin\stats\overview
|
||||
|
||||
if( isset( \IPS\Request::i()->cookie['overviewExcludedApps'] ) )
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
$excludedApps = json_decode( \IPS\Request::i()->cookie['overviewExcludedApps'] );
|
||||
|
||||
if( !\is_array( $excludedApps ) )
|
||||
|
||||
@@ -57,45 +57,12 @@ class _reactions extends \IPS\Dispatcher\Controller
|
||||
'givers' => 'stats_reactions_top_givers',
|
||||
'getters' => 'stats_reactions_top_receivers',
|
||||
);
|
||||
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'type';
|
||||
\IPS\Request::i()->tab ??= 'type';
|
||||
$activeTab = ( array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'type';
|
||||
|
||||
if ( $activeTab === 'type' OR $activeTab === 'app' )
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=reactions&tab=" . $activeTab ), 'core_reputation_index', 'rep_date', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde', '#b09be4', '#eec766', '#9fc973', '#e291bf', '#55c1a6', '#5fb9da' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
),
|
||||
'PieChart',
|
||||
'monthly',
|
||||
array( 'start' => 0, 'end' => 0 ),
|
||||
array(),
|
||||
$activeTab
|
||||
);
|
||||
|
||||
if ( $activeTab === 'type' )
|
||||
{
|
||||
$chart->groupBy = 'reaction';
|
||||
|
||||
foreach( \IPS\Content\Reaction::roots() as $reaction )
|
||||
{
|
||||
$chart->addSeries( $reaction->_title, 'number', 'COUNT(*)', TRUE, $reaction->id );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$chart->groupBy = 'app';
|
||||
|
||||
foreach( \IPS\Application::roots() as $app )
|
||||
{
|
||||
$chart->addSeries( $app->_title, 'number', 'COUNT(*)', TRUE, $app->directory );
|
||||
}
|
||||
}
|
||||
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart', 'PieChart' );
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', ( $activeTab === 'type' ) ? 'Reactions' : 'ReactionsApp' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=reactions&tab=" . $activeTab ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -41,19 +41,7 @@ class _reports extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=reports' ), 'core_rc_reports', 'date_reported', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
) );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_reports'), 'number', 'COUNT(*)', FALSE );
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_reports_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Reports' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=reports" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_reports');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _search extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Default limit to number of graphed results
|
||||
*/
|
||||
protected $defaultLimit = 25;
|
||||
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
@@ -69,53 +64,8 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
'title' => 'searchstats_log',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=activitystats&controller=search&do=log' ),
|
||||
);
|
||||
|
||||
/* Determine minimum date */
|
||||
$minimumDate = NULL;
|
||||
|
||||
if( \IPS\Settings::i()->stats_search_prune )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_search_prune . 'D' ) );
|
||||
}
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Database(
|
||||
\IPS\Http\Url::internal( 'app=core&module=activitystats&controller=search' ),
|
||||
'core_statistics',
|
||||
'time',
|
||||
'',
|
||||
array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde', '#b09be4', '#eec766', '#9fc973', '#e291bf', '#55c1a6', '#5fb9da' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4,
|
||||
'limitSearch' => 'stats_search_term_menu',
|
||||
),
|
||||
'LineChart',
|
||||
'daily',
|
||||
array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P90D' ) ), 'end' => \IPS\DateTime::ts( time() ) ),
|
||||
array(),
|
||||
'',
|
||||
$minimumDate
|
||||
);
|
||||
$chart->where = array( array( 'type=?', 'search' ) );
|
||||
$chart->groupBy = 'value_4';
|
||||
|
||||
$terms = [];
|
||||
foreach( $this->getTerms( $chart->searchTerm ) as $v )
|
||||
{
|
||||
$terms[] = $v;
|
||||
$chart->addSeries( $v, 'number', 'COUNT(*)', FALSE );
|
||||
}
|
||||
|
||||
if ( \count( $terms ) )
|
||||
{
|
||||
$chart->where[] = [ \IPS\Db::i()->in( 'value_4', $terms ) ];
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('search_stats_chart');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Search' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=search" ) );
|
||||
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
|
||||
@@ -128,39 +78,6 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_search');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached top search terms
|
||||
*/
|
||||
protected $_topSearchTerms = array();
|
||||
|
||||
/**
|
||||
* Get the top search terms
|
||||
*
|
||||
* @param string|null $term Term we searched for
|
||||
* @return array
|
||||
*/
|
||||
public function getTerms( $term=NULL )
|
||||
{
|
||||
if( !isset( $this->_topSearchTerms[ $term ] ) )
|
||||
{
|
||||
$this->_topSearchTerms[ $term ] = array();
|
||||
|
||||
$where = array( array( 'type=?', 'search' ) );
|
||||
|
||||
if( $term !== NULL )
|
||||
{
|
||||
$where[] = \IPS\Db::i()->like( 'value_4', $term, TRUE, TRUE, TRUE );
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'SQL_BIG_RESULT value_4, COUNT(*) as total', 'core_statistics', $where, 'total DESC', $this->defaultLimit, 'value_4' ) as $searchedValue )
|
||||
{
|
||||
$this->_topSearchTerms[ $term ][] = $searchedValue['value_4'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_topSearchTerms[ $term ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune Settings
|
||||
*
|
||||
|
||||
@@ -50,39 +50,7 @@ class _tags extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=tags" ), 'core_tags', 'tag_added', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
),
|
||||
'AreaChart',
|
||||
'daily',
|
||||
array( 'start' => \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) ), 'end' => 0 )
|
||||
);
|
||||
$chart->groupBy = 'tag_text';
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart', 'PieChart' );
|
||||
|
||||
$where = $chart->where;
|
||||
$where[] = array( "tag_added>?", 0 );
|
||||
if ( $chart->start )
|
||||
{
|
||||
$where[] = array( "tag_added>?", $chart->start->getTimestamp() );
|
||||
}
|
||||
if ( $chart->end )
|
||||
{
|
||||
$where[] = array( "tag_added<?", $chart->end->getTimestamp() );
|
||||
}
|
||||
|
||||
/* Only get visible tags */
|
||||
$where[] = array( 'tag_aai_lookup IN(?)', \IPS\Db::i()->select( 'tag_perm_aai_lookup', 'core_tags_perms', [ 'tag_perm_visible=1' ] ) );
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'tag_text', 'core_tags', $where, NULL, NULL, array( 'tag_text' ) ) as $tag )
|
||||
{
|
||||
$chart->addSeries( $tag, 'number', 'COUNT(*)', TRUE, $tag );
|
||||
}
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Tags' )->getChart( \IPS\Http\Url::internal( "app=core&module=activitystats&controller=tags" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_activitystats_tags');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ class _api extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
public function __call( $method, $args )
|
||||
{
|
||||
\IPS\Output::i()->responsive = FALSE;
|
||||
|
||||
/* Check htaccess is correct */
|
||||
if ( \IPS\Settings::i()->use_friendly_urls and \IPS\Settings::i()->htaccess_mod_rewrite OR \IPS\Request::i()->fromZapier )
|
||||
{
|
||||
|
||||
@@ -60,18 +60,20 @@ class _applications extends \IPS\Node\Controller
|
||||
{
|
||||
if( \IPS\IPS::canManageResources() )
|
||||
{
|
||||
if ( \IPS\IPS::checkThirdParty() )
|
||||
foreach( \IPS\Application::applications() as $app )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('forms')->blurb( 'applications_blurb' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('forms')->blurb('applications_blurb_no_custom');
|
||||
if( $app->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('marketplace')->removalBanner(FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('forms')->blurb( 'applications_blurb' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('forms')->blurb( 'applications_blurb_no_upload' );
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('forms')->blurb( 'applications_blurb_no_upload' );
|
||||
}
|
||||
}
|
||||
parent::manage();
|
||||
@@ -154,7 +156,7 @@ class _applications extends \IPS\Node\Controller
|
||||
function( $key, $root=FALSE ) use ( $uninstalled, $baseUrl )
|
||||
{
|
||||
$buttons = array();
|
||||
if( \IPS\IPS::canManageResources() AND \IPS\IPS::checkThirdParty() )
|
||||
if( \IPS\IPS::canManageResources() )
|
||||
{
|
||||
$buttons = array(
|
||||
'add' => array(
|
||||
@@ -212,7 +214,7 @@ class _applications extends \IPS\Node\Controller
|
||||
foreach ( $legacyApps as $k => $app )
|
||||
{
|
||||
$buttons = array();
|
||||
if( \IPS\IPS::canManageResources() AND \IPS\IPS::checkThirdParty() )
|
||||
if( \IPS\IPS::canManageResources() )
|
||||
{
|
||||
$buttons['upgrade'] = array(
|
||||
'icon' => 'upload',
|
||||
@@ -241,7 +243,7 @@ class _applications extends \IPS\Node\Controller
|
||||
function( $key, $root=FALSE ) use ( $legacyApps, $baseUrl )
|
||||
{
|
||||
$buttons = array();
|
||||
if( \IPS\IPS::canManageResources() AND \IPS\IPS::checkThirdParty() )
|
||||
if( \IPS\IPS::canManageResources() )
|
||||
{
|
||||
$buttons['upgrade'] = array(
|
||||
'icon' => 'upload',
|
||||
@@ -610,11 +612,11 @@ class _applications extends \IPS\Node\Controller
|
||||
{
|
||||
foreach ( \IPS\Application::applications() as $application )
|
||||
{
|
||||
/* Skip building Marketplace applications */
|
||||
if( $application->marketplace_id )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Skip building defined apps */
|
||||
if( \in_array( $application->directory, \IPS\DEV_SKIP_BUILD_APPS ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $values['developer_build_type'] === 'new' )
|
||||
{
|
||||
@@ -727,12 +729,6 @@ class _applications extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'not_in_dev', '2C133/10', 403, '' );
|
||||
}
|
||||
|
||||
/* Don't allow downloads of Marketplace resources */
|
||||
if( $application->marketplace_id )
|
||||
{
|
||||
// \IPS\Output::i()->error( 'application_cannot_build_marketplace', '2C133/Y', 403, '' );
|
||||
}
|
||||
|
||||
$form = $this->_buildForm( $application->directory, TRUE );
|
||||
if ( $values = $form->values() )
|
||||
@@ -778,6 +774,19 @@ class _applications extends \IPS\Node\Controller
|
||||
\IPS\Output::i()->output = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Enabled/Disable
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function enableToggle()
|
||||
{
|
||||
parent::enableToggle();
|
||||
|
||||
/* update the essential cookie name list */
|
||||
unset( \IPS\Data\Store::i()->essentialCookieNames );
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade an application that is currently installed. After importing a PHAR the user is redirected to this method.
|
||||
*
|
||||
@@ -1041,11 +1050,9 @@ class _applications extends \IPS\Node\Controller
|
||||
/* Return null to indicate we are done */
|
||||
if( $laststep === NULL )
|
||||
{
|
||||
if( \IPS\Request::i()->marketplace AND !\IPS\Application::load( $data['key'] )->marketplace_id )
|
||||
{
|
||||
\IPS\Application::load( $data['key'] )->marketplace_id = (int) \IPS\Request::i()->marketplace;
|
||||
\IPS\Application::load( $data['key'] )->save();
|
||||
}
|
||||
\IPS\Application::load( $data['key'] )->marketplace_id = \IPS\Request::i()->marketplace ? (int) \IPS\Request::i()->marketplace : NULL;
|
||||
\IPS\Application::load( $data['key'] )->save();
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__application_updated', array( \IPS\Application::load( $data['key'] )->titleForLog() => FALSE, \IPS\Application::load( $data['key'] )->version => TRUE ) );
|
||||
|
||||
return NULL;
|
||||
@@ -1300,11 +1307,8 @@ class _applications extends \IPS\Node\Controller
|
||||
/* Return null to indicate we are done */
|
||||
if( $laststep === NULL )
|
||||
{
|
||||
if( \IPS\Request::i()->marketplace )
|
||||
{
|
||||
\IPS\Application::load( $data['key'] )->marketplace_id = (int) \IPS\Request::i()->marketplace;
|
||||
\IPS\Application::load( $data['key'] )->save();
|
||||
}
|
||||
\IPS\Application::load( $data['key'] )->marketplace_id = \IPS\Request::i()->marketplace ? (int) \IPS\Request::i()->marketplace : NULL;
|
||||
\IPS\Application::load( $data['key'] )->save();
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__application_installed', array( "__app_" . $data['key'] => TRUE ) );
|
||||
|
||||
@@ -1563,11 +1567,6 @@ class _applications extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_phar_extension', '1C133/P', 403, '' );
|
||||
}
|
||||
|
||||
if ( !\IPS\IPS::checkThirdParty() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'cic_3rdparty_unavailable', '2C133/Z', 403, '' );
|
||||
}
|
||||
|
||||
$_type = 'install';
|
||||
|
||||
@@ -1619,16 +1618,14 @@ class _applications extends \IPS\Node\Controller
|
||||
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( "app_upload_designersmode", FALSE, array( 'sprintf' => \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=designersmode' ) ) ), '2C133/O', 403, '' );
|
||||
}
|
||||
|
||||
/* Check Marketplace Status? */
|
||||
if( $app->marketplace_id )
|
||||
{
|
||||
// \IPS\Output::i()->error( 'app_upload_marketplace_only', '2C133/X', 403, '' );
|
||||
}
|
||||
|
||||
$_type = 'upgrade';
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'form', 'install' );
|
||||
if( $_type == 'upgrade' AND $app->marketplace_id )
|
||||
{
|
||||
$form->addMessage( 'marketplace_resource_manual_upgrade', 'ipsMessage ipsMessage_info' );
|
||||
}
|
||||
$form->addMessage('applications_manual_install_warning');
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'application_file', NULL, TRUE, array( 'allowedFileTypes' => array( 'tar' ), 'temporary' => TRUE ) ) );
|
||||
|
||||
|
||||
@@ -130,24 +130,20 @@ class _developer extends \IPS\Dispatcher\Controller
|
||||
/* Display */
|
||||
if ( $activeTabContents )
|
||||
{
|
||||
/* Add the build and download button */
|
||||
if( !$this->application->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge(\IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_system.js', 'core', 'admin'));
|
||||
\IPS\Output::i()->sidebar['actions']['build'] = array(
|
||||
'icon' => 'download',
|
||||
'title' => 'download',
|
||||
'link' => \IPS\Http\Url::internal("app=core&module=applications&controller=applications&appKey={$this->application->directory}&do=download"),
|
||||
'data' => array(
|
||||
'controller' => 'system.buildApp',
|
||||
'downloadURL' => \IPS\Http\Url::internal("app=core&module=applications&controller=applications&appKey={$this->application->directory}&do=download&type=download"),
|
||||
'buildURL' => \IPS\Http\Url::internal("app=core&module=applications&controller=applications&appKey={$this->application->directory}&do=download&type=build"),
|
||||
)
|
||||
);
|
||||
}
|
||||
\IPS\Output::i()->jsFiles = array_merge(\IPS\Output::i()->jsFiles, \IPS\Output::i()->js('admin_system.js', 'core', 'admin'));
|
||||
\IPS\Output::i()->sidebar['actions']['build'] = array(
|
||||
'icon' => 'download',
|
||||
'title' => 'download',
|
||||
'link' => \IPS\Http\Url::internal("app=core&module=applications&controller=applications&appKey={$this->application->directory}&do=download"),
|
||||
'data' => array(
|
||||
'controller' => 'system.buildApp',
|
||||
'downloadURL' => \IPS\Http\Url::internal("app=core&module=applications&controller=applications&appKey={$this->application->directory}&do=download&type=download"),
|
||||
'buildURL' => \IPS\Http\Url::internal("app=core&module=applications&controller=applications&appKey={$this->application->directory}&do=download&type=build"),
|
||||
)
|
||||
);
|
||||
|
||||
\IPS\Output::i()->title = $this->application->_title;
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $this->activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}" ) );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $this->activeTab, $activeTabContents,\IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2859,9 +2855,12 @@ class _developer extends \IPS\Dispatcher\Controller
|
||||
protected function removeExtension()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
unlink( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/extensions/" . \IPS\Request::i()->ext . "/" . \IPS\Request::i()->file . ".php" );
|
||||
|
||||
|
||||
if( is_file( \IPS\ROOT_PATH."/applications/{$this->application->directory}/extensions/".\IPS\Request::i()->ext.'/'.\IPS\Request::i()->file.'.php'))
|
||||
{
|
||||
unlink( \IPS\ROOT_PATH."/applications/{$this->application->directory}/extensions/".\IPS\Request::i()->ext.'/'.\IPS\Request::i()->file.'.php' );
|
||||
}
|
||||
|
||||
$this->_writeJson( \IPS\ROOT_PATH . "/applications/{$this->application->directory}/data/extensions.json", $this->application->buildExtensionsJson() );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=applications&controller=developer&appKey={$this->application->directory}&tab=extensions" ), 'deleted' );
|
||||
}
|
||||
|
||||
@@ -74,14 +74,16 @@ class _plugins extends \IPS\Node\Controller
|
||||
|
||||
if ( !\IPS\Request::i()->isAjax() AND \IPS\IPS::canManageResources() )
|
||||
{
|
||||
if ( \IPS\IPS::checkThirdParty() )
|
||||
foreach( \IPS\Plugin::plugins() as $app )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('forms')->blurb( 'plugins_blurb' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('forms')->blurb('plugins_blurb_no_custom');
|
||||
if( $app->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('marketplace')->removalBanner(FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('forms')->blurb( 'plugins_blurb' );
|
||||
}
|
||||
|
||||
parent::manage();
|
||||
@@ -202,11 +204,6 @@ class _plugins extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'plugin_file_not_write', '4C145/N', 403, '' );
|
||||
}
|
||||
|
||||
if ( \IPS\CIC AND ! \IPS\IPS::checkThirdParty() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'cic_3rdparty_unavailable', '2C145/S', 403, '' );
|
||||
}
|
||||
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form( NULL, 'install' );
|
||||
@@ -214,9 +211,9 @@ class _plugins extends \IPS\Node\Controller
|
||||
{
|
||||
$form->hiddenValues['id'] = \IPS\Request::i()->id;
|
||||
|
||||
if( \IPS\Plugin::load( \IPS\Request::i()->id )->marketplace_id )
|
||||
if( \IPS\Plugin::load( (int) \IPS\Request::i()->id,'plugin_id')->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->error( 'app_upload_marketplace_only', '2C145/P', 403, '' );
|
||||
$form->addMessage( 'marketplace_resource_manual_upgrade', 'ipsMessage ipsMessage_info' );
|
||||
}
|
||||
}
|
||||
$form->addMessage('plugins_manual_install_warning');
|
||||
@@ -1191,10 +1188,7 @@ class _plugins extends \IPS\Node\Controller
|
||||
\IPS\Session::i()->log( 'acplog__plugin_installed', array( $plugin->name => FALSE ) );
|
||||
|
||||
/* Set Marketplace ID. */
|
||||
if( \IPS\Request::i()->marketplace )
|
||||
{
|
||||
$plugin->marketplace_id = (int) \IPS\Request::i()->marketplace;
|
||||
}
|
||||
$plugin->marketplace_id = \IPS\Request::i()->marketplace ? (int) \IPS\Request::i()->marketplace : NULL;
|
||||
|
||||
/* Re-enable the plugin */
|
||||
$plugin->enabled = TRUE;
|
||||
@@ -1340,16 +1334,13 @@ class _plugins extends \IPS\Node\Controller
|
||||
if ( $activeTabContents )
|
||||
{
|
||||
/* Add Download Button */
|
||||
if( !$plugin->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions'] = array(
|
||||
'download' => array(
|
||||
'icon' => 'download',
|
||||
'title' => 'download',
|
||||
'link' => \IPS\Http\Url::internal("app=core&module=applications&controller=plugins&do=download&id={$plugin->id}")->csrf(),
|
||||
)
|
||||
);
|
||||
}
|
||||
\IPS\Output::i()->sidebar['actions'] = array(
|
||||
'download' => array(
|
||||
'icon' => 'download',
|
||||
'title' => 'download',
|
||||
'link' => \IPS\Http\Url::internal("app=core&module=applications&controller=plugins&do=download&id={$plugin->id}")->csrf(),
|
||||
)
|
||||
);
|
||||
|
||||
\IPS\Output::i()->title = $plugin->name;
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global' )->tabs( $tabs, $activeTab, $activeTabContents, \IPS\Http\Url::internal( "app=core&module=applications&controller=plugins&do=developer&id={$plugin->id}" ) );
|
||||
@@ -1874,12 +1865,6 @@ class _plugins extends \IPS\Node\Controller
|
||||
\IPS\Output::i()->error( 'node_error', '2C145/B', 404, '' );
|
||||
}
|
||||
|
||||
/* Don't allow downloads of Marketplace resources */
|
||||
if( $plugin->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->error( 'plugin_cannot_build_marketplace', '2C145/Q', 403, '' );
|
||||
}
|
||||
|
||||
/* Init */
|
||||
$xml = \IPS\Xml\SimpleXML::create('plugin');
|
||||
$xml->addAttribute( 'name', $plugin->name );
|
||||
|
||||
@@ -231,13 +231,34 @@ class _clubs extends \IPS\Dispatcher\Controller
|
||||
/* Settings */
|
||||
if ( $activeTab === 'settings' )
|
||||
{
|
||||
if ( $form = $club->form( TRUE ) )
|
||||
$form = $club->form( TRUE );
|
||||
|
||||
if( $values = $form->values() )
|
||||
{
|
||||
$activeTabContents = (string) $form;
|
||||
$club->skipCloneDuplication = TRUE;
|
||||
$old = clone $club;
|
||||
|
||||
$club->processForm( $values, TRUE, FALSE, NULL );
|
||||
|
||||
$changes = $club::renewalChanges( $old, $club );
|
||||
|
||||
if ( !empty( $changes ) )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->decision( 'product_change_blurb', array(
|
||||
'product_change_blurb_existing' => \IPS\Http\Url::internal( "app=core&module=clubs&controller=clubs&do=updateExisting&id={$club->id}" )->setQueryString( 'changes', json_encode( $changes ) )->csrf(),
|
||||
'product_change_blurb_new' => \IPS\Http\Url::internal( "app=core&module=clubs&controller=clubs" ),
|
||||
) );
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal("app=core&module=clubs&controller=clubs"), "saved" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal("app=core&module=clubs&controller=clubs"), "saved" );
|
||||
$activeTabContents = (string) $form;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,4 +662,29 @@ class _clubs extends \IPS\Dispatcher\Controller
|
||||
$node->description
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Existing Purchases
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateExisting()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
try
|
||||
{
|
||||
$club = \IPS\Member\Club::load( \IPS\Request::i()->id );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '3C352/8', 403, '' );
|
||||
}
|
||||
|
||||
$changes = json_decode( \IPS\Request::i()->changes, TRUE );
|
||||
|
||||
\IPS\Task::queue( 'core', 'UpdateClubRenewals', array( 'changes' => $changes, 'club' => $club->id ), 5 );
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=clubs&controller=clubs" ), 'saved' );
|
||||
}
|
||||
}
|
||||
@@ -45,9 +45,11 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$fields = array( 'clubs_default_sort', 'clubs_header', 'clubs_locations', 'clubs_modperms', 'clubs_require_approval', 'form_header_club_display_settings', 'form_header_club_moderation', 'clubs_default_view', 'clubs_allow_view_change', 'club_nodes_in_apps', 'form_header_clubs_paid_settings', 'clubs_paid_on', '_allow_club_moderators', 'club_max_cover' );
|
||||
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->addHeader( 'club_settings' );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_enabled_setting', \IPS\Settings::i()->clubs, FALSE, array( 'togglesOn' => array( 'clubs_default_sort', 'clubs_header', 'clubs_locations', 'clubs_modperms', 'clubs_require_approval', 'form_header_club_display_settings', 'form_header_club_moderation', 'clubs_default_view', 'clubs_allow_view_change', 'club_nodes_in_apps', 'form_header_clubs_paid_settings', 'clubs_paid_on', '_allow_club_moderators' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_enabled_setting', \IPS\Settings::i()->clubs, FALSE, array( 'togglesOn' => $fields ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_require_approval', \IPS\Settings::i()->clubs_require_approval, FALSE, array(), NULL, NULL, NULL, 'clubs_require_approval' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'clubs_locations', \IPS\Settings::i()->clubs_locations, FALSE, array(), NULL, NULL, NULL, 'clubs_locations' ) );
|
||||
if ( \IPS\Application::appIsEnabled( 'nexus' ) )
|
||||
@@ -104,7 +106,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
'delete' => 'club_modperm_delete',
|
||||
'split_merge' => 'club_modperm_split_merge',
|
||||
) ), NULL, NULL, NULL, 'clubs_modperms' ) );
|
||||
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$values['clubs'] = $values['clubs_enabled_setting'];
|
||||
|
||||
@@ -83,7 +83,7 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
foreach ( $templateNames[$app] as $location => $items )
|
||||
{
|
||||
if ( $location === 'front' )
|
||||
if ( $location === 'front' or $location === 'global' )
|
||||
{
|
||||
foreach ( $templateNames[$app][$location] as $path => $items )
|
||||
{
|
||||
@@ -137,8 +137,8 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
else
|
||||
{
|
||||
$templateNames = $skinSet->getRawCss( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT );
|
||||
$templateBits = $skinSet->getRawCss( $t_app, 'front', NULL, \IPS\Theme::RETURN_ALL );
|
||||
$templateBit = ( ! empty( $t_name ) ) ? $templateBits[ $t_app ]['front'][ $t_group ][ $t_name ] : null;
|
||||
$templateBits = $skinSet->getRawCss( $t_app, ['global', 'front'], NULL, \IPS\Theme::RETURN_ALL );
|
||||
$templateBit = ( ! empty( $t_name ) ) ? $templateBits[ $t_app ][ $t_location ][ $t_group ][ $t_name ] : null;
|
||||
$templateBit['css_content'] = htmlentities( $templateBit['css_content'], ENT_DISALLOWED, 'UTF-8', TRUE );
|
||||
}
|
||||
|
||||
|
||||
@@ -54,63 +54,6 @@ class _icons extends \IPS\Dispatcher\Controller
|
||||
$shareLogos = \IPS\Settings::i()->icons_sharer_logo ? json_decode( \IPS\Settings::i()->icons_sharer_logo, true ) : array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_sharer_logo', \count( $shareLogos ) ? array_map( function( $val ) { return \IPS\File::get( 'core_Icons', $val ); }, $shareLogos ) : array(), FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons', 'multiple' => true ) ) );
|
||||
|
||||
/* Homescreen icons - we accept one upload and create the images we need */
|
||||
$homeScreen = json_decode( \IPS\Settings::i()->icons_homescreen, TRUE ) ?? array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_homescreen', ( isset( $homeScreen['original'] ) ) ? \IPS\File::get( 'core_Icons', $homeScreen['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
|
||||
|
||||
$homeScreenMaskable = json_decode( \IPS\Settings::i()->icons_homescreen_maskable, TRUE ) ?? array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_homescreen_maskable', ( isset( $homeScreenMaskable['original'] ) ) ? \IPS\File::get( 'core_Icons', $homeScreenMaskable['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons', 'allowedFileTypes' => ['png', 'webp' ] ) ) );
|
||||
|
||||
/* Apple startup screen logo - we accept one upload and create the images we need */
|
||||
$apple = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) ?? array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_apple_startup', ( isset( $apple['original'] ) ) ? \IPS\File::get( 'core_Icons', $apple['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
|
||||
|
||||
/* Safari pinned tabs icon and highlight color */
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_mask_icon', \IPS\Settings::i()->icons_mask_icon ? \IPS\File::get( 'core_Icons', \IPS\Settings::i()->icons_mask_icon ) : NULL, FALSE, array( 'allowedFileTypes' => array( 'svg' ), 'storageExtension' => 'core_Icons', 'obscure' => FALSE ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'icons_mask_color', \IPS\Settings::i()->icons_mask_color, FALSE ) );
|
||||
|
||||
/* And finally, additional manifest and livetile details */
|
||||
$manifestDetails = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'configure_manifest', \count( $manifestDetails ) > 0, FALSE, array(
|
||||
'togglesOn' => array( 'manifest_shortname', 'manifest_fullname', 'manifest_description', 'manifest_defaultapp', 'manifest_themecolor', 'manifest_bgcolor', 'manifest_display', 'manifest_custom_url_toggle' ),
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'manifest_shortname', ( isset( $manifestDetails['short_name'] ) ) ? $manifestDetails['short_name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_shortname' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'manifest_fullname', ( isset( $manifestDetails['name'] ) ) ? $manifestDetails['name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_fullname' ) );
|
||||
$form->add( new \IPS\Helpers\Form\TextArea( 'manifest_description', ( isset( $manifestDetails['description'] ) ) ? $manifestDetails['description'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_description' ) );
|
||||
|
||||
$formStartUrl = '';
|
||||
if( isset( $manifestDetails['start_url'] ) )
|
||||
{
|
||||
$formStartUrl = str_replace( 'index.php?/', '', \IPS\Http\Url\Friendly::fixComponentPath( $manifestDetails['start_url'] ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'manifest_custom_url_toggle', ( isset( $manifestDetails['start_url'] ) and empty( $formStartUrl ) ? FALSE : TRUE ), FALSE, array(
|
||||
'togglesOn' => array( 'manifest_short_url' ),
|
||||
), NULL, NULL, NULL, 'manifest_custom_url_toggle' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'manifest_short_url', $formStartUrl, FALSE, array(), function( $val )
|
||||
{
|
||||
if ( $val and \IPS\Request::i()->manifest_custom_url_toggle_checkbox )
|
||||
{
|
||||
if ( mb_substr( $val, -1 ) !== '/' )
|
||||
{
|
||||
$val .= '/';
|
||||
}
|
||||
|
||||
$response = \IPS\Http\Url::external( \IPS\Http\Url::baseUrl() . ( \IPS\Settings::i()->htaccess_mod_rewrite ? $val : 'index.php?/' . $val ) )->request( NULL, NULL, FALSE )->get();
|
||||
if ( $response->httpResponseCode != 200 and $response->httpResponseCode != 303 and ( \IPS\Settings::i()->site_online OR $response->httpResponseCode != 503 ) )
|
||||
{
|
||||
throw new \LogicException( 'pwa_start_url_incorrect' );
|
||||
}
|
||||
}
|
||||
}, \IPS\Http\Url::baseUrl() . ( !\IPS\Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ), NULL, 'manifest_short_url' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'manifest_themecolor', ( isset( $manifestDetails['theme_color'] ) ) ? $manifestDetails['theme_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_themecolor' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'manifest_bgcolor', ( isset( $manifestDetails['background_color'] ) ) ? $manifestDetails['background_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_bgcolor' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'manifest_display', ( isset( $manifestDetails['display'] ) ) ? $manifestDetails['display'] : 'standalone', FALSE, array( 'options' => array( 'fullscreen' => 'manifest_fullscreen', 'standalone' => 'manifest_standalone', 'minimal-ui' => 'manifest_minimalui', 'browser' => 'manifest_browser' ) ), NULL, NULL, NULL, 'manifest_display' ) );
|
||||
|
||||
/* We've submitted, check our values! */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
@@ -123,373 +66,20 @@ class _icons extends \IPS\Dispatcher\Controller
|
||||
$values['icons_sharer_logo'] = json_encode( array_map( function( $val ){ return (string) $val; }, $values['icons_sharer_logo'] ) );
|
||||
}
|
||||
|
||||
$path = \IPS\Http\Url::createFromString( \IPS\Http\Url::baseUrl() )->data[ \IPS\Http\Url::COMPONENT_PATH ];
|
||||
$startUrl = $path ?? '';
|
||||
|
||||
if ( $values['manifest_custom_url_toggle'] !== FALSE and ! empty( $values['manifest_short_url'] ) )
|
||||
{
|
||||
$startUrl = '/' . trim( $values['manifest_short_url'], '/' ) . '/';
|
||||
|
||||
if( !empty( $path ) )
|
||||
{
|
||||
$startUrl = '/' . trim( $path . ( !\IPS\Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ) . ltrim( $values['manifest_short_url'], '/' ), '/' ) . '/';
|
||||
}
|
||||
}
|
||||
|
||||
/* Homescreen icon is the hardest part, as we need to generate different sizes.. */
|
||||
$values = static::processApplicationIcon( $values, $homeScreen, $homeScreenMaskable );
|
||||
|
||||
/* The start screen requires more different sizes so we'll rebuild that after submit */
|
||||
$rebuildStartScreen = FALSE;
|
||||
|
||||
if( $values['icons_apple_startup'] AND ( !isset( $apple['original'] ) OR !$apple['original'] OR (string) $values['icons_apple_startup'] != $apple['original'] ) )
|
||||
{
|
||||
$rebuildStartScreen = TRUE;
|
||||
}
|
||||
|
||||
if( ( !isset( $manifestDetails['background_color'] ) AND $values['manifest_bgcolor'] ) OR ( isset( $manifestDetails['background_color'] ) AND !$values['manifest_bgcolor'] ) OR ( isset( $manifestDetails['background_color'] ) AND $values['manifest_bgcolor'] != $manifestDetails['background_color'] ) )
|
||||
{
|
||||
if( $values['icons_apple_startup'] )
|
||||
{
|
||||
$rebuildStartScreen = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
$values = static::processAppleStartupScreen( $values, $apple );
|
||||
|
||||
/* We need the string value of this uploaded file as well */
|
||||
$values['icons_mask_icon'] = (string) $values['icons_mask_icon'];
|
||||
|
||||
/* Finally, handle the manifest details */
|
||||
$values['manifest_details'] = array();
|
||||
|
||||
if( $values['configure_manifest'] )
|
||||
{
|
||||
$values['manifest_details']['short_name'] = $values['manifest_shortname'];
|
||||
$values['manifest_details']['start_url'] = $startUrl;
|
||||
$values['manifest_details']['name'] = $values['manifest_fullname'];
|
||||
$values['manifest_details']['description'] = $values['manifest_description'];
|
||||
$values['manifest_details']['theme_color'] = $values['manifest_themecolor'];
|
||||
$values['manifest_details']['background_color'] = $values['manifest_bgcolor'];
|
||||
$values['manifest_details']['display'] = $values['manifest_display'];
|
||||
}
|
||||
|
||||
unset( $values['configure_manifest'], $values['manifest_shortname'], $values['manifest_fullname'], $values['manifest_description'], $values['manifest_display'], $values['manifest_bgcolor'], $values['manifest_themecolor'], $values['manifest_custom_url_toggle'], $values['manifest_short_url'] );
|
||||
|
||||
$values['manifest_details'] = json_encode( $values['manifest_details'] );
|
||||
|
||||
/* Save the settings */
|
||||
$form->saveAsSettings( $values );
|
||||
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Clear manifest and ie browser data stores */
|
||||
unset( \IPS\Data\Store::i()->manifest, \IPS\Data\Store::i()->iebrowserconfig );
|
||||
|
||||
/* And log */
|
||||
\IPS\Session::i()->log( 'acplogs__icons_and_logos' );
|
||||
|
||||
/* And Redirect */
|
||||
if( $rebuildStartScreen === TRUE )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $this->url->setQueryString( 'do', 'buildStartupScreenImages' ), 'saved' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $this->url, 'saved' );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $this->url, 'saved' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_customization_icons');
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'menu__core_customization_icons', $form );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process application icon
|
||||
*
|
||||
* @param array $values Values from form submission
|
||||
* @param array $homeScreen Existing values, if any
|
||||
* @param array $homeScreenMaskable Existing values, if any
|
||||
* @return array
|
||||
*/
|
||||
public static function processApplicationIcon( $values, $homeScreen = array(), $homeScreenMaskable = array() )
|
||||
{
|
||||
if( ( isset( $values['icons_homescreen'] ) AND $values['icons_homescreen'] ) or ( isset( $values['icons_homescreen_maskable' ] ) AND $values['icons_homescreen_maskable'] ) )
|
||||
{
|
||||
foreach( [ 'icons_homescreen', 'icons_homescreen_maskable' ] as $type )
|
||||
{
|
||||
$setting = [];
|
||||
if( isset( $values[ $type ] ) AND $values[ $type ] )
|
||||
{
|
||||
$sizes = array(
|
||||
'android-chrome-36x36' => array(36, 36),
|
||||
'android-chrome-48x48' => array(48, 48),
|
||||
'android-chrome-72x72' => array(72, 72),
|
||||
'android-chrome-96x96' => array(96, 96),
|
||||
'android-chrome-144x144' => array(144, 144),
|
||||
'android-chrome-192x192' => array(192, 192),
|
||||
'android-chrome-256x256' => array(256, 256),
|
||||
'android-chrome-384x384' => array(384, 384),
|
||||
'android-chrome-512x512' => array(512, 512),
|
||||
'msapplication-square70x70logo' => array(128, 128),
|
||||
'msapplication-TileImage' => array(144, 144),
|
||||
'msapplication-square150x150logo' => array(270, 270),
|
||||
'msapplication-wide310x150logo' => array(558, 558),
|
||||
'msapplication-square310x310logo' => array(558, 270),
|
||||
'apple-touch-icon-57x57' => array(57, 57),
|
||||
'apple-touch-icon-60x60' => array(60, 60),
|
||||
'apple-touch-icon-72x72' => array(72, 72),
|
||||
'apple-touch-icon-76x76' => array(76, 76),
|
||||
'apple-touch-icon-114x114' => array(114, 114),
|
||||
'apple-touch-icon-120x120' => array(120, 120),
|
||||
'apple-touch-icon-144x144' => array(144, 144),
|
||||
'apple-touch-icon-152x152' => array(152, 152),
|
||||
'apple-touch-icon-180x180' => array(180, 180),
|
||||
);
|
||||
|
||||
$setting = array('original' => (string)$values[ $type ]);
|
||||
|
||||
foreach ( $sizes as $filename => $_sizes )
|
||||
{
|
||||
if ( $type == 'icons_homescreen_maskable' )
|
||||
{
|
||||
$filename .= "-masked";
|
||||
|
||||
if ( ! \mb_strstr( $filename, 'android-chrome' ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
$image = \IPS\Image::create( $values[ $type ]->contents() );
|
||||
|
||||
if ( $image::exifSupported() )
|
||||
{
|
||||
$image->setExifData( $values[ $type ]->contents() );
|
||||
}
|
||||
|
||||
$image->crop( $_sizes[0], $_sizes[1] );
|
||||
|
||||
$setting[$filename] = array(
|
||||
'url' => (string)\IPS\File::create( 'core_Icons', $filename . '.png', (string)$image, NULL, TRUE, NULL, FALSE ),
|
||||
'width' => $image->width,
|
||||
'height' => $image->height
|
||||
);
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$values[ $type ] = json_encode( $setting );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delete any images that may already exist */
|
||||
foreach( $homeScreen as $key => $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
foreach( $homeScreenMaskable as $key => $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
$values['icons_homescreen'] = '';
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Minimum padding on either side of startup image (in px)
|
||||
*/
|
||||
const MINIMUM_STARTUP_IMAGE_PADDING = 50;
|
||||
|
||||
/**
|
||||
* Process Apple startup screen images
|
||||
*
|
||||
* @param array $values Values from form submission
|
||||
* @param array $apple Existing values, if any
|
||||
* @return array
|
||||
*/
|
||||
public static function processAppleStartupScreen( $values, $apple = array() )
|
||||
{
|
||||
if( $values['icons_apple_startup'] )
|
||||
{
|
||||
$values['icons_apple_startup'] = json_encode( array( 'original' => (string) $values['icons_apple_startup'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delete any images that may already exist */
|
||||
foreach( $apple as $key => $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
$values['icons_apple_startup'] = '';
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Apple startup screen images
|
||||
*
|
||||
* @param array $values Values from form submission
|
||||
* @param array $apple Existing values, if any
|
||||
* @return array
|
||||
*/
|
||||
public function buildStartupScreenImages()
|
||||
{
|
||||
$self = $this;
|
||||
|
||||
$multiRedirect = new \IPS\Helpers\MultipleRedirect(
|
||||
$this->url->setQueryString('do', 'buildStartupScreenImages'),
|
||||
function( $data )
|
||||
{
|
||||
/* Get the necessary data */
|
||||
$manifestDetails = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
|
||||
$setting = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) ?? array();
|
||||
|
||||
if( isset( $setting['original'] ) )
|
||||
{
|
||||
$sizes = array(
|
||||
'apple-startup-1136x640' => array( 320, 568, 2, 'landscape' ),
|
||||
'apple-startup-2436x1125' => array( 375, 812, 3, 'landscape' ),
|
||||
'apple-startup-1792x828' => array( 414, 896, 2, 'landscape' ),
|
||||
'apple-startup-828x1792' => array( 414, 896, 2, 'portrait' ),
|
||||
'apple-startup-1334x750' => array( 375, 667, 2, 'landscape' ),
|
||||
'apple-startup-1242x2688' => array( 414, 896, 3, 'portrait' ),
|
||||
'apple-startup-2208x1242' => array( 414, 736, 3, 'landscape' ),
|
||||
'apple-startup-1125x2436' => array( 375, 812, 3, 'portrait' ),
|
||||
'apple-startup-1242x2208' => array( 414, 736, 3, 'portrait' ),
|
||||
'apple-startup-2732x2048' => array( 1024, 1366, 2, 'landscape' ),
|
||||
'apple-startup-2688x1242' => array( 414, 896, 3, 'landscape' ),
|
||||
'apple-startup-2224x1668' => array( 834, 1112, 2, 'landscape' ),
|
||||
'apple-startup-750x1334' => array( 375, 667, 2, 'portrait' ),
|
||||
'apple-startup-2048x2732' => array( 1024, 1366, 2, 'portrait' ),
|
||||
'apple-startup-2388x1668' => array( 834, 1194, 2, 'landscape' ),
|
||||
'apple-startup-1668x2224' => array( 834, 1112, 2, 'portrait' ),
|
||||
'apple-startup-640x1136' => array( 320, 568, 2, 'portrait' ),
|
||||
'apple-startup-1668x2388' => array( 834, 1194, 2, 'portrait' ),
|
||||
'apple-startup-2048x1536' => array( 768, 1024, 2, 'landscape' ),
|
||||
'apple-startup-1536x2048' => array( 768, 1024, 2, 'portrait' ),
|
||||
'apple-startup-2360x1640' => array( 1180, 820, 2, 'landscape' ),
|
||||
'apple-startup-1640x2360' => array( 1180, 820, 2, 'portrait' ),
|
||||
'apple-startup-2160x1620' => array( 1080, 810, 2, 'landscape' ),
|
||||
'apple-startup-1620x2160' => array( 1080, 810, 2, 'portrait' ),
|
||||
'apple-startup-2778x1284' => array( 428, 926, 3, 'landscape' ),
|
||||
'apple-startup-1284x2778' => array( 428, 926, 3, 'portrait' ),
|
||||
'apple-startup-2532x1170' => array( 390, 844, 3, 'landscape' ),
|
||||
'apple-startup-1170x2532' => array( 390, 844, 3, 'portrait' ),
|
||||
'apple-startup-2340x1080' => array( 360, 780, 3, 'landscape' ),
|
||||
'apple-startup-1080x2340' => array( 360, 780, 3, 'portrait' ),
|
||||
);
|
||||
|
||||
$file = \IPS\File::get( 'core_Icons', $setting['original'] );
|
||||
$originalContents = $file->contents();
|
||||
|
||||
$backgroundColor = ( isset( $manifestDetails['background_color'] ) ) ? str_replace( '#', '', $manifestDetails['background_color'] ) : 'FFFFFF';
|
||||
|
||||
$rgb = array();
|
||||
|
||||
if ( \strlen( $backgroundColor ) == 3 )
|
||||
{
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 0, 1 ) . \substr( $backgroundColor, 0, 1 ) ); // R
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 1, 1 ) . \substr( $backgroundColor, 1, 1 ) ); // G
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 2, 1 ) . \substr( $backgroundColor, 2, 1 ) ); // B
|
||||
}
|
||||
else
|
||||
{
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 0, 2 ) ); // R
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 2, 2 ) ); // G
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 4, 2 ) ); // B
|
||||
}
|
||||
|
||||
$did = 0;
|
||||
|
||||
foreach( $sizes as $filename => $_sizes )
|
||||
{
|
||||
$did++;
|
||||
|
||||
if( isset( $setting[ $filename ] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$width = ( $_sizes[3] == 'landscape' ) ? $_sizes[1] * $_sizes[2] : $_sizes[0] * $_sizes[2];
|
||||
$height = ( $_sizes[3] == 'portrait' ) ? $_sizes[1] * $_sizes[2] : $_sizes[0] * $_sizes[2];
|
||||
|
||||
$logoImage = \IPS\Image::create( $originalContents );
|
||||
$canvas = \IPS\Image::newImageCanvas( $width, $height, $rgb );
|
||||
|
||||
$logoImage->resizeToMax( $width - static::MINIMUM_STARTUP_IMAGE_PADDING, $height - static::MINIMUM_STARTUP_IMAGE_PADDING );
|
||||
|
||||
$xPos = ( $width - $logoImage->width ) / 2;
|
||||
$yPos = ( $height - $logoImage->height ) / 2;
|
||||
|
||||
$canvas->impose( $logoImage, $xPos, $yPos );
|
||||
|
||||
if( $canvas::exifSupported() )
|
||||
{
|
||||
$canvas->setExifData( $originalContents );
|
||||
}
|
||||
|
||||
$setting[ $filename ] = array(
|
||||
'url' => (string) \IPS\File::create( 'core_Icons', $filename . '.png', (string) $canvas, NULL, TRUE, NULL, FALSE ),
|
||||
'width' => $canvas->width,
|
||||
'height' => $canvas->height,
|
||||
'density' => $_sizes[2],
|
||||
'orientation' => $_sizes[3],
|
||||
);
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'apple-startup-image' );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Are we done? */
|
||||
if( $did == \count( $sizes ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'icons_apple_startup' => json_encode( $setting ) ) );
|
||||
}
|
||||
|
||||
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('build_start_images_title'), ( $did ) ? round( ( 100 / \count( $sizes ) * $did ), 2 ) : 0 );
|
||||
},
|
||||
function() use( $self )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $self->url, 'completed' );
|
||||
}
|
||||
);
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('build_start_images_title');
|
||||
\IPS\Output::i()->output = $multiRedirect;
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,18 @@ class _themes extends \IPS\Node\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
if ( !\IPS\Request::i()->isAjax() AND \IPS\IPS::canManageResources() )
|
||||
{
|
||||
foreach( \IPS\Theme::themes() as $app )
|
||||
{
|
||||
if( $app->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate('marketplace')->removalBanner(FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( \IPS\Theme::designersModeEnabled() and ! isset( \IPS\Request::i()->root ) )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack('theme_designer_mode_warning'), 'information', NULL, FALSE );
|
||||
@@ -1100,7 +1112,7 @@ class _themes extends \IPS\Node\Controller
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect(
|
||||
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key, 'id' => \IPS\Request::i()->id ) )->csrf(),
|
||||
\IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key, 'id' => \IPS\Request::i()->id, 'manual' => \IPS\Request::i()->manual ) )->csrf(),
|
||||
function( $data )
|
||||
{
|
||||
$set = \IPS\Theme::load( \IPS\Request::i()->id );
|
||||
@@ -1124,6 +1136,13 @@ class _themes extends \IPS\Node\Controller
|
||||
if ( !\is_array( $data ) )
|
||||
{
|
||||
$_SESSION['theme_import'] = array( 'css' => array(), 'isNewSet' => false );
|
||||
|
||||
/* Remove marketplace link */
|
||||
if( \IPS\Theme::load( \IPS\Request::i()->id )->marketplace_id AND \IPS\Request::i()->manual )
|
||||
{
|
||||
\IPS\Theme::load( \IPS\Request::i()->id )->marketplace_id = NULL;
|
||||
\IPS\Theme::load( \IPS\Request::i()->id )->save();
|
||||
}
|
||||
|
||||
/* Save snapshot */
|
||||
\IPS\Theme::load( \IPS\Request::i()->id )->saveHistorySnapshot();
|
||||
@@ -1859,11 +1878,6 @@ class _themes extends \IPS\Node\Controller
|
||||
|
||||
$themeSet = \IPS\Theme::load( $id );
|
||||
$apps = array();
|
||||
|
||||
if( $themeSet->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->error( 'app_upload_marketplace_only', '2C163/K', 403, '' );
|
||||
}
|
||||
|
||||
foreach( \IPS\Application::applications() as $key => $data )
|
||||
{
|
||||
@@ -1872,6 +1886,11 @@ class _themes extends \IPS\Node\Controller
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form( 'form', 'theme_set_import_button' );
|
||||
if( $themeSet->marketplace_id )
|
||||
{
|
||||
$form->addMessage( 'marketplace_resource_manual_upgrade', 'ipsMessage ipsMessage_info' );
|
||||
}
|
||||
$form->addMessage('themes_manual_install_warning');
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'core_theme_set_new_import', NULL, FALSE, array( 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ), NULL, NULL, NULL, 'core_theme_set_new_import' ) );
|
||||
|
||||
@@ -1882,7 +1901,7 @@ class _themes extends \IPS\Node\Controller
|
||||
move_uploaded_file( $values['core_theme_set_new_import'], $tempFile );
|
||||
|
||||
/* Initate a redirector */
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ), 'id' => \IPS\Request::i()->id) )->csrf() );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=customization&controller=themes&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ), 'id' => \IPS\Request::i()->id, 'manual' => 1 ) )->csrf() );
|
||||
}
|
||||
|
||||
/* Display */
|
||||
@@ -2610,6 +2629,12 @@ class _themes extends \IPS\Node\Controller
|
||||
|
||||
/* Extra template only variables */
|
||||
$save['attributes'] = \IPS\Request::i()->$attributesName;
|
||||
|
||||
/* This is likely a customization of a core CSS file which was allowed previously, but now is not. So let's inform the user it cannot be saved */
|
||||
if ( $save['app'] === 'core' and $save['location'] === 'global' )
|
||||
{
|
||||
\IPS\Output::i()->error( 'cant_save_global_css_changes_now_sorry', '3C163/Z', 500, '' );
|
||||
}
|
||||
|
||||
$newId = \IPS\Theme::load( $save['set_id'] )->saveCss( $save );
|
||||
}
|
||||
@@ -2992,26 +3017,23 @@ class _themes extends \IPS\Node\Controller
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
/* Test the syntax */
|
||||
$errors = [];
|
||||
foreach( [ 'header', 'footer', 'css' ] as $key )
|
||||
{
|
||||
/* Test the syntax */
|
||||
$errors = [];
|
||||
foreach( [ 'header', 'footer', 'css' ] as $key )
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Theme::checkTemplateSyntax( $values['theme_simple_' . $key ] );
|
||||
}
|
||||
catch( \LogicException $e )
|
||||
{
|
||||
$errors[] = \IPS\Member::loggedIn()->language()->addToStack( 'theme_error_in_template', NULL, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->get('theme_simple_' . $key . '_tab') ] ] );
|
||||
}
|
||||
\IPS\Theme::checkTemplateSyntax( $values['theme_simple_' . $key ] );
|
||||
}
|
||||
catch( \LogicException $e )
|
||||
{
|
||||
$errors[] = \IPS\Member::loggedIn()->language()->addToStack( 'theme_error_in_template', NULL, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->get('theme_simple_' . $key . '_tab') ] ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( \count( $errors ) )
|
||||
{
|
||||
\IPS\Output::i()->error( implode( ". ", $errors ), '3C163/I', 500, '' );
|
||||
}
|
||||
if ( \count( $errors ) )
|
||||
{
|
||||
\IPS\Output::i()->error( implode( ". ", $errors ), '3C163/I', 500, '' );
|
||||
}
|
||||
|
||||
$themeSet->custom_header = $values['theme_simple_header'];
|
||||
@@ -3144,7 +3166,7 @@ class _themes extends \IPS\Node\Controller
|
||||
{
|
||||
foreach ( $templateNames[$app] as $location => $items )
|
||||
{
|
||||
if ( $location === 'front' )
|
||||
if ( $location === 'front' or $location === 'global' )
|
||||
{
|
||||
foreach ( $templateNames[$app][$location] as $path => $items )
|
||||
{
|
||||
|
||||
@@ -84,6 +84,18 @@ class _languages extends \IPS\Node\Controller
|
||||
protected function manage()
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'flags.css', 'core', 'global' ) );
|
||||
|
||||
if ( !\IPS\Request::i()->isAjax() AND \IPS\IPS::canManageResources() )
|
||||
{
|
||||
foreach ( \IPS\Lang::languages() as $app )
|
||||
{
|
||||
if ( $app->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'marketplace' )->removalBanner( FALSE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'languages', 'lang_words' ) )
|
||||
{
|
||||
@@ -187,7 +199,6 @@ class _languages extends \IPS\Node\Controller
|
||||
{
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->addMessage('languages_manual_install_warning');
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'lang_upload', NULL, TRUE, array( 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ) ) );
|
||||
\IPS\Lang::localeField( $form );
|
||||
|
||||
@@ -380,6 +391,9 @@ class _languages extends \IPS\Node\Controller
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Update the essential cookie name list */
|
||||
unset( \IPS\Data\Store::i()->essentialCookieNames );
|
||||
|
||||
/* Log */
|
||||
if ( \IPS\Request::i()->status )
|
||||
{
|
||||
@@ -464,7 +478,7 @@ class _languages extends \IPS\Node\Controller
|
||||
*/
|
||||
protected function translate()
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->cookie['vle_editor'] ) and \IPS\Request::i()->cookie['vle_editor'] )
|
||||
if ( \IPS\Lang::vleActive() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_translate_with_vle', '1C126/8', 403, '' );
|
||||
}
|
||||
@@ -531,6 +545,10 @@ class _languages extends \IPS\Node\Controller
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->shortMessage( \IPS\Member::loggedIn()->language()->addToStack('translate_na'), array( 'ipsBadge', 'ipsBadge_neutral' ) );
|
||||
}
|
||||
},
|
||||
'word_default' => function( $val, $row )
|
||||
{
|
||||
return htmlspecialchars( $val, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', TRUE );
|
||||
},
|
||||
'word_custom' => function( $val, $row )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'customization' )->langString( $val, $row['word_key'], $row['lang_id'], $row['word_js'] );
|
||||
@@ -717,6 +735,9 @@ class _languages extends \IPS\Node\Controller
|
||||
unset( \IPS\Data\Store::i()->languages );
|
||||
unset( \IPS\Data\Store::i()->listFormats );
|
||||
|
||||
/* Update the essential cookie name list */
|
||||
unset( \IPS\Data\Store::i()->essentialCookieNames );
|
||||
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
@@ -873,13 +894,12 @@ class _languages extends \IPS\Node\Controller
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'lang_words' );
|
||||
|
||||
$language = \IPS\Lang::load( \IPS\Request::i()->id );
|
||||
|
||||
if( $language->marketplace_id )
|
||||
{
|
||||
\IPS\Output::i()->error( 'app_upload_marketplace_only', '2C126/B', 403, '' );
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form;
|
||||
if( $language->marketplace_id )
|
||||
{
|
||||
$form->addMessage( 'marketplace_resource_manual_upgrade', 'ipsMessage ipsMessage_info' );
|
||||
}
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'lang_upload', NULL, TRUE, array( 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ) ) );
|
||||
|
||||
/* Handle submissions */
|
||||
@@ -1059,6 +1079,9 @@ class _languages extends \IPS\Node\Controller
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Update the essential cookie name list */
|
||||
unset( \IPS\Data\Store::i()->essentialCookieNames );
|
||||
|
||||
@unlink( \IPS\Request::i()->file );
|
||||
|
||||
/* Redirect back to marketplace if it was installed from there. */
|
||||
@@ -1066,6 +1089,11 @@ class _languages extends \IPS\Node\Controller
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=marketplace&controller=marketplace&do=viewFile&id=' . \IPS\Request::i()->marketplace ), 'lang_installed' );
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->into ) )
|
||||
{
|
||||
\IPS\Lang::load( (int) \IPS\Request::i()->into )->marketplace_id = NULL;
|
||||
\IPS\Lang::load( (int) \IPS\Request::i()->into )->save();
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=languages&controller=languages' ) );
|
||||
}
|
||||
|
||||
@@ -26,6 +26,76 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Get the available filters for the main table
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function _getTableFilters() : array
|
||||
{
|
||||
$filters = [
|
||||
'members_filter_banned' => 'temp_ban<>0',
|
||||
'members_filter_spam' => \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ),
|
||||
'members_filter_validating' => '( v.lost_pass=0 AND v.forgot_security=0 AND v.vid IS NOT NULL )',
|
||||
'members_filter_administrators' => '(1=1)' // We use a straight join when this filter is activated, so there's no additional where needed
|
||||
];
|
||||
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( "email <> '' and name=''" ) )->first() )
|
||||
{
|
||||
$filters['members_filtered_reserved'] = "(name='')";
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->ipb_bruteforce_attempts )
|
||||
{
|
||||
/* We do this so we can put the locked filter at the 'end' of the buttons - array_unshift does not give us a simple method to retain keys */
|
||||
$filters += array( 'members_filter_locked' => '( failed_login_count>=' . (int) \IPS\Settings::i()->ipb_bruteforce_attempts . ' OR failed_mfa_attempts>=' . (int) \IPS\Settings::i()->security_questions_tries . ')' );
|
||||
}
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the joins for the main table
|
||||
*
|
||||
* @returns array
|
||||
*/
|
||||
protected static function _getTableJoins( array $joinFields, \IPS\Helpers\Table\Db $table ) : array
|
||||
{
|
||||
$joins = [
|
||||
array(
|
||||
'select' => 'v.vid, v.coppa_user, v.lost_pass, v.forgot_security, v.new_reg, v.email_chg, v.user_verified, v.spam_flag, v.reg_cancelled',
|
||||
'from' => array( 'core_validating', 'v' ),
|
||||
'where' => 'v.member_id=core_members.member_id AND v.lost_pass != 1 AND v.forgot_security != 1' ),
|
||||
array(
|
||||
'select' => implode( ',', $joinFields ),
|
||||
'from' => array( 'core_pfields_content', 'p' ),
|
||||
'where' => 'p.member_id=core_members.member_id' ),
|
||||
array(
|
||||
'select' => 'm.row_id',
|
||||
'from' => array( 'core_admin_permission_rows', 'm' ),
|
||||
'where' => "( m.row_id_type='group' and ( m.row_id=core_members.member_group_id OR FIND_IN_SET( m.row_id, core_members.mgroup_others ) ) or ( m.row_id=core_members.member_id AND m.row_id_type='member' ))",
|
||||
'type' => 'STRAIGHT_JOIN' )
|
||||
];
|
||||
|
||||
/* Makes query less efficient */
|
||||
if ( $table->filter !== 'members_filter_administrators' )
|
||||
{
|
||||
unset( $joins[2] );
|
||||
}
|
||||
|
||||
if ( $table->filter !== 'members_filter_validating' )
|
||||
{
|
||||
unset( $joins[0] );
|
||||
}
|
||||
|
||||
if ( ! isset( \IPS\Request::i()->advanced_search_submitted ) )
|
||||
{
|
||||
unset( $joins[1] );
|
||||
}
|
||||
|
||||
return $joins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage Members
|
||||
@@ -51,7 +121,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Create the table */
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'email<>?', '' ) ), $forceIndex );
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_members', \IPS\Http\Url::internal( 'app=core&module=members&controller=members' ), array( array( 'core_members.email<>?', '' ) ), $forceIndex );
|
||||
$table->langPrefix = 'members_';
|
||||
|
||||
/* Columns we need */
|
||||
@@ -149,37 +219,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Joins */
|
||||
$table->joins = array(
|
||||
array(
|
||||
'select' => 'v.vid, v.coppa_user, v.lost_pass, v.forgot_security, v.new_reg, v.email_chg, v.user_verified, v.spam_flag, v.reg_cancelled',
|
||||
'from' => array( 'core_validating', 'v' ),
|
||||
'where' => 'v.member_id=core_members.member_id AND v.lost_pass != 1 AND v.forgot_security != 1' ),
|
||||
array(
|
||||
'select' => implode( ',', $joinFields ),
|
||||
'from' => array( 'core_pfields_content', 'p' ),
|
||||
'where' => 'p.member_id=core_members.member_id' ),
|
||||
array(
|
||||
'select' => 'm.row_id',
|
||||
'from' => array( 'core_admin_permission_rows', 'm' ),
|
||||
'where' => "( m.row_id_type='group' and ( m.row_id=core_members.member_group_id OR FIND_IN_SET( m.row_id, core_members.mgroup_others ) ) or ( m.row_id=core_members.member_id AND m.row_id_type='member' ))",
|
||||
'type' => 'STRAIGHT_JOIN' )
|
||||
);
|
||||
|
||||
/* Makes query less efficient */
|
||||
if ( $table->filter !== 'members_filter_administrators' )
|
||||
{
|
||||
unset( $table->joins[2] );
|
||||
}
|
||||
|
||||
if ( $table->filter !== 'members_filter_validating' )
|
||||
{
|
||||
unset( $table->joins[0] );
|
||||
}
|
||||
|
||||
if ( ! isset( \IPS\Request::i()->advanced_search_submitted ) )
|
||||
{
|
||||
unset( $table->joins[1] );
|
||||
}
|
||||
$table->joins = static::_getTableJoins( $joinFields, $table );
|
||||
|
||||
/* Ranks */
|
||||
$rankOptions = array( '' => 'any' );
|
||||
@@ -206,7 +246,10 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
return array( "core_members.member_id=?", (float) $v[1] );
|
||||
}
|
||||
} ),
|
||||
'email' => \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT,
|
||||
'email' => array( \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT, array(), function( $val )
|
||||
{
|
||||
return array( "core_members.email LIKE ?", '%' . $val . '%' );
|
||||
} ),
|
||||
'ip_address' => array( \IPS\Helpers\Table\SEARCH_CONTAINS_TEXT, array(), function( $val )
|
||||
{
|
||||
return array( "core_members.ip_address LIKE ?", '%' . $val . '%' );
|
||||
@@ -266,23 +309,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Filters */
|
||||
$table->filters = array(
|
||||
'members_filter_banned' => 'temp_ban<>0',
|
||||
'members_filter_spam' => \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ),
|
||||
'members_filter_validating' => '( v.lost_pass=0 AND v.forgot_security=0 AND v.vid IS NOT NULL )',
|
||||
'members_filter_administrators' => '(1=1)' // We use a straight join when this filter is activated, so there's no additional where needed
|
||||
);
|
||||
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( "email <> '' and name=''" ) )->first() )
|
||||
{
|
||||
$table->filters['members_filtered_reserved'] = "(name='')";
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->ipb_bruteforce_attempts )
|
||||
{
|
||||
/* We do this so we can put the locked filter at the 'end' of the buttons - array_unshift does not give us a simple method to retain keys */
|
||||
$table->filters = array( 'members_filter_locked' => '( failed_login_count>=' . (int) \IPS\Settings::i()->ipb_bruteforce_attempts . ' OR failed_mfa_attempts>=' . (int) \IPS\Settings::i()->security_questions_tries . ')' ) + $table->filters;
|
||||
}
|
||||
$table->filters = static::_getTableFilters();
|
||||
|
||||
/* Custom parsers */
|
||||
$table->parsers = array(
|
||||
@@ -2896,7 +2923,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
unset( \IPS\Data\Store::i()->bannedIpAddresses );
|
||||
}
|
||||
|
||||
|
||||
$member->save();
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__members_edited', array( $member->name => FALSE ) );
|
||||
@@ -4272,8 +4299,8 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Cells starting with =, + or - can be a security risk. */
|
||||
if ( !isset( $wizardData['includeInsecure'] ) and !\in_array( $column, array( 'primary_group_name', 'secondary_group_names', 'skin_name', 'language_name', 'members_pass_hash', 'members_pass_salt' ) ) and \in_array( mb_substr( $valueToWrite, 0, 1 ), array( '=', '+', '-', '@' ) ) )
|
||||
{
|
||||
if ( !isset( $wizardData['includeInsecure'] ) and !\in_array( $column, array( 'primary_group_name', 'secondary_group_names', 'skin_name', 'language_name', 'members_pass_hash', 'members_pass_salt' ) ) and \in_array( mb_substr( $valueToWrite, 0, 1 ), array( '=', '+', '-', '@' ) ) and ! is_numeric( \str_replace( ' ', '', $valueToWrite ) ) )
|
||||
{
|
||||
$mrData['removedData'][ $member['member_id'] ] = array( $column, base64_encode( $valueToWrite ) );
|
||||
return FALSE;
|
||||
}
|
||||
@@ -4378,22 +4405,7 @@ class _members extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Init */
|
||||
$xml = \IPS\Xml\SimpleXML::create('member_export');
|
||||
$xml->addAttribute( 'created', \IPS\DateTime::ts( time() )->rfc3339() );
|
||||
|
||||
/* Get the data */
|
||||
foreach( \IPS\Application::allExtensions( 'core', 'MemberExportPersonalInformation', TRUE, 'core' ) AS $key => $ext )
|
||||
{
|
||||
if ( $data = $ext->getData( $member ) and \is_array( $data ) and \count( $data ) )
|
||||
{
|
||||
$child = $xml->addChild( $key );
|
||||
foreach( $data as $k => $v )
|
||||
{
|
||||
$child->addChild( $k, $v );
|
||||
}
|
||||
}
|
||||
}
|
||||
$xml = $member->getPiiData( $member );
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__member_pii_exported', array( $member->name => FALSE ) );
|
||||
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief privacy
|
||||
* @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 07 Mar 2023
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\members;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Member;
|
||||
use IPS\Output;
|
||||
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* privacy
|
||||
*/
|
||||
class _privacy extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'privacy_manage' );
|
||||
\IPS\Output::i()->sidebar['actions']['settings'] = array(
|
||||
'icon' => 'cog',
|
||||
'title' => 'settings',
|
||||
'link' => $this->url->setQueryString( 'do', 'settings' ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('settings') )
|
||||
);
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
/* Some advanced search links may bring us here */
|
||||
\IPS\Output::i()->bypassCsrfKeyCheck = true;
|
||||
|
||||
/* Create the table */
|
||||
$where = [ [ \IPS\Db::i()->in('action', [\IPS\Member\PrivacyAction::TYPE_REQUEST_DELETE, \IPS\Member\PrivacyAction::TYPE_REQUEST_PII] ) ], ['approved=?', 0] ];
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_member_privacy_actions', \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy' ), $where );
|
||||
$table->include = [ 'photo', 'name', 'email', 'joined','action','request_date' ];
|
||||
|
||||
$table->filters = [
|
||||
'deletion_request' => ['action=?', \IPS\Member\PrivacyAction::TYPE_REQUEST_DELETE],
|
||||
'pii_data' => ['action=?', \IPS\Member\PrivacyAction::TYPE_REQUEST_PII],
|
||||
];
|
||||
|
||||
$table->joins = [
|
||||
[ 'select' => 'm.*', 'from' => [ 'core_members', 'm' ], 'where' => 'core_member_privacy_actions.member_id=m.member_id' ]
|
||||
];
|
||||
|
||||
$table->parsers = [
|
||||
'photo' => function( $val, $row )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( \IPS\Member::constructFromData( $row ), 'tiny' );
|
||||
},
|
||||
'name' => function( $val, $row ){
|
||||
if( $val )
|
||||
{
|
||||
$member = \IPS\Member::constructFromData( $row );
|
||||
|
||||
if( $banned = $member->isBanned() )
|
||||
{
|
||||
if( $banned instanceof \IPS\DateTime )
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'suspended_until', FALSE, array( 'sprintf' => array( $banned->localeDate() ) ) );
|
||||
}else
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'banned' );
|
||||
}
|
||||
return "<a href='".\IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ).$row[ 'member_id' ]."'>".htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE )."</a> <span class='ipsBadge ipsBadge_negative'>".$title.'</span> ';
|
||||
}else
|
||||
{
|
||||
return "<a href='".\IPS\Http\Url::internal( 'app=core&module=members&controller=members&do=view&id=' ).$row[ 'member_id' ]."'>".htmlentities( $val, ENT_DISALLOWED, 'UTF-8', FALSE ).'</a>';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'members', 'core', 'admin' )->memberReserved( \IPS\Member::constructFromData( $row ) );
|
||||
}
|
||||
},
|
||||
'joined' => function( $val, $row )
|
||||
{
|
||||
return \IPS\DateTime::ts( $val )->localeDate();
|
||||
},
|
||||
'request_date' => function( $val, $row )
|
||||
{
|
||||
return \IPS\DateTime::ts( $val )->localeDate();
|
||||
},
|
||||
'action' => function( $val, $row )
|
||||
{
|
||||
switch ( $val )
|
||||
{
|
||||
case \IPS\Member\PrivacyAction::TYPE_REQUEST_PII:
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('pii_download_requested');
|
||||
case \IPS\Member\PrivacyAction::TYPE_REQUEST_DELETE:
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('account_deletion_requested');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
$table->rowButtons = function( $row )
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if( $row['action'] == \IPS\Member\PrivacyAction::TYPE_REQUEST_PII )
|
||||
{
|
||||
$return[ 'approve' ] = [
|
||||
'title' => 'approve',
|
||||
'icon' => 'check-circle',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy&do=approvePii&id='.$row[ 'id' ] )->csrf()->getSafeUrlFromFilters(),
|
||||
];
|
||||
$return['reject'] = [
|
||||
'icon' => 'times',
|
||||
'title' => 'reject',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy&do=rejectPii&id=' . $row['id'] )->csrf()->getSafeUrlFromFilters(),
|
||||
];
|
||||
}
|
||||
else if( $row['action'] == \IPS\Member\PrivacyAction::TYPE_REQUEST_DELETE )
|
||||
{
|
||||
$member = \IPS\Member::constructFromData( $row );
|
||||
|
||||
$return[ 'approveDeletion' ] = [
|
||||
'title' => 'approve',
|
||||
'icon' => 'check-circle',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy&do=approveDeletion&id='.$row[ 'id' ] )->csrf()->getSafeUrlFromFilters(),
|
||||
'data' => [ 'confirm' => '', 'confirmSubMessage' => \IPS\Member::loggedIn()->language()->addToStack( 'delete_member_confirm', FALSE, array( 'sprintf' => $member->name ) ) ]
|
||||
];
|
||||
$return['rejectDeletion'] = [
|
||||
'icon' => 'times',
|
||||
'title' => 'reject',
|
||||
'link' => \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy&do=rejectDeletion&id=' . $row['id'] )->csrf()->getSafeUrlFromFilters(),
|
||||
'data' => array(
|
||||
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
return $return;
|
||||
};
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'menu__core_members_privacy');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $table );
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve PII Request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function approvePii()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
try
|
||||
{
|
||||
$request = \IPS\Member\PrivacyAction::load( \IPS\Request::i()->id );
|
||||
$request->approvePiiRequest();
|
||||
\IPS\Session::i()->log( 'acplog__piirequest_approved', array( $request->member->name => FALSE ) );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C432/1', 404, '' );
|
||||
}
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy' )->getSafeUrlFromFilters(), 'approved' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject PII Request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function rejectPii()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
try
|
||||
{
|
||||
$request = \IPS\Member\PrivacyAction::load( \IPS\Request::i()->id );
|
||||
$request->rejectPiiRequest();
|
||||
\IPS\Session::i()->log( 'acplog__piirequest_rejected', array( $request->member->name => FALSE ) );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C432/2', 404, '' );
|
||||
}
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy' )->getSafeUrlFromFilters(), 'pii_request_rejected' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve deletion request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function approveDeletion()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
try
|
||||
{
|
||||
$request = \IPS\Member\PrivacyAction::load( \IPS\Request::i()->id );
|
||||
|
||||
\IPS\Request::i()->confirmedDelete( message: \IPS\Member::loggedIn()->language()->addToStack( 'delete_member_confirm', FALSE, array( 'sprintf' => $request->member->name ) ) );
|
||||
|
||||
$request->deleteAccount();
|
||||
\IPS\Session::i()->log( 'acplog__deletionrequest__approved', array( $request->member->name => FALSE ) );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C432/3', 404, '' );
|
||||
}
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy' )->getSafeUrlFromFilters(), 'approved' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject deletion request
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function rejectDeletion()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
try
|
||||
{
|
||||
$request = \IPS\Member\PrivacyAction::load( \IPS\Request::i()->id );
|
||||
$request->rejectDeletionRequest();
|
||||
\IPS\Session::i()->log( 'acplog__deletionrequest__rejected', array( $request->member->name => FALSE ) );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C432/4', 404, '' );
|
||||
}
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy' )->getSafeUrlFromFilters(), 'rejected' );
|
||||
}
|
||||
|
||||
protected function settings()
|
||||
{
|
||||
$form = new \IPS\Helpers\Form();
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'pii_type', \IPS\Settings::i()->pii_type, FALSE, array(
|
||||
'options' => array(
|
||||
'off' => 'disabled',
|
||||
'on' => 'enabled',
|
||||
'redirect' => "pii_external" ),
|
||||
'toggles' => array(
|
||||
'off' => array( '' ),
|
||||
'redirect' => array( 'pii_link' ),
|
||||
'on' => array(),
|
||||
)
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Url( 'pii_link', \IPS\Settings::i()->pii_link, FALSE, array(), NULL, NULL, NULL, 'pii_link' ) );
|
||||
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'right_to_be_forgotten_type', \IPS\Settings::i()->right_to_be_forgotten_type, FALSE, array(
|
||||
'options' => array(
|
||||
'off' => 'disabled',
|
||||
'on' => 'enabled',
|
||||
'redirect' => "right_to_be_forgotten_external" ),
|
||||
'toggles' => array(
|
||||
'off' => array( '' ),
|
||||
'redirect' => array( 'right_to_be_forgotten_link' ),
|
||||
'on' => array(),
|
||||
)
|
||||
) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Url( 'right_to_be_forgotten_link', \IPS\Settings::i()->right_to_be_forgotten_link, FALSE, array(), NULL, NULL, NULL, 'right_to_be_forgotten_link' ) );
|
||||
|
||||
|
||||
if( $values = $form->values() )
|
||||
{
|
||||
$form->saveAsSettings();
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=members&controller=privacy' ), 'saved' );
|
||||
}
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'settings');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'title', (string) $form );
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,8 @@ class _refersettings extends \IPS\Dispatcher\Controller
|
||||
\IPS\Session::i()->log( 'acplog__referrals_disabled' );
|
||||
}
|
||||
|
||||
/* update the essential cookie name list */
|
||||
unset( \IPS\Data\Store::i()->essentialCookieNames );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=membersettings&controller=referrals') );
|
||||
}
|
||||
|
||||
|
||||
@@ -37,19 +37,7 @@ class _pmstats extends \IPS\Dispatcher\Controller
|
||||
/* Check permission */
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'messages_manage', 'core', 'members' );
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=messengerstats&controller=pmstats' ), 'core_message_posts', 'msg_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
) );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('new_conversations'), 'number', 'SUM(msg_is_first_post)' );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('mt_replies'), 'number', '( count(*) - SUM(msg_is_first_post) )' );
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_messages_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Conversations' )->getChart( \IPS\Http\Url::internal( 'app=core&module=messengerstats&controller=pmstats' ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_messengerstats_pmstats');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
|
||||
@@ -65,10 +65,15 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
$tabs['flagging'] = 'spamprevention_flagging';
|
||||
$tabs['service'] = 'enhancements__core_SpamMonitoring';
|
||||
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'qanda_manage' ) and \in_array( \IPS\Login::registrationType(), array( 'normal', 'full' ) ) )
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'qanda_manage' ) )
|
||||
{
|
||||
$tabs['qanda'] = 'qanda_settings';
|
||||
}
|
||||
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'geolocation' ) )
|
||||
{
|
||||
$tabs['geolocation'] = 'geolocation_settings';
|
||||
}
|
||||
|
||||
/* Add a button for logs */
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'moderation', 'spam_service_log' ) )
|
||||
@@ -220,7 +225,7 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'spam_service_enabled', 0, FALSE, array( 'disabled' => $disabled, 'togglesOn' => array( 'spam_service_send_to_ips', 'spam_service_action_0', 'spam_service_action_1', 'spam_service_action_2', 'spam_service_action_3', 'spam_service_action_4' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'spam_service_enabled', 0, FALSE, array( 'disabled' => $disabled, 'togglesOn' => array( 'spam_service_send_to_ips', 'spam_service_action_0', 'spam_service_action_1', 'spam_service_action_2', 'spam_service_action_3', 'spam_service_action_4', 'spam_service_disposable' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'spam_service_send_to_ips', 0, FALSE, array( 'disabled' => $disabled ), NULL, NULL, NULL, 'spam_service_send_to_ips' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'spam_service_action_1', \IPS\Settings::i()->spam_service_action_1, FALSE, array( 'disabled' => $disabled, 'options' => $actions, 'toggles' => array( '5' => array( 'spam_service_action_1_num' ) ) ), NULL, NULL, NULL, 'spam_service_action_1' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'spam_service_action_1_num', ( isset( $days[1] ) ? $days[1] : -1 ), FALSE, array( 'unlimited' => -1, 'unlimitedLang' => 'spam_service_action_unlimited_days'), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('days'), 'spam_service_action_1_num' ) );
|
||||
@@ -230,20 +235,23 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'spam_service_action_3_num', ( isset( $days[3] ) ? $days[3] : -1 ), FALSE, array( 'unlimited' => -1, 'unlimitedLang' => 'spam_service_action_unlimited_days'), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('days'), 'spam_service_action_3_num' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'spam_service_action_4', \IPS\Settings::i()->spam_service_action_4, FALSE, array( 'disabled' => $disabled, 'options' => $actions, 'toggles' => array( '5' => array( 'spam_service_action_4_num' ) ) ), NULL, NULL, NULL, 'spam_service_action_4' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'spam_service_action_4_num', ( isset( $days[4] ) ? $days[4] : -1 ), FALSE, array( 'unlimited' => -1, 'unlimitedLang' => 'spam_service_action_unlimited_days'), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('days'), 'spam_service_action_4_num' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'spam_service_disposable', \IPS\Settings::i()->spam_service_disposable, FALSE, array( 'disabled' => $disabled, 'options' => $actions, 'toggles' => array( '5' => array( 'spam_service_disposable_num' ) ) ), NULL, NULL, NULL, 'spam_service_disposable' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'spam_service_disposable_num', ( isset( $days['disposable'] ) ? $days['disposable'] : -1 ), FALSE, array( 'unlimited' => -1, 'unlimitedLang' => 'spam_service_action_unlimited_days'), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('days'), 'spam_service_disposable_num' ) );
|
||||
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'spam_service_action_0', \IPS\Settings::i()->spam_service_action_0, FALSE, array( 'disabled' => $disabled, 'options' => $actions ), NULL, NULL, NULL, 'spam_service_action_0' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$values['spam_service_days'] = array();
|
||||
foreach( array( 1, 2, 3, 4 ) as $num )
|
||||
foreach( array( 'action_1', 'action_2', 'action_3', 'action_4', 'disposable' ) as $num )
|
||||
{
|
||||
if ( $values['spam_service_action_' . $num ] == 5 )
|
||||
if ( $values['spam_service_' . $num ] == 5 )
|
||||
{
|
||||
$values['spam_service_days'][ $num ] = $values['spam_service_action_' . $num . '_num' ];
|
||||
$values['spam_service_days'][ str_replace( 'action_', '', $num ) ] = $values['spam_service_' . $num . '_num' ];
|
||||
}
|
||||
|
||||
unset( $values['spam_service_action_' . $num . '_num' ] );
|
||||
unset( $values['spam_service_' . $num . '_num' ] );
|
||||
}
|
||||
|
||||
$values['spam_service_days'] = json_encode( $values['spam_service_days'] );
|
||||
@@ -318,7 +326,7 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
return $return;
|
||||
};
|
||||
|
||||
return (string) $table;
|
||||
return \IPS\Theme::i()->getTemplate( 'spam' )->spamQandASettings( $table );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -596,7 +604,7 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
|
||||
/* Build form */
|
||||
$form = new \IPS\Helpers\Form();
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'whitelist_type', $current['whitelist_type'], TRUE,
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'whitelist_type', $current ? $current['whitelist_type'] : NULL, TRUE,
|
||||
array(
|
||||
'options' => array(
|
||||
'ip' => 'spam_whitelist_ip_select',
|
||||
@@ -608,14 +616,14 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
)
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_ip_content', $current['whitelist_content'], TRUE, array(), NULL, NULL, NULL, 'whitelist_ip_content' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_domain_content', $current['whitelist_content'], TRUE, array( 'placeholder' => 'mycompany.com' ), function( $value ) {
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_ip_content', $current ? $current['whitelist_content'] : NULL, TRUE, array(), NULL, NULL, NULL, 'whitelist_ip_content' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_domain_content', $current ? $current['whitelist_content'] : NULL, TRUE, array( 'placeholder' => 'mycompany.com' ), function( $value ) {
|
||||
if( isset( $value ) AND mb_stripos( $value, '@' ) )
|
||||
{
|
||||
throw new \DomainException( 'whitelist_domain_email_detected' );
|
||||
}
|
||||
}, NULL, NULL, 'whitelist_domain_content' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_reason', $current['whitelist_reason'] ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'whitelist_reason', $current ? $current['whitelist_reason'] : NULL ) );
|
||||
|
||||
/* Handle submissions */
|
||||
if ( $values = $form->values() )
|
||||
@@ -669,4 +677,69 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&do=whitelist' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show GeoLocation settings
|
||||
*
|
||||
* @return string HTML to display
|
||||
*/
|
||||
protected function _manageGeolocation()
|
||||
{
|
||||
$licenseData = \IPS\IPS::licenseKey();
|
||||
|
||||
/* Build Form */
|
||||
$settings = \IPS\Settings::i()->spam_geo_settings ? json_decode( \IPS\Settings::i()->spam_geo_settings, true ) : array();
|
||||
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$matrix = new \IPS\Helpers\Form\Matrix;
|
||||
|
||||
if( !$licenseData or !isset( $licenseData['products']['spam'] ) or !$licenseData['products']['spam'] or ( !$licenseData['cloud'] AND strtotime( $licenseData['expires'] ) < time() ) )
|
||||
{
|
||||
if( !\IPS\Settings::i()->ipb_reg_number )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['spam_service_enabled_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '__nulling_null_alert' ); //Changing error message to custom
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['spam_service_enabled_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '__nulling_null_alert' ); //Changing error message to custom
|
||||
}
|
||||
}
|
||||
|
||||
$matrix->columns = array(
|
||||
'country' => function( $key, $value, $data ) {
|
||||
$options = array();
|
||||
foreach( \IPS\GeoLocation::$countries AS $country )
|
||||
{
|
||||
$options[ $country ] = \IPS\Member::loggedIn()->language()->addToStack( 'country-' . $country );
|
||||
}
|
||||
return new \IPS\Helpers\Form\Select( $key, $value, TRUE, array( 'options' => $options ) );
|
||||
},
|
||||
'action' => function( $key, $value, $data ) {
|
||||
return new \IPS\Helpers\Form\Select( $key, $value, TRUE, array( 'options' => array( 'moderate' => 'spam_service_act_2', 'block' => 'spam_service_act_4' ) ) );
|
||||
}
|
||||
);
|
||||
|
||||
$matrix->rows = array();
|
||||
foreach( $settings AS $country => $action )
|
||||
{
|
||||
$matrix->rows[] = array(
|
||||
'country' => $country,
|
||||
'action' => $action
|
||||
);
|
||||
}
|
||||
$form->addMatrix( 'geolocation', $matrix );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$save = array();
|
||||
foreach( $values['geolocation'] AS $key => $value )
|
||||
{
|
||||
$save[ $value['country'] ] = $value['action'];
|
||||
}
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'spam_geo_settings' => json_encode( $save ) ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=moderation&controller=spam&tab=geolocation" ), 'saved' );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'spam' )->spamGeoSettings( $form );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief mycharts
|
||||
* @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 09 Dec 2022
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\overview;
|
||||
|
||||
use IPS\core\Statistics\Chart;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* mycharts
|
||||
*/
|
||||
class _mycharts extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* @brief Allow MySQL RW separation for efficiency
|
||||
*/
|
||||
public static $allowRWSeparation = TRUE;
|
||||
|
||||
/**
|
||||
* Manage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$charts = [];
|
||||
foreach( Chart::getChartsForMember( \IPS\Http\Url::internal( "app=core&module=overview&controller=mycharts" ), TRUE ) AS $id )
|
||||
{
|
||||
$charts[] = $id;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_overview_mycharts');
|
||||
if ( !\count( $charts ) )
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('stats')->mychartsEmpty();
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('stats')->mycharts( $charts );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chart
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getChart()
|
||||
{
|
||||
|
||||
if ( !isset( \IPS\Request::i()->chartId ) )
|
||||
{
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->output = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=mycharts" ) );
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$chart = Chart::constructMemberChartFromData( \IPS\Request::i()->chartId, \IPS\Http\Url::internal( "app=core&module=overview&controller=mycharts&do=getChart&chartId=" . \IPS\Request::i()->chartId ) );
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
catch( \Throwable )
|
||||
{
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->output = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=overview&controller=mycharts" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class _onboard extends \IPS\Dispatcher\Controller
|
||||
$values[ 'site_address' ] = json_encode( $values[ 'site_address' ] );
|
||||
$values[ 'icons_favicon' ] = (string) $values[ 'icons_favicon' ];
|
||||
|
||||
$values=\IPS\core\modules\admin\customization\icons::processApplicationIcon( $values );
|
||||
$values=\IPS\core\modules\admin\settings\webapp::processApplicationIcon( $values );
|
||||
$values=\IPS\core\modules\admin\settings\terms::processForm( $values );
|
||||
|
||||
/* If a logo was uploaded, do stuff with it... */
|
||||
|
||||
@@ -110,6 +110,8 @@ class _contactus extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$form->add( $field );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'contact_email_verify', \IPS\Settings::i()->contact_email_verify, TRUE ) );
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,12 @@ class _email extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch ( \Exception $exception )
|
||||
{
|
||||
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( \get_class( $exception ) . ": " . $exception->getMessage() . " (" . $exception->getCode() . ")", 'error' );
|
||||
$content = $exception->getMessage();
|
||||
if ( !( $exception instanceof \IPS\Email\Outgoing\Exception ) )
|
||||
{
|
||||
$content = \get_class( $exception ) . ": " . $exception->getMessage() . " (" . $exception->getCode() . ")";
|
||||
}
|
||||
$messageHtml = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( $content, 'error' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ class _posting extends \IPS\Dispatcher\Controller
|
||||
$form->addHeader('posting_images');
|
||||
$form->add( new \IPS\Helpers\Form\WidthHeight( 'attachment_resample_size', \IPS\Settings::i()->attachment_resample_size ? explode( 'x', \IPS\Settings::i()->attachment_resample_size ) : array( 0, 0 ), FALSE, array( 'resizableDiv' => FALSE, 'unlimited' => array( 0, 0 ) ), NULL, NULL, NULL, 'attachment_resample_size' ) );
|
||||
$current = ( isset( \IPS\Settings::i()->attachment_image_size ) ) ? explode( 'x', \IPS\Settings::i()->attachment_image_size ) : array( 1000, 750 );
|
||||
$form->add( new \IPS\Helpers\Form\WidthHeight( 'attachment_image_size', $current, FALSE, array( 'resizableDiv' => FALSE, 'unlimited' => array( 0, 0 ) ), NULL, NULL, NULL, 'attachment_image_size' ) );
|
||||
$form->add( new \IPS\Helpers\Form\WidthHeight( 'attachment_image_size', $current, FALSE, array( 'resizableDiv' => FALSE, 'unlimited' => array( 0, 0 ) ), function( $value ){ if( $value[0] > 4800 OR $value[1] > 4800 ) { throw new \InvalidArgumentException('form_image_too_large'); } }, NULL, NULL, 'attachment_image_size' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'editor_embeds', \IPS\Settings::i()->editor_embeds, FALSE, array( 'togglesOn' => array( 'max_video_width', 'max_internalembed_width' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'max_video_width', \IPS\Settings::i()->max_video_width, FALSE, array( 'unlimited' => 0 ), NULL, NULL, 'px', 'max_video_width' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'max_internalembed_width', \IPS\Settings::i()->max_internalembed_width, FALSE, array( 'unlimited' => 0 ), NULL, NULL, 'px', 'max_internalembed_width' ) );
|
||||
@@ -478,10 +478,10 @@ class _posting extends \IPS\Dispatcher\Controller
|
||||
|
||||
$form = new \IPS\Helpers\Form();
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_enabled', \IPS\Settings::i()->tags_enabled, FALSE, array( 'togglesOn' => array( 'tags_can_prefix', 'tags_open_system', 'tags_predefined', 'tags_force_lower', 'tags_min', 'tags_max', 'tags_len_min', 'tags_len_max', 'tags_clean' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_enabled', \IPS\Settings::i()->tags_enabled, FALSE, array( 'togglesOn' => array( 'tags_can_prefix', 'tags_open_system', 'tags_predefined', 'tags_force_lower', 'tags_min', 'tags_max', 'tags_len_min', 'tags_len_max', 'tags_clean', 'tags_alphabetical' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_can_prefix', \IPS\Settings::i()->tags_can_prefix, FALSE, array(), NULL, NULL, NULL, 'tags_can_prefix' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'tags_open_system', \IPS\Settings::i()->tags_open_system, FALSE, array( 'options' => array( 1 => 'tags_open_system_open', 0 => 'tags_open_system_closed' ) ), NULL, NULL, NULL, 'tags_open_system' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'tags_predefined', \IPS\Settings::i()->tags_predefined, FALSE, array( 'autocomplete' => array( 'unique' => TRUE ) ), NULL, NULL, NULL, 'tags_predefined' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'tags_predefined', \IPS\Settings::i()->tags_predefined, FALSE, array( 'autocomplete' => array( 'unique' => TRUE, 'alphabetical' => \IPS\Settings::i()->tags_alphabetical ) ), NULL, NULL, NULL, 'tags_predefined' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_force_lower', \IPS\Settings::i()->tags_force_lower, FALSE, array(), NULL, NULL, NULL, 'tags_force_lower' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'tags_min', \IPS\Settings::i()->tags_min, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'tags_min_none', 'unlimitedToggles' => array( 'tags_min_req' ), 'unlimitedToggleOn' => FALSE ), NULL, NULL, NULL, 'tags_min' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_min_req', \IPS\Settings::i()->tags_min_req, FALSE, array(), NULL, NULL, NULL, 'tags_min_req' ) );
|
||||
@@ -489,6 +489,7 @@ class _posting extends \IPS\Dispatcher\Controller
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'tags_len_min', \IPS\Settings::i()->tags_len_min, FALSE, array( 'unlimited' => 0 ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack( 'characters' ), 'tags_len_min' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'tags_len_max', \IPS\Settings::i()->tags_len_max, FALSE, array( 'unlimited' => 0 ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack( 'characters' ), 'tags_len_max' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_clean', \IPS\Settings::i()->tags_clean, FALSE, array(), NULL, NULL, NULL, 'tags_clean' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'tags_alphabetical', \IPS\Settings::i()->tags_alphabetical, FALSE, array(), NULL, NULL, NULL, 'tags_alphabetical' ) );
|
||||
|
||||
if ( ! \IPS\Settings::i()->tags_open_system and ! \IPS\Settings::i()->tags_predefined )
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ class _terms extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
public static function processForm( $values )
|
||||
{
|
||||
foreach ( array( 'gl_guidelines' => 'guidelines_value', 'privacy_text' => 'privacy_text_value', 'reg_rules' => 'reg_rules_value', 'guest_terms_bar_text' => 'guest_terms_bar_text_value' ) as $k => $v )
|
||||
foreach ( array( 'gl_guidelines' => 'guidelines_value', 'privacy_text' => 'privacy_text_value', 'reg_rules' => 'reg_rules_value', 'guest_terms_bar_text' => 'guest_terms_bar_text_value', 'cookie_3rdpartynotice' => 'cookie_3rdpartynotice_value' ) as $k => $v )
|
||||
{
|
||||
/* Guest terms bar text has special replacements that need to be swapped to sprintf parameters */
|
||||
if ( $k == 'guest_terms_bar_text' and $values['guest_terms_bar'] )
|
||||
@@ -105,6 +105,9 @@ class _terms extends \IPS\Dispatcher\Controller
|
||||
unset( $values[ $k ] );
|
||||
}
|
||||
|
||||
/* Update the essential cookie name list */
|
||||
unset( \IPS\Data\Store::i()->essentialCookieNames );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
@@ -157,6 +160,9 @@ class _terms extends \IPS\Dispatcher\Controller
|
||||
$form->addHeader( 'guest_terms_options' );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'guest_terms_bar', \IPS\Settings::i()->guest_terms_bar, FALSE, array( 'togglesOn' => array( 'guest_terms_bar_text' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'guest_terms_bar_text', NULL, FALSE, array( 'app' => 'core', 'key' => 'guest_terms_bar_text_value', 'sprintf' => array( '{terms}', '{privacy}', '{guidelines}', '{cookies}' ) ), NULL, NULL, NULL, 'guest_terms_bar_text' ) );
|
||||
|
||||
$form->addHeader( 'terms_cookies' );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'cookie_3rdpartynotice', NULL, FALSE, array( 'app' => 'core', 'key' => 'cookie_3rdpartynotice_value', 'editor' => array( 'app' => 'core', 'key' => 'Admin', 'autoSaveKey' => '3rdPartyCookies', 'attachIds' => array( NULL, NULL, 'privacy_text' ) ) ) ));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief webapp
|
||||
* @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 28 Mar 2023
|
||||
*/
|
||||
|
||||
namespace IPS\core\modules\admin\settings;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* webapp
|
||||
*/
|
||||
class _webapp extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'webapp_manage' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$form = new \IPS\Helpers\Form;
|
||||
|
||||
$form->addTab( 'webapp_tab_icons' );
|
||||
|
||||
/* Homescreen icons - we accept one upload and create the images we need */
|
||||
$homeScreen = json_decode( \IPS\Settings::i()->icons_homescreen, TRUE ) ?? array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_homescreen', ( isset( $homeScreen['original'] ) ) ? \IPS\File::get( 'core_Icons', $homeScreen['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
|
||||
|
||||
$homeScreenMaskable = json_decode( \IPS\Settings::i()->icons_homescreen_maskable, TRUE ) ?? array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_homescreen_maskable', ( isset( $homeScreenMaskable['original'] ) ) ? \IPS\File::get( 'core_Icons', $homeScreenMaskable['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons', 'allowedFileTypes' => ['png', 'webp' ] ) ) );
|
||||
|
||||
/* Apple startup screen logo - we accept one upload and create the images we need */
|
||||
$apple = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) ?? array();
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_apple_startup', ( isset( $apple['original'] ) ) ? \IPS\File::get( 'core_Icons', $apple['original'] ) : NULL, FALSE, array( 'image' => true, 'storageExtension' => 'core_Icons' ) ) );
|
||||
|
||||
/* Safari pinned tabs icon and highlight color */
|
||||
$form->add( new \IPS\Helpers\Form\Upload( 'icons_mask_icon', \IPS\Settings::i()->icons_mask_icon ? \IPS\File::get( 'core_Icons', \IPS\Settings::i()->icons_mask_icon ) : NULL, FALSE, array( 'allowedFileTypes' => array( 'svg' ), 'storageExtension' => 'core_Icons', 'obscure' => FALSE ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'icons_mask_color', \IPS\Settings::i()->icons_mask_color, FALSE ) );
|
||||
|
||||
$form->addTab( 'webapp_tab_manifest' );
|
||||
|
||||
/* And finally, additional manifest and livetile details */
|
||||
$manifestDetails = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'configure_manifest', \count( $manifestDetails ) > 0, FALSE, array(
|
||||
'togglesOn' => array( 'manifest_shortname', 'manifest_fullname', 'manifest_description', 'manifest_defaultapp', 'manifest_themecolor', 'manifest_bgcolor', 'manifest_display', 'manifest_custom_url_toggle' ),
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'manifest_shortname', ( isset( $manifestDetails['short_name'] ) ) ? $manifestDetails['short_name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_shortname' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'manifest_fullname', ( isset( $manifestDetails['name'] ) ) ? $manifestDetails['name'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_fullname' ) );
|
||||
$form->add( new \IPS\Helpers\Form\TextArea( 'manifest_description', ( isset( $manifestDetails['description'] ) ) ? $manifestDetails['description'] : '', FALSE, array(), NULL, NULL, NULL, 'manifest_description' ) );
|
||||
|
||||
$formStartUrl = '';
|
||||
if( isset( $manifestDetails['start_url'] ) )
|
||||
{
|
||||
$formStartUrl = str_replace( 'index.php?/', '', \IPS\Http\Url\Friendly::fixComponentPath( $manifestDetails['start_url'] ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'manifest_custom_url_toggle', ( isset( $manifestDetails['start_url'] ) and empty( $formStartUrl ) ? FALSE : TRUE ), FALSE, array(
|
||||
'togglesOn' => array( 'manifest_short_url' ),
|
||||
), NULL, NULL, NULL, 'manifest_custom_url_toggle' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'manifest_short_url', $formStartUrl, FALSE, array(), function( $val )
|
||||
{
|
||||
if ( $val and \IPS\Request::i()->manifest_custom_url_toggle_checkbox )
|
||||
{
|
||||
if ( mb_substr( $val, -1 ) !== '/' )
|
||||
{
|
||||
$val .= '/';
|
||||
}
|
||||
|
||||
$response = \IPS\Http\Url::external( \IPS\Http\Url::baseUrl() . ( \IPS\Settings::i()->htaccess_mod_rewrite ? $val : 'index.php?/' . $val ) )->request( NULL, NULL, FALSE )->get();
|
||||
if ( $response->httpResponseCode != 200 and $response->httpResponseCode != 303 and ( \IPS\Settings::i()->site_online OR $response->httpResponseCode != 503 ) )
|
||||
{
|
||||
throw new \LogicException( 'pwa_start_url_incorrect' );
|
||||
}
|
||||
}
|
||||
}, \IPS\Http\Url::baseUrl() . ( !\IPS\Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ), NULL, 'manifest_short_url' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'manifest_themecolor', ( isset( $manifestDetails['theme_color'] ) ) ? $manifestDetails['theme_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_themecolor' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'manifest_bgcolor', ( isset( $manifestDetails['background_color'] ) ) ? $manifestDetails['background_color'] : NULL, FALSE, array(), NULL, NULL, NULL, 'manifest_bgcolor' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'manifest_display', ( isset( $manifestDetails['display'] ) ) ? $manifestDetails['display'] : 'standalone', FALSE, array( 'options' => array( 'fullscreen' => 'manifest_fullscreen', 'standalone' => 'manifest_standalone', 'minimal-ui' => 'manifest_minimalui', 'browser' => 'manifest_browser' ) ), NULL, NULL, NULL, 'manifest_display' ) );
|
||||
|
||||
if( $values = $form->values() )
|
||||
{
|
||||
$path = \IPS\Http\Url::createFromString( \IPS\Http\Url::baseUrl() )->data[ \IPS\Http\Url::COMPONENT_PATH ];
|
||||
$startUrl = $path ?? '';
|
||||
|
||||
if ( $values['manifest_custom_url_toggle'] !== FALSE and ! empty( $values['manifest_short_url'] ) )
|
||||
{
|
||||
$startUrl = '/' . trim( $values['manifest_short_url'], '/' ) . '/';
|
||||
|
||||
if( !empty( $path ) )
|
||||
{
|
||||
$startUrl = '/' . trim( $path . ( !\IPS\Settings::i()->htaccess_mod_rewrite ? 'index.php?/' : '' ) . ltrim( $values['manifest_short_url'], '/' ), '/' ) . '/';
|
||||
}
|
||||
}
|
||||
|
||||
/* Homescreen icon is the hardest part, as we need to generate different sizes.. */
|
||||
$values = static::processApplicationIcon( $values, $homeScreen, $homeScreenMaskable );
|
||||
|
||||
/* The start screen requires more different sizes so we'll rebuild that after submit */
|
||||
$rebuildStartScreen = FALSE;
|
||||
|
||||
if( $values['icons_apple_startup'] AND ( !isset( $apple['original'] ) OR !$apple['original'] OR (string) $values['icons_apple_startup'] != $apple['original'] ) )
|
||||
{
|
||||
$rebuildStartScreen = TRUE;
|
||||
}
|
||||
|
||||
if( ( !isset( $manifestDetails['background_color'] ) AND $values['manifest_bgcolor'] ) OR ( isset( $manifestDetails['background_color'] ) AND !$values['manifest_bgcolor'] ) OR ( isset( $manifestDetails['background_color'] ) AND $values['manifest_bgcolor'] != $manifestDetails['background_color'] ) )
|
||||
{
|
||||
if( $values['icons_apple_startup'] )
|
||||
{
|
||||
$rebuildStartScreen = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
$values = static::processAppleStartupScreen( $values, $apple );
|
||||
|
||||
/* We need the string value of this uploaded file as well */
|
||||
$values['icons_mask_icon'] = (string) $values['icons_mask_icon'];
|
||||
|
||||
/* Finally, handle the manifest details */
|
||||
$values['manifest_details'] = array();
|
||||
|
||||
if( $values['configure_manifest'] )
|
||||
{
|
||||
$values['manifest_details']['short_name'] = $values['manifest_shortname'];
|
||||
$values['manifest_details']['start_url'] = $startUrl;
|
||||
$values['manifest_details']['name'] = $values['manifest_fullname'];
|
||||
$values['manifest_details']['description'] = $values['manifest_description'];
|
||||
$values['manifest_details']['theme_color'] = $values['manifest_themecolor'];
|
||||
$values['manifest_details']['background_color'] = $values['manifest_bgcolor'];
|
||||
$values['manifest_details']['display'] = $values['manifest_display'];
|
||||
}
|
||||
|
||||
unset( $values['configure_manifest'], $values['manifest_shortname'], $values['manifest_fullname'], $values['manifest_description'], $values['manifest_display'], $values['manifest_bgcolor'], $values['manifest_themecolor'], $values['manifest_custom_url_toggle'], $values['manifest_short_url'] );
|
||||
|
||||
$values['manifest_details'] = json_encode( $values['manifest_details'] );
|
||||
|
||||
/* Save the settings */
|
||||
$form->saveAsSettings( $values );
|
||||
|
||||
/* Clear guest page caches */
|
||||
\IPS\Data\Cache::i()->clearAll();
|
||||
|
||||
/* Clear manifest and ie browser data stores */
|
||||
unset( \IPS\Data\Store::i()->manifest, \IPS\Data\Store::i()->iebrowserconfig );
|
||||
|
||||
/* And log */
|
||||
\IPS\Session::i()->log( 'acplogs__webapp' );
|
||||
|
||||
/* And Redirect */
|
||||
if( $rebuildStartScreen === TRUE )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $this->url->setQueryString( 'do', 'buildStartupScreenImages' ), 'saved' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $this->url, 'saved' );
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_settings_webapp');
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global' )->block( 'menu__core_settings_webapp', $form );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process application icon
|
||||
*
|
||||
* @param array $values Values from form submission
|
||||
* @param array $homeScreen Existing values, if any
|
||||
* @param array $homeScreenMaskable Existing values, if any
|
||||
* @return array
|
||||
*/
|
||||
public static function processApplicationIcon( $values, $homeScreen = array(), $homeScreenMaskable = array() )
|
||||
{
|
||||
if( ( isset( $values['icons_homescreen'] ) AND $values['icons_homescreen'] ) or ( isset( $values['icons_homescreen_maskable' ] ) AND $values['icons_homescreen_maskable'] ) )
|
||||
{
|
||||
foreach( [ 'icons_homescreen', 'icons_homescreen_maskable' ] as $type )
|
||||
{
|
||||
$setting = [];
|
||||
if( isset( $values[ $type ] ) AND $values[ $type ] )
|
||||
{
|
||||
$sizes = array(
|
||||
'android-chrome-36x36' => array(36, 36),
|
||||
'android-chrome-48x48' => array(48, 48),
|
||||
'android-chrome-72x72' => array(72, 72),
|
||||
'android-chrome-96x96' => array(96, 96),
|
||||
'android-chrome-144x144' => array(144, 144),
|
||||
'android-chrome-192x192' => array(192, 192),
|
||||
'android-chrome-256x256' => array(256, 256),
|
||||
'android-chrome-384x384' => array(384, 384),
|
||||
'android-chrome-512x512' => array(512, 512),
|
||||
'msapplication-square70x70logo' => array(128, 128),
|
||||
'msapplication-TileImage' => array(144, 144),
|
||||
'msapplication-square150x150logo' => array(270, 270),
|
||||
'msapplication-wide310x150logo' => array(558, 558),
|
||||
'msapplication-square310x310logo' => array(558, 270),
|
||||
'apple-touch-icon-57x57' => array(57, 57),
|
||||
'apple-touch-icon-60x60' => array(60, 60),
|
||||
'apple-touch-icon-72x72' => array(72, 72),
|
||||
'apple-touch-icon-76x76' => array(76, 76),
|
||||
'apple-touch-icon-114x114' => array(114, 114),
|
||||
'apple-touch-icon-120x120' => array(120, 120),
|
||||
'apple-touch-icon-144x144' => array(144, 144),
|
||||
'apple-touch-icon-152x152' => array(152, 152),
|
||||
'apple-touch-icon-180x180' => array(180, 180),
|
||||
);
|
||||
|
||||
$setting = array('original' => (string)$values[ $type ]);
|
||||
|
||||
foreach ( $sizes as $filename => $_sizes )
|
||||
{
|
||||
if ( $type == 'icons_homescreen_maskable' )
|
||||
{
|
||||
$filename .= "-masked";
|
||||
|
||||
if ( ! \mb_strstr( $filename, 'android-chrome' ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
$image = \IPS\Image::create( $values[ $type ]->contents() );
|
||||
|
||||
if ( $image::exifSupported() )
|
||||
{
|
||||
$image->setExifData( $values[ $type ]->contents() );
|
||||
}
|
||||
|
||||
$image->crop( $_sizes[0], $_sizes[1] );
|
||||
|
||||
$setting[$filename] = array(
|
||||
'url' => (string)\IPS\File::create( 'core_Icons', $filename . '.png', (string)$image, NULL, TRUE, NULL, FALSE ),
|
||||
'width' => $image->width,
|
||||
'height' => $image->height
|
||||
);
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$values[ $type ] = json_encode( $setting );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delete any images that may already exist */
|
||||
foreach( $homeScreen as $key => $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
foreach( $homeScreenMaskable as $key => $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
$values['icons_homescreen'] = '';
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Minimum padding on either side of startup image (in px)
|
||||
*/
|
||||
const MINIMUM_STARTUP_IMAGE_PADDING = 50;
|
||||
|
||||
/**
|
||||
* Process Apple startup screen images
|
||||
*
|
||||
* @param array $values Values from form submission
|
||||
* @param array $apple Existing values, if any
|
||||
* @return array
|
||||
*/
|
||||
public static function processAppleStartupScreen( $values, $apple = array() )
|
||||
{
|
||||
if( $values['icons_apple_startup'] )
|
||||
{
|
||||
$values['icons_apple_startup'] = json_encode( array( 'original' => (string) $values['icons_apple_startup'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Delete any images that may already exist */
|
||||
foreach( $apple as $key => $image )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $image : $image['url'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
|
||||
$values['icons_apple_startup'] = '';
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Apple startup screen images
|
||||
*
|
||||
* @param array $values Values from form submission
|
||||
* @param array $apple Existing values, if any
|
||||
* @return array
|
||||
*/
|
||||
public function buildStartupScreenImages()
|
||||
{
|
||||
$self = $this;
|
||||
|
||||
$multiRedirect = new \IPS\Helpers\MultipleRedirect(
|
||||
$this->url->setQueryString('do', 'buildStartupScreenImages'),
|
||||
function( $data )
|
||||
{
|
||||
/* Get the necessary data */
|
||||
$manifestDetails = json_decode( \IPS\Settings::i()->manifest_details, TRUE );
|
||||
$setting = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) ?? array();
|
||||
|
||||
if( isset( $setting['original'] ) )
|
||||
{
|
||||
$sizes = array(
|
||||
'apple-startup-1136x640' => array( 320, 568, 2, 'landscape' ),
|
||||
'apple-startup-2436x1125' => array( 375, 812, 3, 'landscape' ),
|
||||
'apple-startup-1792x828' => array( 414, 896, 2, 'landscape' ),
|
||||
'apple-startup-828x1792' => array( 414, 896, 2, 'portrait' ),
|
||||
'apple-startup-1334x750' => array( 375, 667, 2, 'landscape' ),
|
||||
'apple-startup-1242x2688' => array( 414, 896, 3, 'portrait' ),
|
||||
'apple-startup-2208x1242' => array( 414, 736, 3, 'landscape' ),
|
||||
'apple-startup-1125x2436' => array( 375, 812, 3, 'portrait' ),
|
||||
'apple-startup-1242x2208' => array( 414, 736, 3, 'portrait' ),
|
||||
'apple-startup-2732x2048' => array( 1024, 1366, 2, 'landscape' ),
|
||||
'apple-startup-2688x1242' => array( 414, 896, 3, 'landscape' ),
|
||||
'apple-startup-2224x1668' => array( 834, 1112, 2, 'landscape' ),
|
||||
'apple-startup-750x1334' => array( 375, 667, 2, 'portrait' ),
|
||||
'apple-startup-2048x2732' => array( 1024, 1366, 2, 'portrait' ),
|
||||
'apple-startup-2388x1668' => array( 834, 1194, 2, 'landscape' ),
|
||||
'apple-startup-1668x2224' => array( 834, 1112, 2, 'portrait' ),
|
||||
'apple-startup-640x1136' => array( 320, 568, 2, 'portrait' ),
|
||||
'apple-startup-1668x2388' => array( 834, 1194, 2, 'portrait' ),
|
||||
'apple-startup-2048x1536' => array( 768, 1024, 2, 'landscape' ),
|
||||
'apple-startup-1536x2048' => array( 768, 1024, 2, 'portrait' ),
|
||||
'apple-startup-2360x1640' => array( 1180, 820, 2, 'landscape' ),
|
||||
'apple-startup-1640x2360' => array( 1180, 820, 2, 'portrait' ),
|
||||
'apple-startup-2160x1620' => array( 1080, 810, 2, 'landscape' ),
|
||||
'apple-startup-1620x2160' => array( 1080, 810, 2, 'portrait' ),
|
||||
'apple-startup-2778x1284' => array( 428, 926, 3, 'landscape' ),
|
||||
'apple-startup-1284x2778' => array( 428, 926, 3, 'portrait' ),
|
||||
'apple-startup-2532x1170' => array( 390, 844, 3, 'landscape' ),
|
||||
'apple-startup-1170x2532' => array( 390, 844, 3, 'portrait' ),
|
||||
'apple-startup-2340x1080' => array( 360, 780, 3, 'landscape' ),
|
||||
'apple-startup-1080x2340' => array( 360, 780, 3, 'portrait' ),
|
||||
);
|
||||
|
||||
$file = \IPS\File::get( 'core_Icons', $setting['original'] );
|
||||
$originalContents = $file->contents();
|
||||
|
||||
$backgroundColor = ( isset( $manifestDetails['background_color'] ) ) ? str_replace( '#', '', $manifestDetails['background_color'] ) : 'FFFFFF';
|
||||
|
||||
$rgb = array();
|
||||
|
||||
if ( \strlen( $backgroundColor ) == 3 )
|
||||
{
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 0, 1 ) . \substr( $backgroundColor, 0, 1 ) ); // R
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 1, 1 ) . \substr( $backgroundColor, 1, 1 ) ); // G
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 2, 1 ) . \substr( $backgroundColor, 2, 1 ) ); // B
|
||||
}
|
||||
else
|
||||
{
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 0, 2 ) ); // R
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 2, 2 ) ); // G
|
||||
$rgb[] = hexdec( \substr( $backgroundColor, 4, 2 ) ); // B
|
||||
}
|
||||
|
||||
$did = 0;
|
||||
|
||||
foreach( $sizes as $filename => $_sizes )
|
||||
{
|
||||
$did++;
|
||||
|
||||
if( isset( $setting[ $filename ] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$width = ( $_sizes[3] == 'landscape' ) ? $_sizes[1] * $_sizes[2] : $_sizes[0] * $_sizes[2];
|
||||
$height = ( $_sizes[3] == 'portrait' ) ? $_sizes[1] * $_sizes[2] : $_sizes[0] * $_sizes[2];
|
||||
|
||||
$logoImage = \IPS\Image::create( $originalContents );
|
||||
$canvas = \IPS\Image::newImageCanvas( $width, $height, $rgb );
|
||||
|
||||
$logoImage->resizeToMax( $width - static::MINIMUM_STARTUP_IMAGE_PADDING, $height - static::MINIMUM_STARTUP_IMAGE_PADDING );
|
||||
|
||||
$xPos = ( $width - $logoImage->width ) / 2;
|
||||
$yPos = ( $height - $logoImage->height ) / 2;
|
||||
|
||||
$canvas->impose( $logoImage, $xPos, $yPos );
|
||||
|
||||
if( $canvas::exifSupported() )
|
||||
{
|
||||
$canvas->setExifData( $originalContents );
|
||||
}
|
||||
|
||||
$setting[ $filename ] = array(
|
||||
'url' => (string) \IPS\File::create( 'core_Icons', $filename . '.png', (string) $canvas, NULL, TRUE, NULL, FALSE ),
|
||||
'width' => $canvas->width,
|
||||
'height' => $canvas->height,
|
||||
'density' => $_sizes[2],
|
||||
'orientation' => $_sizes[3],
|
||||
);
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'apple-startup-image' );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Are we done? */
|
||||
if( $did == \count( $sizes ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'icons_apple_startup' => json_encode( $setting ) ) );
|
||||
}
|
||||
|
||||
return array( $data, \IPS\Member::loggedIn()->language()->addToStack('build_start_images_title'), ( $did ) ? round( ( 100 / \count( $sizes ) * $did ), 2 ) : 0 );
|
||||
},
|
||||
function() use( $self )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $self->url, 'completed' );
|
||||
}
|
||||
);
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('build_start_images_title');
|
||||
\IPS\Output::i()->output = $multiRedirect;
|
||||
}
|
||||
}
|
||||
@@ -114,39 +114,12 @@ class _badges extends \IPS\Dispatcher\Controller
|
||||
'list' => 'stats_badges_by_group',
|
||||
'member' => 'stats_badges_by_member',
|
||||
);
|
||||
|
||||
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'type';
|
||||
\IPS\Request::i()->tab ??= 'type';
|
||||
$activeTab = ( array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'type';
|
||||
|
||||
if ( $activeTab === 'type' )
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=badges&tab=' . $activeTab ), 'core_member_badges', 'datetime', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array('gridlines' => array('color' => '#f5f5f5')),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
),
|
||||
'AreaChart',
|
||||
'daily',
|
||||
array('start' => 0, 'end' => 0),
|
||||
array(),
|
||||
$activeTab
|
||||
);
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_badges_title' );
|
||||
$chart->availableTypes = array('AreaChart', 'ColumnChart', 'BarChart');
|
||||
$chart->enableHourly = FALSE;
|
||||
|
||||
$chart->groupBy = 'badge';
|
||||
|
||||
foreach ( \IPS\core\Achievements\Badge::roots() as $badge )
|
||||
{
|
||||
$chart->addSeries( $badge->_title, 'number', 'COUNT(*)', TRUE, $badge->id );
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_badges_title' );
|
||||
$chart->availableTypes = array('AreaChart', 'ColumnChart', 'BarChart');
|
||||
$chart->showIntervals = TRUE;
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Badges' )->getChart( \IPS\Http\Url::internal( 'app=core&module=stats&controller=badges&tab=' . $activeTab ) );
|
||||
}
|
||||
elseif ( $activeTab === 'member' )
|
||||
{
|
||||
|
||||
@@ -58,49 +58,7 @@ class _deviceusage extends \IPS\Dispatcher\Controller
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
|
||||
);
|
||||
|
||||
/* Determine minimum date */
|
||||
$minimumDate = NULL;
|
||||
|
||||
if( \IPS\Settings::i()->stats_device_usage_prune )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_device_usage_prune . 'D' ) );
|
||||
}
|
||||
|
||||
/* We can't retrieve any stats prior to the new tracking being implemented */
|
||||
try
|
||||
{
|
||||
$oldestLog = \IPS\Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'online_users' ) )->first();
|
||||
|
||||
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::ts( $oldestLog );
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* We have nothing tracked, set minimum date to today */
|
||||
$minimumDate = \IPS\DateTime::create();
|
||||
}
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=deviceusage' ), 'core_statistics', 'time', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'AreaChart', 'hourly' );
|
||||
|
||||
$chart->where[] = array( 'type=?', 'devices' );
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_deviceusage_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->enableHourly = TRUE;
|
||||
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_mobiles'), 'number', 'SUM(value_1)', TRUE );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_tablets'), 'number', 'SUM(value_2)', TRUE );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_consoles'), 'number', 'SUM(value_3)', TRUE );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_devices_desktops'), 'number', 'SUM(value_4)', TRUE );
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'DeviceUsage' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=deviceusage" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_deviceusage');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
|
||||
@@ -46,91 +46,14 @@ class _moderators extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=moderators'), 'core_moderator_logs', 'ctime', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'member_id', 'ctime' ), 'spam' );
|
||||
|
||||
$chart->groupBy = 'member_id';
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_moderator_activity_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
$chart->tableParsers = array(
|
||||
'ctime' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
/* Didn't find any specified? Do the default of the top 50 moderators */
|
||||
$where = array();
|
||||
if ( $chart->start instanceof \IPS\DateTime or $chart->end instanceof \IPS\DateTime )
|
||||
{
|
||||
$start = $chart->start instanceof \IPS\DateTime ? $chart->start->getTimestamp() : 0;
|
||||
$end = $chart->end instanceof \IPS\DateTime ? $chart->end->getTimestamp() : time();
|
||||
$where[] = array( 'ctime BETWEEN ? AND ?', $start, $end );
|
||||
}
|
||||
|
||||
/* Get actual moderators */
|
||||
$modMember = [];
|
||||
$modGroup = [];
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $mod )
|
||||
{
|
||||
if ( $mod['type'] == 'g' )
|
||||
{
|
||||
$modGroup[] = $mod['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$modMember[] = $mod['id'];
|
||||
}
|
||||
}
|
||||
|
||||
$query = [];
|
||||
|
||||
if ( \count( $modGroup ) )
|
||||
{
|
||||
$query[] = \IPS\Db::i()->in( 'member_group_id', $modGroup );
|
||||
$query[] = \IPS\Db::i()->findInSet( 'mgroup_others', $modGroup );
|
||||
}
|
||||
|
||||
if ( \count( $modMember ) )
|
||||
{
|
||||
$query[] = \IPS\Db::i()->in( 'member_id', $modMember );
|
||||
}
|
||||
|
||||
/* I mean $query should never be empty, but lets not wait for a ticket and have to release a patch to find out that it could be... */
|
||||
if ( \count( $query ) )
|
||||
{
|
||||
$where[] = [ 'member_id IN(?)', \IPS\Db::i()->select( 'member_id', 'core_members', implode( ' OR ', $query ) ) ];
|
||||
}
|
||||
|
||||
$topModerators = \IPS\Db::i()->select( 'member_id, COUNT(*) as _mod_count', 'core_moderator_logs', $where, '_mod_count DESC', 50, array( 'member_id' ) );
|
||||
|
||||
foreach ( $topModerators as $moderatorRow )
|
||||
{
|
||||
$member = \IPS\Member::load( $moderatorRow['member_id'] );
|
||||
$chart->addSeries(
|
||||
( $member->member_id ) ? $member->name : \IPS\Member::loggedIn()->language()->addToStack( 'deleted_member' ),
|
||||
'number',
|
||||
'COUNT(*)',
|
||||
TRUE,
|
||||
$moderatorRow['member_id']
|
||||
);
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
\IPS\Output::i()->output = (string) \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Moderators' )->getChart( \IPS\Http\Url::internal( 'app=core&module=stats&controller=moderators' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_moderators');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
\IPS\Output::i()->output = (string) \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Moderators' )->getChart( \IPS\Http\Url::internal( 'app=core&module=stats&controller=moderators' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,56 +58,7 @@ class _onlineusers extends \IPS\Dispatcher\Controller
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('prunesettings') )
|
||||
);
|
||||
|
||||
/* Determine minimum date */
|
||||
$minimumDate = NULL;
|
||||
|
||||
if( \IPS\Settings::i()->stats_online_users_prune )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Settings::i()->stats_online_users_prune . 'D' ) );
|
||||
}
|
||||
|
||||
/* We can't retrieve any stats prior to the new tracking being implemented */
|
||||
try
|
||||
{
|
||||
$oldestLog = \IPS\Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'online_users' ) )->first();
|
||||
|
||||
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$minimumDate = \IPS\DateTime::ts( $oldestLog );
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* We have nothing tracked, set minimum date to today */
|
||||
$minimumDate = \IPS\DateTime::create();
|
||||
}
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Callback(
|
||||
\IPS\Http\Url::internal( 'app=core&module=stats&controller=onlineusers' ),
|
||||
array( $this, 'getResults' ),
|
||||
'',
|
||||
array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
),
|
||||
'AreaChart',
|
||||
'none',
|
||||
array( 'start' => \IPS\DateTime::ts( time() - ( 60 * 60 * 24 * 30 ) ), 'end' => \IPS\DateTime::create() ),
|
||||
'',
|
||||
$minimumDate
|
||||
);
|
||||
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('members'), 'number' );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('guests'), 'number' );
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_onlineusers_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->showIntervals = FALSE;
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'OnlineUsers' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=onlineusers" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_onlineusers');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
@@ -132,50 +83,4 @@ class _onlineusers extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('prunesettings');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('global')->block( 'prunesettings', $form, FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the results
|
||||
*
|
||||
* @param \IPS\Helpers\Chart\Callback $chart Chart object
|
||||
* @return array
|
||||
*/
|
||||
public function getResults( $chart )
|
||||
{
|
||||
$where = array( array( 'type=?', 'online_users' ), array( "time>?", 0 ) );
|
||||
|
||||
if ( $chart->start )
|
||||
{
|
||||
$where[] = array( "time>?", $chart->start->getTimestamp() );
|
||||
}
|
||||
if ( $chart->end )
|
||||
{
|
||||
$where[] = array( "time<?", $chart->end->getTimestamp() );
|
||||
}
|
||||
|
||||
$results = array();
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_statistics', $where, 'time ASC' ) as $row )
|
||||
{
|
||||
if( !isset( $results[ $row['time'] ] ) )
|
||||
{
|
||||
$results[ $row['time'] ] = array(
|
||||
'time' => $row['time'],
|
||||
\IPS\Member::loggedIn()->language()->get('members') => 0,
|
||||
\IPS\Member::loggedIn()->language()->get('guests') => 0
|
||||
);
|
||||
}
|
||||
|
||||
if( $row['value_4'] == 'members' )
|
||||
{
|
||||
$results[ $row['time'] ][ \IPS\Member::loggedIn()->language()->get('members') ] = $row['value_1'];
|
||||
}
|
||||
|
||||
if( $row['value_4'] == 'guests' )
|
||||
{
|
||||
$results[ $row['time'] ][ \IPS\Member::loggedIn()->language()->get('guests') ] = $row['value_1'];
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
@@ -46,25 +46,7 @@ class _points extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=points' ), 'core_points_log', 'datetime', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e', '#ea7963', '#de6470', '#6b9dde' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'AreaChart', 'daily' );
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_points_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->enableHourly = FALSE;
|
||||
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_member_points'), 'number', 'SUM(points)', TRUE );
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_points_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart->showIntervals = TRUE;
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Points' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=points" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_points');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
}
|
||||
|
||||
@@ -45,66 +45,20 @@ class _preferences extends \IPS\Dispatcher\Controller
|
||||
'theme' => 'stats_member_pref_theme',
|
||||
'lang' => 'stats_member_pref_lang',
|
||||
);
|
||||
\IPS\Request::i()->tab ??= 'lang';
|
||||
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'lang';
|
||||
|
||||
switch( $activeTab )
|
||||
{
|
||||
case 'theme':
|
||||
|
||||
$chart = new \IPS\Helpers\Chart;
|
||||
$counts = iterator_to_array( \IPS\Db::i()->select( 'skin, COUNT(member_id) as count', 'core_members', array( "skin > ?", 0), NULL, NULL, "skin" )->setKeyField( 'skin' ) );
|
||||
|
||||
$chart->addHeader( "theme", "string" );
|
||||
$chart->addHeader( \IPS\Member::loggedIn()->language()->get('chart_members'), "number" );
|
||||
foreach( $counts as $id => $theme )
|
||||
{
|
||||
$chart->addRow( array( \IPS\Member::loggedIn()->language()->addToStack('core_theme_set_title_' . $id ), $theme['count'] ) );
|
||||
}
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Theme' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=preferences&tab=theme" ) );
|
||||
break;
|
||||
|
||||
case 'lang':
|
||||
|
||||
$chart = new \IPS\Helpers\Chart;
|
||||
$counts = iterator_to_array( \IPS\Db::i()->select( 'language, COUNT(member_id) as count', 'core_members', array( "language > ?", 0), NULL, NULL, "language" )->setKeyField( 'language' ) );
|
||||
|
||||
$chart->addHeader( "language", "string" );
|
||||
$chart->addHeader( \IPS\Member::loggedIn()->language()->get('chart_members'), "number" );
|
||||
|
||||
/* We need to make sure the language exists - otherwise apply the count to the default language. */
|
||||
$rows = [];
|
||||
foreach( $counts as $id => $lang )
|
||||
{
|
||||
try
|
||||
{
|
||||
$l = \IPS\Lang::load( $id );
|
||||
if ( !isset( $rows[ $id ] ) )
|
||||
{
|
||||
$rows[ $id ] = array( 'title' => $l->title, 'count' => 0 );
|
||||
}
|
||||
$rows[ $id ]['count'] += $lang['count'];
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
if ( !isset( $rows[ \IPS\Lang::defaultLanguage() ] ) )
|
||||
{
|
||||
$rows[ \IPS\Lang::defaultLanguage() ] = array( 'title' => \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->title, 'count' => 0 );
|
||||
}
|
||||
$rows[ \IPS\Lang::defaultLanguage() ]['count'] += $lang['count'];
|
||||
}
|
||||
}
|
||||
|
||||
/* Now add the rows to the chart */
|
||||
foreach( $rows AS $row )
|
||||
{
|
||||
$chart->addRow( array( $row['title'], $row['count'] ) );
|
||||
}
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Language' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=preferences&tab=lang" ) );
|
||||
break;
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_' . $activeTab . '_title');
|
||||
|
||||
$chart = $chart->render('PieChart', array(
|
||||
'backgroundColor' => '#ffffff',
|
||||
'pieHole' => 0.4,
|
||||
|
||||
@@ -46,26 +46,7 @@ class _rankprogression extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart;
|
||||
$chart->addHeader( "Rank", 'string' );
|
||||
$chart->addHeader( "Days", 'number' );
|
||||
|
||||
$data = \IPS\Db::i()->select( 'new_rank, AVG(time_to_new_rank) as time_to_rank', 'core_points_log', array('time_to_new_rank IS NOT NULL'), 'core_member_ranks.points ASC', NULL, ['new_rank'] );
|
||||
$data->join( 'core_member_ranks', 'core_member_ranks.id = core_points_log.new_rank' );
|
||||
|
||||
foreach ( $data as $row )
|
||||
{
|
||||
try
|
||||
{
|
||||
$rank = \IPS\core\Achievements\Rank::load( $row['new_rank'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$chart->addRow( array( $rank->_title, floor( $row['time_to_rank'] / 86400 ) ) );
|
||||
}
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'RankProgression' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=rankprogression" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_rankprogression');
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'stats' )->rankprogressionmessage();
|
||||
\IPS\Output::i()->output .= $chart->render( 'ScatterChart', array(
|
||||
|
||||
@@ -41,23 +41,8 @@ class _registrationstats extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/* Check permission */
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'registrations_manage', 'core', 'stats' );
|
||||
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=registrationstats' ), 'core_members', 'joined', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'colors' => array( '#10967e' ),
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
) );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('stats_new_registrations'), 'number', 'COUNT(*)', FALSE );
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_registrations_title');
|
||||
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
/* fetch only successful registered members ; if this needs to be changed, please review the other areas where we have the name<>? AND email<>? condition */
|
||||
$chart->where[] = array( 'completed=?', true );
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_registrationstats');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
\IPS\Output::i()->output = (string) \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Registrations' )->getChart( \IPS\Http\Url::internal( 'app=core&module=stats&controller=registrationstats' ) );
|
||||
}
|
||||
}
|
||||
@@ -47,31 +47,7 @@ class _spam extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=spam' ), 'core_spam_service_log', 'log_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'log_code', 'log_date' ), 'spam' );
|
||||
|
||||
$chart->groupBy = 'log_code';
|
||||
|
||||
foreach( array( 1,2,3,4 ) as $v )
|
||||
{
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('spam_service_action_stats_' . $v ), 'number', 'COUNT(*)', TRUE, $v );
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_spam_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
|
||||
$chart->tableParsers = array(
|
||||
'log_date' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'Spam' )->getChart( \IPS\Http\Url::internal( "app=core&module=stats&controller=spam" ) );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__core_stats_spam');
|
||||
\IPS\Output::i()->output = (string) $chart;
|
||||
|
||||
|
||||
@@ -51,52 +51,19 @@ class _warnings extends \IPS\Dispatcher\Controller
|
||||
'reason' => 'stats_warnings_reason',
|
||||
'suspended' => 'stats_warnings_suspended',
|
||||
);
|
||||
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'reason';
|
||||
|
||||
/* Make sure tab is set, otherwise saved charts may not show up when loading the page. */
|
||||
\IPS\Request::i()->tab ??= 'reason';
|
||||
$activeTab = ( array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'reason';
|
||||
|
||||
if ( $activeTab === 'reason' )
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=warnings&tab=' . $activeTab ), 'core_members_warn_logs', 'wl_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'wl_reason', 'wl_date' ), 'warnings' );
|
||||
|
||||
$chart->groupBy = 'wl_reason';
|
||||
|
||||
foreach( \IPS\core\Warnings\Reason::roots() as $reason )
|
||||
{
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('core_warn_reason_' . $reason->id ), 'number', 'COUNT(*)', TRUE, $reason->id );
|
||||
}
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_warnings_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'WarningReasons' )->getChart( \IPS\Http\Url::internal( 'app=core&module=stats&controller=warnings&tab=reason' ) );
|
||||
}
|
||||
else if ( $activeTab === 'suspended' )
|
||||
{
|
||||
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( 'app=core&module=stats&controller=warnings&tab=' . $activeTab ), 'core_members_warn_logs', 'wl_date', '', array(
|
||||
'isStacked' => TRUE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
|
||||
'lineWidth' => 1,
|
||||
'areaOpacity' => 0.4
|
||||
), 'LineChart', 'monthly', array( 'start' => 0, 'end' => 0 ), array( 'wl_reason', 'wl_date' ), 'warnings' );
|
||||
|
||||
$chart->where = array( 'wl_suspend IS NOT NULL' );
|
||||
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack('suspended' ), 'number', 'COUNT(*)', TRUE );
|
||||
|
||||
$chart->title = \IPS\Member::loggedIn()->language()->addToStack('stats_warnings_title');
|
||||
$chart->availableTypes = array( 'LineChart', 'AreaChart', 'ColumnChart', 'BarChart' );
|
||||
$chart = \IPS\core\Statistics\Chart::loadFromExtension( 'core', 'WarningSuspended' )->getChart( \IPS\Http\Url::internal( 'app=core&module=stats&controller=warnings&tab=suspended' ) );
|
||||
}
|
||||
|
||||
$chart->tableParsers = array(
|
||||
'wl_date' => function( $val )
|
||||
{
|
||||
return (string) \IPS\DateTime::ts( $val );
|
||||
}
|
||||
);
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
|
||||
@@ -107,7 +107,6 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
|
||||
\IPS\Log::log('Truncate table core_error_logs filed');
|
||||
}
|
||||
}
|
||||
@@ -119,7 +118,6 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
|
||||
\IPS\Log::log('Truncate table core_mail_error_logs filed');
|
||||
}
|
||||
}
|
||||
@@ -865,7 +863,7 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
->request()
|
||||
->get();
|
||||
|
||||
$headerKeys = array_map( 'mb_strtolower', array_keys( $request->httpHeaders ) );
|
||||
$headerKeys = \is_array( $request->httpHeaders ) ? array_map( 'mb_strtolower', array_keys( $request->httpHeaders ) ) : [];
|
||||
|
||||
if( \in_array( 'cf-cache-status', $headerKeys ) )
|
||||
{
|
||||
@@ -1649,6 +1647,8 @@ class _support extends \IPS\Dispatcher\Controller
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->get('health_error_log_title'), 'number', FALSE );
|
||||
$chart->addSeries( \IPS\Member::loggedIn()->language()->get('health_email_error_log_title'), 'number', FALSE );
|
||||
$chart->title = NULL;
|
||||
$chart->showFilterTabs = FALSE;
|
||||
$chart->showSave = FALSE;
|
||||
$chart->availableTypes = array( 'LineChart' );
|
||||
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
|
||||
Reference in new issue
Block a user