Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

@@ -0,0 +1,563 @@
<?php
/**
* @brief Popular things
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 21 Oct 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\discover;
/* 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;
}
/**
* Most popular things
*/
class _popular extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
/* Ensure that the rep system is enabled and the leaderboard is enabled */
if ( ! \IPS\Settings::i()->reputation_enabled or ! \IPS\Settings::i()->reputation_leaderboard_on )
{
\IPS\Output::i()->error( 'module_no_permission', '2C343/1', 403, '' );
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/search.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/leaderboard.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/search_responsive.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/leaderboard_responsive.css' ) );
}
/* Make sure default tab is first */
$tabs = array( \IPS\Settings::i()->reputation_leaderboard_default_tab );
foreach( array( 'leaderboard', 'history', 'members' ) as $addTab )
{
if ( $addTab != \IPS\Settings::i()->reputation_leaderboard_default_tab )
{
$tabs[] = $addTab;
}
}
$activeTab = ( isset( \IPS\Request::i()->tab ) and in_array(\IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : \IPS\Settings::i()->reputation_leaderboard_default_tab;
/* Initiate the breadcrumb */
\IPS\Output::i()->breadcrumb = array( array( \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=" . $activeTab, 'front', 'leaderboard_' . $activeTab ), \IPS\Member::loggedIn()->language()->addToStack('leaderboard_title') ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_tabs_' . $activeTab );
$content = $this->$activeTab();
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $content ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
}
else
{
/* Display */
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('popular')->tabs( $tabs, $activeTab, $content );
}
}
/**
* View top members
*
* @return void
*/
protected function members()
{
$filters = array(
'reputation' => array( 'pp_reputation_points', \IPS\Member::loggedIn()->language()->addToStack('leaderboard_tab_reputation') ),
'posts' => array( 'member_posts', \IPS\Member::loggedIn()->language()->addToStack('leaderboard_tab_posts') )
);
$classes = array();
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter', TRUE ) as $object )
{
$classes = array_merge( $object->classes, $classes );
}
foreach( $classes as $item )
{
$commentClass = NULL;
if ( isset( $item::$commentClass ) )
{
$commentClass = $item::$commentClass;
}
if ( $item::$firstCommentRequired and isset( $commentClass::$databaseColumnMap['author'] ) )
{
$filters[ 'app_' . $item::$application . '_' . $item::$module ] = array(
$commentClass,
\IPS\Member::loggedIn()->language()->addToStack('leaderboard_tab_x', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack("{$commentClass::$title}_pl_lc") ) ) ),
\IPS\Member::loggedIn()->language()->addToStack("{$commentClass::$title}_pl")
);
}
else if ( isset( $item::$databaseColumnMap['author'] ) )
{
$filters[ 'app_' . $item::$application . '_' . $item::$module ] = array(
$item,
\IPS\Member::loggedIn()->language()->addToStack('leaderboard_tab_x', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack("{$item::$title}_pl_lc") ) ) ),
\IPS\Member::loggedIn()->language()->addToStack("{$item::$title}_pl")
);
}
}
$activeFilter = ( isset( \IPS\Request::i()->filter ) and isset( $filters[ \IPS\Request::i()->filter ] ) ) ? \IPS\Request::i()->filter : 'reputation';
$members = array();
/* Get the members */
if ( mb_substr( $activeFilter, 0, 4 ) == 'app_' )
{
$storeKey = 'store_' . $activeFilter;
$recache = true;
$memberIds = NULL;
if ( isset( \IPS\Data\Store::i()->$storeKey ) )
{
$cache = \IPS\Data\Store::i()->$storeKey;
if ( isset( $cache['time'] ) and isset( $cache['memberIds'] ) and ( time() - $cache['time'] < 300 ) )
{
$memberIds = $cache['memberIds'];
}
}
/* Nothing returned from the cache, so fetch and store */
if ( $memberIds === NULL )
{
$class = $filters[ $activeFilter ][0];
$authorField = $class::$databasePrefix . $class::$databaseColumnMap['author'];
$memberIds = array();
$where = NULL;
if ( isset( $class::$databaseColumnMap['hidden'] ) )
{
$where = array( $class::$databasePrefix . $class::$databaseColumnMap['hidden'] . '=0' );
}
else if ( isset( $class::$databaseColumnMap['approved'] ) )
{
$where = array( $class::$databasePrefix . $class::$databaseColumnMap['approved'] . '=1' );
}
/* Get member IDS */
foreach( \IPS\Db::i()->select( 'COUNT(*) as count, ' . $class::$databaseTable . '.' . $authorField, $class::$databaseTable, $where, 'count DESC', array( 0, \IPS\Settings::i()->reputation_max_members ), $authorField ) as $row )
{
$memberIds[ $row[ $authorField ] ] = array( $row['count'] . '.' . $row[ $authorField ], $row['count'] );
}
\IPS\Data\Store::i()->$storeKey = array( 'time' => time(), 'memberIds' => $memberIds );
}
if ( count( $memberIds ) )
{
foreach( \IPS\Db::i()->select( '*', 'core_members', array( \IPS\Db::i()->in( 'member_id', array_keys( $memberIds ) ) ) ) as $member )
{
$members[ $memberIds[ $member['member_id'] ][0] ] = \IPS\Member::constructFromData( array_merge( $member, array( 'custom_count' => $memberIds[ $member['member_id'] ][1] ) ) );
}
krsort( $members );
}
}
else
{
$members = iterator_to_array( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( "name IS NOT NULL AND name != '' AND temp_ban != -1 AND email != '' AND " . $filters[ $activeFilter ][0] . " > 0" ), $filters[ $activeFilter ][0] . ' DESC', array( 0, \IPS\Settings::i()->reputation_max_members ) ), '\IPS\Member' ) );
}
$contentLabel = 'members_member_posts';
$contentCount = 'member_posts';
if ( isset( $filters[ $activeFilter ][2] ) )
{
$contentLabel = $filters[ $activeFilter ][2];
$contentCount = 'custom_count';
}
if ( \IPS\Request::i()->isAjax() and \IPS\Request::i()->topMembers )
{
\IPS\Output::i()->json( array( 'rows' => \IPS\Theme::i()->getTemplate('popular')->membersWrapper( $members, $contentLabel, $contentCount ), 'extraHtml' => $filters[ $activeFilter ][1] ) );
}
else
{
return \IPS\Theme::i()->getTemplate('popular')->members( $members, $filters, $activeFilter, \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=members", 'front', 'leaderboard_members' ), $contentLabel, $contentCount );
}
}
/**
* View past leaders
*
* @return void
*/
protected function history()
{
$table = new \IPS\Helpers\Table\Db( 'core_reputation_leaderboard_history', \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=history", 'front', 'leaderboard_history' ) );
$table->where = array( 'leader_position <= 3' );
$table->limit = 21;
$table->selects = array( 'leader_member_id, leader_position, leader_rep_total', 'ABS(leader_date - leader_position) as leader_date' );
$table->joins = array( array( 'select' => 'core_members.*', 'from' => 'core_members', 'where' => 'core_reputation_leaderboard_history.leader_member_id=core_members.member_id' ) );
$table->include = array( 'leader_member_id', 'leader_date', 'leader_position', 'leader_rep_total' );
$table->noSort = array( 'leader_member_id', 'leader_position', 'leader_rep_total' );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'popular', 'core', 'front' ), 'popularTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'popular', 'core', 'front' ), 'popularRows' );
$table->title = 'leaderboard_history';
$table->mainColumn = 'leader_date';
$table->sortBy = $table->sortBy ?: 'leader_date';
$table->sortDirection = $table->sortDirection ?: 'DESC';
/* Like or what? */
if ( \IPS\Settings::i()->reputation_point_types == 'like' )
{
\IPS\Member::loggedIn()->language()->words['leader_rep_total'] = \IPS\Member::loggedIn()->language()->addToStack( 'leader_rep_total_likes' );
\IPS\Member::loggedIn()->language()->words['leaderboard_history__desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_desc', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_likes') ) ) );
}
else
{
\IPS\Member::loggedIn()->language()->words['leader_rep_total'] = \IPS\Member::loggedIn()->language()->addToStack( 'leader_rep_total_rep' );
\IPS\Member::loggedIn()->language()->words['leaderboard_history__desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_desc', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_rep') ) ) );
}
/* Parsers */
$table->parsers = array(
'leader_member_id' => function( $val, $row )
{
return \IPS\Member::constructFromData( $row );
},
'leader_date' => function( $val )
{
return \IPS\DateTime::ts( $val )->setTimezone( new \DateTimeZone( \IPS\Settings::i()->reputation_timezone ) );
}
);
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $table ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
}
else
{
if ( $table->page > 1 )
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( \IPS\Output::i()->title, $table->page ) ) );
}
return (string) $table;
}
}
/**
* View Popular list
*
* It's slightly cumbersome because we need to group, but we can only select columns in the group list, so we have to:
* 1) Fetch the lookup_hash and total_rep
* 2) Fetch the rep data so we can...
* 3) Fetch the search engine data and then...
* 4) Manually sort in PHP
*
* @return void
*/
protected function leaderboard()
{
/* Figure out dates */
$dates = array();
$timezone = new \DateTimeZone( \IPS\Settings::i()->reputation_timezone );
$endDate = \IPS\DateTime::ts( time() )->setTimezone( $timezone );
$firstRepDate = \IPS\Db::i()->select( 'MIN(rep_date)', 'core_reputation_index' )->first();
$firstIndexDate = \IPS\Db::i()->select( 'MIN(index_date_updated)', 'core_search_index' )->first();
$appWhere = null;
$descApp = \IPS\Member::loggedIn()->language()->addToStack('leaderboard_in_all_apps');
$dates['oldest'] = \IPS\DateTime::ts( ( $firstRepDate > $firstIndexDate ) ? $firstRepDate : $firstIndexDate );
$oldestStamp = $dates['oldest']->getTimeStamp();
$date = $dates['oldest'];
$aYearAgo = \IPS\DateTime::create()->setTimezone( $timezone )->sub( new \DateInterval( 'P1Y' ) );
$month = \IPS\DateTime::create()->setTimezone( $timezone )->sub( new \DateInterval( 'P1M' ) )->setTime( 0, 0 );
$week = \IPS\DateTime::create()->setTimezone( $timezone )->sub( new \DateInterval( 'P7D' ) )->setTime( 0, 0 );
$today = \IPS\DateTime::create()->setTimezone( $timezone )->setTime( 0, 0 );
if ( $aYearAgo->getTimeStamp() > $oldestStamp )
{
$dates['year'] = $aYearAgo;
}
if ( $month->getTimeStamp() > $oldestStamp )
{
$dates['month'] = $month;
}
if ( $week->getTimeStamp() > $oldestStamp )
{
$dates['week'] = $week;
}
if ( $today->getTimeStamp() > $oldestStamp )
{
$dates['today'] = $today;
}
/* Got a date? */
if ( isset( \IPS\Request::i()->time ) and isset( $dates[ \IPS\Request::i()->time ] ) )
{
$date = $dates[ \IPS\Request::i()->time ];
}
else if ( isset( $dates['month'] ) )
{
/* Set the default to month */
\IPS\Request::i()->time = 'month';
$date = $dates['month'];
}
/* Applications */
$classes = array();
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter', TRUE ) as $object )
{
$classes = array_merge( $object->classes, $classes );
}
$areas = array();
foreach( $classes as $item )
{
$commentClass = NULL;
$reviewClass = NULL;
if ( in_array( 'IPS\Content\Reputation', class_implements( $item ) ) and isset( $item::$reputationType ) )
{
$areas[ $item::$application . '-' . $item::$reputationType ] = array( $item, \IPS\Member::loggedIn()->language()->addToStack("{$item::$title}_pl") );
}
if ( isset( $item::$commentClass ) )
{
$commentClass = $item::$commentClass;
if ( in_array( 'IPS\Content\Reputation', class_implements( $commentClass ) ) and isset( $commentClass::$reputationType ) )
{
$areas[ $item::$application . '-' . $commentClass::$reputationType ] = array( $commentClass, \IPS\Member::loggedIn()->language()->addToStack("{$commentClass::$title}_pl") );
}
}
if ( isset( $item::$reviewClass ) )
{
$reviewClass = $item::$reviewClass;
if ( in_array( 'IPS\Content\Reputation', class_implements( $reviewClass ) ) and isset( $reviewClass::$reputationType ) )
{
$areas[ $item::$application . '-' . $reviewClass::$reputationType ] = array( $reviewClass, \IPS\Member::loggedIn()->language()->addToStack("{$reviewClass::$title}_pl") );
}
}
}
$form = new \IPS\Helpers\Form('popular_date', 'continue');
$form->class = 'ipsForm_vertical';
$customStart = isset( \IPS\Request::i()->custom_date_start ) ? \IPS\Request::i()->custom_date_start : NULL;
$customEnd = isset( \IPS\Request::i()->custom_date_end ) ? \IPS\Request::i()->custom_date_end : NULL;
$form->add( new \IPS\Helpers\Form\DateRange( 'custom_date', array( 'start' => $customStart, 'end' => $customEnd ), FALSE, array( 'start' => array( 'min' => $dates['oldest'], 'time' => false ) ) ) );
if ( $values = $form->values() )
{
$url = \IPS\Request::i()->url()->stripQueryString('time');
if ( isset( $values['custom_date']['start'] ) and $values['custom_date']['start'] instanceof \IPS\DateTime )
{
$url = $url->setQueryString( 'custom_date_start', $values['custom_date']['start']->getTimeStamp() );
}
if ( isset( $values['custom_date']['end'] ) and $values['custom_date']['end'] instanceof \IPS\DateTime )
{
$url = $url->setQueryString( 'custom_date_end', $values['custom_date']['end']->getTimeStamp() );
}
\IPS\Output::i()->redirect( $url );
}
else
{
if ( $customStart )
{
$date = \IPS\DateTime::ts( $customStart )->setTimezone( $timezone )->setTime( 0, 0, 1 );
}
if ( $customEnd )
{
$endDate = \IPS\DateTime::ts( $customEnd )->setTimezone( $timezone )->setTime( 23, 59, 59 );
}
}
/* Got an app? */
$appWhere = '';
if ( isset( \IPS\Request::i()->in ) and isset( $areas[ \IPS\Request::i()->in ] ) )
{
$appWhere = " AND rep_class='" . \IPS\Db::i()->escape_string( $areas[ \IPS\Request::i()->in ][0] ) . "'";
$descApp = \IPS\Member::loggedIn()->language()->addToStack('leaderboard_in_app', NULL, array( 'sprintf' => array( $areas[ \IPS\Request::i()->in ][1] ) ) );
}
$storeKey = NULL;
$hashes = NULL;
if ( ! $customStart and ! $customEnd AND ! $appWhere )
{
$storeKey = 'leaderHashes_' . \IPS\Request::i()->time . '-' . md5( implode( ',', \IPS\Member::loggedIn()->groups ) );
if ( isset( \IPS\Data\Store::i()->$storeKey ) )
{
$stored = \IPS\Data\Store::i()->$storeKey;
if ( isset( $stored['hashes'] ) and isset( $stored['time'] ) and $stored['time'] > ( time() - 900 ) )
{
$hashes = $stored['hashes'];
}
}
}
/* Get hashes and total rep */
if ( $hashes === NULL )
{
/* Prevent race condition */
if ( $storeKey )
{
\IPS\Data\Store::i()->$storeKey = array( 'time' => time(), 'hashes' => array() );
}
$testFirst = iterator_to_array( \IPS\Db::i()->select( 'class_type_id_hash', 'core_reputation_index', array( 'rep_date BETWEEN ' . $date->getTimeStamp() . ' AND ' . $endDate->getTimeStamp() . $appWhere ), NULL, NULL, 'class_type_id_hash' ) );
$searchWhere = array( array( "( si.index_permissions = '*' OR " . \IPS\Db::i()->findInSet( 'si.index_permissions', \IPS\Member::loggedIn()->groups ) . ' AND si.index_hidden=0 )' ) );
if ( count( $testFirst ) < 501 )
{
/* We can use an IN() to make this a bit more efficient */
$repQuery = \IPS\Db::i()->select( 'class_type_id_hash, SUM(rep_rating) as total_rep', 'core_reputation_index', \IPS\Db::i()->in( 'class_type_id_hash', array_values( $testFirst ) ), NULL, NULL, 'class_type_id_hash' );
$searchWhere[] = array( \IPS\Db::i()->in( 'si.index_class_type_id_hash', array_values( $testFirst ) ) );
}
else
{
$repQuery = \IPS\Db::i()->select( 'class_type_id_hash, SUM(rep_rating) as total_rep', 'core_reputation_index', array( 'rep_date BETWEEN ' . $date->getTimeStamp() . ' AND ' . $endDate->getTimeStamp() . $appWhere ), NULL, NULL, 'class_type_id_hash' );
}
$searchQuery = \IPS\Db::i()->select( 'index_class_type_id_hash', array( 'core_search_index', 'si' ), $searchWhere );
$hashes = iterator_to_array(
\IPS\Db::i()->select( 'class_type_id_hash, total_rep', array( $repQuery, 'ri' ), array( 'class_type_id_hash IN(?)', $searchQuery ), 'total_rep DESC', array( 0, 50 ) )->setKeyField('class_type_id_hash')
);
if ( $storeKey )
{
\IPS\Data\Store::i()->$storeKey = array( 'time' => time(), 'hashes' => $hashes );
}
}
$classes = array();
$repData = array();
$or = array();
$results = array();
$preLoadMembers = array();
if ( count( $hashes ) )
{
/* Now get the reputation data */
foreach( \IPS\Db::i()->select( '*', 'core_reputation_index', array( \IPS\Db::i()->in( 'class_type_id_hash', array_keys( $hashes ) ) ) ) as $data )
{
$data['total_rep'] = $hashes[ $data['class_type_id_hash'] ]['total_rep'];
$repData[ $data['rep_class'] . '-' . $data['type_id'] ] = $data;
$classes[ $data['rep_class'] ][] = $data['type_id'];
if ( ! empty( $data['member_id'] ) )
{
$preLoadMembers[] = $data['member_id'];
}
}
foreach( $classes as $class => $ids )
{
$or[] = '( index_class=\'' . \IPS\Db::i()->escape_string( $class ) . '\' AND ' . \IPS\Db::i()->in( 'index_object_id', $ids ) . ')';
}
/* Construct the query */
$query = \IPS\Db::i()->select( '*', array( 'core_search_index', 'main' ), array( implode( ' OR ', $or ) ), NULL, NULL, NULL, NULL );
$array = iterator_to_array( $query );
$sorted = array();
/* Manually sort */
foreach( $array as $index => $data )
{
if ( isset( $repData[ $data['index_class'] . '-' . $data['index_object_id'] ] ) )
{
$data['rep_data'] = $repData[ $data['index_class'] . '-' . $data['index_object_id'] ];
$sorted[ $data['rep_data']['total_rep'] . '.' . $data['index_date_updated'] . '.'. $index ] = $data;
}
}
unset( $array );
krsort( $sorted, SORT_NUMERIC );
$results = new \IPS\Content\Search\Results( $sorted, count( $sorted ) );
/* Load data we need like the authors, etc */
$results->init();
}
/* Get top rated contributors */
$topContributors = array();
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', array( 'member_received>0 ' . $appWhere . ' and rep_date BETWEEN ' . intval( $date->getTimeStamp() ) . ' AND ' . intval( $endDate->getTimeStamp() ) ), NULL, NULL, 'member' );
foreach( \IPS\Db::i()->select( 'member, rep', array( $innerQuery, 'in' ), NULL, 'rep DESC', 4 )->setKeyField('member')->setValueField('rep') as $member => $rep )
{
$topContributors[ $member ] = $rep;
}
if ( count( $topContributors ) )
{
$preLoadMembers = array_merge( $preLoadMembers, array_keys( $topContributors ) );
}
/* Load their data */
if ( count( $preLoadMembers ) )
{
foreach ( \IPS\Db::i()->select( '*', 'core_members', \IPS\Db::i()->in( 'member_id', array_unique( $preLoadMembers ) ) ) as $member )
{
\IPS\Member::constructFromData( $member );
}
}
/* Work out the description for popular content */
if ( \IPS\Settings::i()->reputation_point_types == 'like' )
{
$popularResultsSingle = 'popular_results_single_desc';
$popularResultsMany = 'popular_results_desc';
}
else
{
$popularResultsSingle = 'popular_results_single_desc_rep';
$popularResultsMany = 'popular_results_desc_rep';
}
$description = \IPS\Member::loggedIn()->language()->addToStack( ( $date->localeDate() == $endDate->localeDate() ) ? $popularResultsSingle : $popularResultsMany, NULL, array( 'sprintf' => array( $date->localeDate(), $descApp ) ) );
/* Are our offsets different? */
$tzOffsetDifference = NULL;
try
{
if ( \IPS\DateTime::ts( time() )->getOffset() != \IPS\DateTime::ts( time() )->setTimezone( $timezone )->getOffset() )
{
$tzOffsetDifference = \IPS\DateTime::ts( time() )->setTimezone( $timezone )->format('P');
}
}
catch( \Exception $ex ) { }
/* Display */
return \IPS\Theme::i()->getTemplate('popular')->popularWrapper( $results, $areas, $topContributors, $dates, $description, $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) ), $tzOffsetDifference );
}
}
@@ -0,0 +1,80 @@
<?php
/**
* @brief rss
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 13 Oct 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\discover;
/* 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;
}
/**
* rss
*/
class _rss extends \IPS\Dispatcher\Controller
{
/**
* Display Feed
*
* @return void
*/
protected function manage()
{
try
{
$feed = \IPS\core\Rss::load( \IPS\Request::i()->id );
}
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C340/1', 404, '' );
}
if ( !$feed->_enabled )
{
\IPS\Output::i()->error( 'node_error_no_perm', '2C340/2', 403, '' );
}
/* Specific Member? */
if ( isset( \IPS\Request::i()->member_id ) AND isset( \IPS\Request::i()->key ) )
{
/* Load Member */
$member = \IPS\Member::load( \IPS\Request::i()->member_id );
/* Make sure we have an actual member, and that the key matches. If it doesn't, we can bubble up and see if the feed works for guests, and just use that */
if ( $member->member_id AND \IPS\Login::compareHashes( (string) \IPS\Request::i()->key, md5( $member->member_id . $member->email . $member->member_pass_hash . $member->member_pass_salt ) ) )
{
/* Make sure we have access to this feed. */
if ( $feed->groups == '*' OR $member->inGroup( $feed->groups ) )
{
/* Send It */
\IPS\Output::i()->sendOutput( $feed->generate( $member ), 200, 'text/xml' );
}
else
{
\IPS\Output::i()->error( 'node_error_no_perm', '2C340/3', 403, '' );
}
}
}
/* We're working with a guest. */
if ( $feed->groups == '*' OR in_array( \IPS\Settings::i()->guest_group, $feed->groups ) )
{
\IPS\Output::i()->sendOutput( $feed->generate(), 200, 'text/xml' );
}
else
{
\IPS\Output::i()->error( 'node_error_no_perm', '2C340/4', 403, '' );
}
}
}
@@ -2,9 +2,9 @@
/**
* @brief streams
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 02 Jul 2015
* @version SVN_VERSION_NUMBER
*/
@@ -30,13 +30,23 @@ class _streams extends \IPS\Dispatcher\Controller
*/
public function execute()
{
if ( isset( \IPS\Request::i()->_nodeSelectName ) )
{
return $this->getContainerNodeElement();
}
/* Initiate the breadcrumb */
\IPS\Output::i()->breadcrumb = array( array( \IPS\Http\Url::internal( "app=core&module=discovery&controller=streams", 'front', 'discover_all' ), \IPS\Member::loggedIn()->language()->addToStack('activity') ) );
\IPS\Output::i()->breadcrumb = array( array( \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ), \IPS\Member::loggedIn()->language()->addToStack('activity') ) );
/* Necessary CSS/JS */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_streams.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams_responsive.css', 'core', 'front' ) );
}
/* Execute */
return parent::execute();
}
@@ -49,11 +59,25 @@ class _streams extends \IPS\Dispatcher\Controller
protected function manage()
{
/* If this request is from an auto-poll, kill it and exit */
if ( !\IPS\Settings::i()->auto_polling_enabled && \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->after ) ){
if ( !\IPS\Settings::i()->auto_polling_enabled && \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->after ) )
{
\IPS\Output::i()->json( array( 'error' => 'auto_polling_disabled' ) );
return;
}
/* RSS validate? */
$member = NULL;
if ( isset( \IPS\Request::i()->rss ) )
{
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( !\IPS\Login::compareHashes( md5( ( $member->members_pass_hash ?: $member->email ) . $member->members_pass_salt ), (string) \IPS\Request::i()->key ) )
{
$member = NULL;
}
}
$form = NULL;
/* Viewing a particular stream? */
if ( isset( \IPS\Request::i()->id ) )
{
@@ -68,15 +92,15 @@ class _streams extends \IPS\Dispatcher\Controller
}
/* Suitable for guests? */
if ( ! \IPS\Member::loggedIn()->member_id and ! ( ( $stream->ownership == 'all' or $stream->ownership == 'custom' ) and $stream->read == 'all' and $stream->follow == 'all' and $stream->date_type != 'last_visit' ) )
if ( !\IPS\Member::loggedIn()->member_id and !$member and !( ( $stream->ownership == 'all' or $stream->ownership == 'custom' ) and $stream->read == 'all' and $stream->follow == 'all' and $stream->date_type != 'last_visit' ) )
{
\IPS\Output::i()->error( 'stream_no_permission', '2C280/3', 403, '' );
}
$baseUrl = $stream->url();
if ( \IPS\Member::loggedIn()->member_id and isset( \IPS\Request::i()->default ) )
{
\IPS\Session::i()->csrfCheck();
if ( \IPS\Request::i()->default )
{
\IPS\Member::loggedIn()->defaultStream = $stream->_id;
@@ -97,9 +121,10 @@ class _streams extends \IPS\Dispatcher\Controller
else
{
\IPS\Output::i()->json( array(
'url' => $defaultStream->url(),
'title' => $defaultStream->_title,
'id' => $defaultStream->_id
'url' => $defaultStream->url(),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'tooltip' => $defaultStream->_title, // We need to pass this individually for the tooltip that shows, but the JS itself will escape any entities
'id' => $defaultStream->_id
) );
}
}
@@ -107,27 +132,7 @@ class _streams extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( $stream->url() );
}
if ( isset( \IPS\Request::i()->form ) )
{
if ( \IPS\Request::i()->form == 'show' )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $this->_buildForm( $stream ), 200, 'text/html' );
}
else
{
\IPS\Output::i()->output = $this->_buildForm( $stream );
}
return;
}
else
{
/* We want to process the form */
$this->_buildForm( $stream );
}
}
$form = $this->_buildForm( $stream );
/* Set title and breadcrumb */
\IPS\Output::i()->breadcrumb[] = array( $stream->url(), $stream->_title );
@@ -139,6 +144,8 @@ class _streams extends \IPS\Dispatcher\Controller
{
if ( \IPS\Member::loggedIn()->member_id and isset( \IPS\Request::i()->default ) )
{
\IPS\Session::i()->csrfCheck();
if ( \IPS\Request::i()->default )
{
\IPS\Member::loggedIn()->defaultStream = 0;
@@ -159,43 +166,109 @@ class _streams extends \IPS\Dispatcher\Controller
else
{
\IPS\Output::i()->json( array(
'url' => \IPS\Http\Url::internal( "app=core&module=discovery&controller=streams", 'front', 'discover_all' ),
'title' => $defaultStream->_title,
'url' => \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'id' => $defaultStream->_id
) );
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=discovery&controller=streams", 'front', 'discover_all' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ) );
}
/* Start with a blank stream */
$stream = \IPS\core\Stream::allActivityStream();
$baseUrl = \IPS\Http\Url::internal( "app=core&module=discovery&controller=streams", 'front', 'discover_all' );
/* Set the title to "All Activity" */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('all_activity');
}
/* Changes from Update Only */
foreach ( array( 'include_comments', 'classes', 'containers', 'ownership', 'read', 'follow', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort' ) as $k )
{
if ( isset( \IPS\Request::i()->$k ) )
{
$stream->$k = \IPS\Request::i()->$k;
$baseUrl = $baseUrl->setQueryString( $k, \IPS\Request::i()->$k );
}
}
/* RSS validate? */
$member = NULL;
if ( isset( \IPS\Request::i()->rss ) )
/* Look for url params that can come from view switch or load more button */
/* but only if we haven't submitted the form on this request */
if( !\IPS\Request::i()->stream_submitted )
{
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( \IPS\Request::i()->key != md5( ( $member->members_pass_hash ?: $member->email ) . $member->members_pass_salt ) )
$streamFields = array( 'include_comments', 'classes', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' );
/* Build and format field values */
$_values = array();
foreach ( \IPS\Request::i() as $requestKey => $requestField )
{
$member = NULL;
$field = str_replace( 'stream_', '', $requestKey );
if ( $field == 'custom_members' and isset( \IPS\Request::i()->stream_custom_members ) )
{
$members = NULL;
foreach( explode( ',', \IPS\Request::i()->stream_custom_members ) as $name )
{
try
{
$members[] = \IPS\Member::load( $name, 'name' );
}
catch( \OutOfRangeException $e ) { }
}
$_values['stream_custom_members'] = $members;
}
else if ( in_array( $field, $streamFields ) && ( $field == 'classes' || $field == 'followed_types' ) && is_array( \IPS\Request::i()->{ 'stream_' . $field } ) )
{
/* Some array values will come in as key=1 params, so we only need the keys here */
$_values[ $requestKey ] = array_keys( $requestField );
}
else
{
$_values[ $requestKey ] = $requestField;
}
}
$formattedValues = $stream->formatFormValues( $_values );
/* Overwrite stream config if present in the request */
foreach ( $streamFields as $k )
{
$requestKey = 'stream_' . $k;
if ( isset( \IPS\Request::i()->$requestKey ) )
{
if ( $stream->$k != $formattedValues[ $k ] )
{
$stream->$k = $formattedValues[ $k ];
$stream->baseUrl = $stream->baseUrl->setQueryString( 'stream_' . $k, \IPS\Request::i()->$requestKey );
}
}
}
/* Containers are special */
if ( isset( \IPS\Request::i()->stream_containers ) and is_array( \IPS\Request::i()->stream_containers ) )
{
/* Remove null/'' values as we no longer want to restrict by container for this class if that occurs */
$cleanedContainers = array();
foreach( \IPS\Request::i()->stream_containers as $class => $containers )
{
if ( $containers )
{
$cleanedContainers[ $class ] = $containers;
}
}
if ( count( array_diff_assoc( $cleanedContainers, $stream::containersToUrl( $stream->containers ) ) ) )
{
$stream->containers = $stream::containersFromUrl( $cleanedContainers );
$stream->baseUrl = $stream->baseUrl->setQueryString( 'stream_containers', $cleanedContainers );
}
}
if ( isset( \IPS\Request::i()->id ) )
{
/* reset the form to account for all the modifications to $stream class variables */
$form = $this->_buildForm( $stream );
}
}
/* In order to make most streams more efficient, if we are looking at newest items first, and we haven't set a custom date, then just look for the last 12 months max */
if ( $stream->date_type == 'all' and $stream->sort == 'newest' )
{
$stream->date_relative_days = 365;
$stream->date_type = 'relative';
}
/* Build the query */
@@ -203,36 +276,62 @@ class _streams extends \IPS\Dispatcher\Controller
/* Set page or the before/after date */
$currentPage = 1;
if ( isset( \IPS\Request::i()->page ) )
if ( isset( \IPS\Request::i()->page ) AND intval( \IPS\Request::i()->page ) > 0 )
{
$currentPage = \IPS\Request::i()->page;
$query->setPage( $currentPage );
}
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->before ) )
$before = isset( \IPS\Request::i()->before ) ? \IPS\Request::i()->before : null;
$after = isset( \IPS\Request::i()->after ) ? \IPS\Request::i()->after : null;
/* If we sort by oldest, then we need to switch these values */
if ( $stream->sort == 'oldest' )
{
$tmp = $after;
$after = $before;
$before = $tmp;
unset( $tmp );
}
if ( isset( \IPS\Request::i()->latest ) )
{
if ( $stream->id and !$stream->include_comments )
{
$query->filterByLastUpdatedDate( NULL, \IPS\DateTime::ts( \IPS\Request::i()->before ) );
$query->filterByLastUpdatedDate( \IPS\DateTime::ts( \IPS\Request::i()->latest ) );
}
else
{
$query->filterByCreateDate( NULL, \IPS\DateTime::ts( \IPS\Request::i()->before ) );
$query->filterByCreateDate( \IPS\DateTime::ts( \IPS\Request::i()->latest ) );
}
$query->setLimit(350);
}
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->after ) )
else if ( $before )
{
if ( $stream->id and !$stream->include_comments )
{
$query->filterByLastUpdatedDate( \IPS\DateTime::ts( \IPS\Request::i()->after ) );
$query->filterByLastUpdatedDate( NULL, \IPS\DateTime::ts( $before ) );
}
else
{
$query->filterByCreateDate( \IPS\DateTime::ts( \IPS\Request::i()->after ) );
$query->filterByCreateDate( NULL, \IPS\DateTime::ts( $before ) );
}
}
if ( $after )
{
if ( $stream->id and !$stream->include_comments )
{
$query->filterByLastUpdatedDate( \IPS\DateTime::ts( $after ) );
}
else
{
$query->filterByCreateDate( \IPS\DateTime::ts( $after ) );
}
}
/* Get the results */
$results = $query->search( NULL, $stream->tags ? explode( ',', $stream->tags ) : NULL );
$results = $query->search( NULL, $stream->tags ? explode( ',', $stream->tags ) : NULL, ( $stream->include_comments ? \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY + \IPS\Content\Search\Query::TERM_OR_TAGS : \IPS\Content\Search\Query::TERM_OR_TAGS ) );
/* Load data we need like the authors, etc */
$results->init();
@@ -260,44 +359,45 @@ class _streams extends \IPS\Dispatcher\Controller
$view = 'expanded';
$streamID = ( \IPS\Request::i()->id ) ? \IPS\Request::i()->id : 'all';
if ( ( isset( \IPS\Request::i()->cookie['stream_view_' . $streamID] ) and \IPS\Request::i()->cookie['stream_view_' . $streamID] == 'condensed' ) or ( isset( \IPS\Request::i()->view ) and \IPS\Request::i()->view == 'condensed' ) )
if ( isset( \IPS\Request::i()->cookie['stream_view_' . $streamID] ) )
{
$view = 'condensed';
$view = \IPS\Request::i()->cookie['stream_view_' . $streamID];
}
else
{
$view = $stream->default_view;
}
/* If this is an AJAX request, just show the results */
if ( \IPS\Request::i()->isAjax() )
{
if( isset( \IPS\Request::i()->_changeView ) )
{
$output = \IPS\Theme::i()->getTemplate('streams')->stream( $stream, $results, !isset( \IPS\Request::i()->id ), true, $baseUrl, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
}
else
{
$output = \IPS\Theme::i()->getTemplate('streams')->streamItems( $results, true, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
}
$output = \IPS\Theme::i()->getTemplate('streams')->streamItems( $results, TRUE, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
$return = array(
'title' => $stream->_title,
'title' => htmlspecialchars( $stream->_title, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'blurb' => $stream->blurb(),
'config' => json_encode( $stream->config() ),
'count' => count( $results ),
'results' => $output,
'id' => ( $stream->id ) ? $stream->id : ''
'id' => ( $stream->id ) ? $stream->id : '',
'url' => $stream->url()
);
\IPS\Output::i()->json( $return );
\IPS\Output::i()->json( $return );
return;
}
/* Display - RSS */
if ( isset( \IPS\Request::i()->rss ) )
if ( \IPS\Settings::i()->activity_stream_rss and isset( \IPS\Request::i()->rss ) )
{
$document = \IPS\Xml\Rss::newDocument( $baseUrl, $stream->_title, sprintf( \IPS\Member::loggedIn()->language()->get( 'stream_rss_title' ), \IPS\Settings::i()->board_name, $stream->_title ) );
$document = \IPS\Xml\Rss::newDocument( $stream->baseUrl, $stream->_title, sprintf( \IPS\Member::loggedIn()->language()->get( 'stream_rss_title' ), \IPS\Settings::i()->board_name, $stream->_title ) );
foreach ( $results as $result )
{
$result->addToRssFeed( $document );
if ( $result instanceof \IPS\Content\Search\Result\Content )
{
$result->addToRssFeed( $document );
}
}
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml' );
@@ -309,25 +409,28 @@ class _streams extends \IPS\Dispatcher\Controller
{
/* What's the RSS Link? */
$rssLink = NULL;
if ( isset( \IPS\Request::i()->id ) )
if ( \IPS\Settings::i()->activity_stream_rss )
{
$rssLink = \IPS\Http\Url::internal( "app=core&module=discovery&controller=streams&id={$stream->id}", 'front', 'discover_rss' );
if ( \IPS\Member::loggedIn()->member_id )
if ( isset( \IPS\Request::i()->id ) )
{
$rssLink = $rssLink->setQueryString( 'member', \IPS\Member::loggedIn()->member_id );
if ( !\IPS\Member::loggedIn()->members_pass_salt )
$rssLink = \IPS\Http\Url::internal( "app=core&module=discover&controller=streams&id={$stream->id}", 'front', 'discover_rss' );
if ( \IPS\Member::loggedIn()->member_id )
{
\IPS\Member::loggedIn()->members_pass_salt = \IPS\Member::loggedIn()->generateSalt();
\IPS\Member::loggedIn()->save();
$rssLink = $rssLink->setQueryString( 'member', \IPS\Member::loggedIn()->member_id )->setQueryString( 'key', md5( ( \IPS\Member::loggedIn()->members_pass_hash ?: \IPS\Member::loggedIn()->email ) . \IPS\Member::loggedIn()->members_pass_salt ) );
}
$rssLink = $rssLink->setQueryString( 'key', md5( ( \IPS\Member::loggedIn()->members_pass_hash ?: \IPS\Member::loggedIn()->email ) . \IPS\Member::loggedIn()->members_pass_salt ) );
}
else
{
/* It's all activity! */
$rssLink = \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_rss_all_activity' );
}
}
/* Display */
$output = \IPS\Theme::i()->getTemplate('streams')->stream( $stream, $results, !isset( \IPS\Request::i()->id ), true, $baseUrl, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('streams')->streamWrapper( $stream, $output, ( isset( \IPS\Request::i()->id ) and ( !$stream->member or $stream->member == \IPS\Member::loggedIn()->member_id ) ) ? TRUE : FALSE, $rssLink, isset( \IPS\Request::i()->id ) and $stream->member and $stream->member != \IPS\Member::loggedIn()->member_id );
$output = \IPS\Theme::i()->getTemplate('streams')->stream( $stream, $results, $stream->id ? FALSE : TRUE, TRUE, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
\IPS\Output::i()->jsVars['stream_config'] = $stream->config();
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('streams')->streamWrapper( $stream, $output, $form, $rssLink, isset( \IPS\Request::i()->id ) and $stream->member and \IPS\Member::loggedIn()->member_id and $stream->member != \IPS\Member::loggedIn()->member_id );
}
}
@@ -338,13 +441,72 @@ class _streams extends \IPS\Dispatcher\Controller
*/
public function create()
{
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C280/A', 403, '' );
}
$stream = new \IPS\core\Stream;
$stream->member = \IPS\Member::loggedIn()->member_id;
$stream->default_view = 'expanded';
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'create_new_stream' );
\IPS\Output::i()->output = $this->_buildForm( $stream );
}
/**
* Edit a stream's title
*
* @return void
*/
public function edit()
{
\IPS\Session::i()->csrfCheck();
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C280/6', 403, '' );
}
try
{
$stream = \IPS\core\Stream::load( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C280/7', 404, '' );
}
if ( $stream->member != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_permission', '2C280/8', 403, '' );
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Text( 'stream_title', $stream->title ) );
if ( $values = $form->values() )
{
if ( isset( $values['stream_title'] ) and $values['stream_title'] )
{
$stream->title = $values['stream_title'];
$stream->save();
$this->_rebuildStreams();
\IPS\Output::i()->redirect( $stream->url() );
}
}
/* Output */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->genericBlock( $form, NULL, 'ipsPad' ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'stream_edit_title' );
\IPS\Output::i()->output = $form;
}
/**
* Copy a stream
*
@@ -352,6 +514,13 @@ class _streams extends \IPS\Dispatcher\Controller
*/
public function copy()
{
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C280/4', 403, '' );
}
\IPS\Session::i()->csrfCheck();
try
{
$stream = clone \IPS\core\Stream::load( \IPS\Request::i()->id );
@@ -361,7 +530,7 @@ class _streams extends \IPS\Dispatcher\Controller
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C280/3', 404, '' );
\IPS\Output::i()->error( 'node_error', '2C280/5', 404, '' );
}
\IPS\Output::i()->redirect( $stream->url() );
@@ -374,6 +543,11 @@ class _streams extends \IPS\Dispatcher\Controller
*/
public function delete()
{
\IPS\Session::i()->csrfCheck();
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$stream = \IPS\core\Stream::load( \IPS\Request::i()->id );
@@ -392,17 +566,54 @@ class _streams extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ) );
}
/**
* Get the container Node form element HTML
*
* @return string
*/
protected function getContainerNodeElement()
{
$currentContainers = array();
$stream = NULL;
if ( isset( \IPS\Request::i()->id ) )
{
$stream = \IPS\core\Stream::load( \IPS\Request::i()->id );
$currentContainers = $stream->containers ? json_decode( $stream->containers, TRUE ) : array();
if ( isset( \IPS\Request::i()->stream_containers ) )
{
$currentContainers = json_decode( $stream::containersFromUrl( \IPS\Request::i()->stream_containers ), TRUE );
}
}
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
{
$classes[ $class ] = $class::$title . '_pl';
if ( isset( $class::$containerNodeClass ) and $class == \IPS\Request::i()->className )
{
$url = $stream ? $stream->baseUrl->setQueryString( 'className', $class ) : \IPS\Request::i()->url()->setQueryString( 'className', $class );
$containerClass = $class::$containerNodeClass;
$field = new \IPS\Helpers\Form\Node( 'stream_containers_' . $class::$title, isset( $currentContainers[ $class ] ) ? $currentContainers[ $class ] : array(), NULL, array( 'url' => $url, 'class' => $class::$containerNodeClass, 'multiple' => TRUE, 'permissionCheck' => $containerClass::searchableNodesPermission() ), NULL, NULL, NULL, 'stream_containers_' . $class::$title );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( 'stream_narrow_by_container_label', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $containerClass::$nodeTitle ) ) ) );
return \IPS\Output::i()->json( array( 'node' => \IPS\Theme::i()->getTemplate('streams')->filterFormContentTypeContent( $field, $class, \IPS\Request::i()->key ) ) );
}
}
return NULL;
}
/**
* Build form
*
* @param \IPS\core\Stream $stream The stream
* @return string
*/
protected function _buildForm( \IPS\core\Stream $stream )
protected function _buildForm( \IPS\core\Stream &$stream )
{
/* Build form */
$form = new \IPS\Helpers\Form( 'select_blog', 'continue', ( $stream->id ? $stream->url() : NULL ) );
$form = new \IPS\Helpers\Form( 'stream', 'continue', ( $stream->id ? $stream->url() : NULL ) );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$stream->form( $form, 'Text', !$stream->id );
@@ -413,44 +624,62 @@ class _streams extends \IPS\Dispatcher\Controller
{
$form->hiddenValues['__custom_stream'] = TRUE;
}
if ( $stream->member )
{
$form->hiddenValues['__stream_owner'] = $stream->member;
}
$form->hiddenValues['stream_default_view'] = $stream->default_view;
/* Handle submissions */
if ( $values = $form->values() )
{
/* Update only */
if ( !$stream->member or isset( \IPS\Request::i()->updateOnly ) )
{
/* As the node container form elements are not in the actual form, we need to work some magic. And by magic, I do mean a sort of hacky thing. */
foreach ( \IPS\Request::i() as $k => $v )
{
$url = $stream->url();
$formattedValues = $stream->formatFormValues( $values );
foreach ( array( 'include_comments', 'classes', 'containers', 'ownership', 'read', 'follow', 'date_type', 'date_start', 'date_end', 'date_relative_days' ) as $k )
if ( mb_substr( $k, 0, 18 ) == 'stream_containers_' and $v )
{
if ( $stream->$k != $formattedValues[ $k ] )
$vals = explode( ',', $v );
$values[ $k ] = array_combine( $vals, $vals );
}
}
/* Update only */
if ( isset( \IPS\Request::i()->updateOnly ) )
{
$formattedValues = $stream->formatFormValues( $values );
foreach ( array( 'include_comments', 'classes', 'containers', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' ) as $k )
{
$requestKey = 'stream_' . $k;
if ( isset( $formattedValues[ $k ] ) AND $stream->$k != $formattedValues[ $k ] )
{
$url = $url->setQueryString( $k, $formattedValues[ $k ] );
$stream->$k = $formattedValues[ $k ];
$stream->baseUrl = $stream->baseUrl->setQueryString( 'stream_' . $k, \IPS\Request::i()->$requestKey );
}
}
\IPS\Output::i()->redirect( $url );
}
/* Update & Save */
else
{
{
if ( !$stream->id )
{
$stream->position = \IPS\Db::i()->select( 'MAX(position)', 'core_streams', array( 'member=?', \IPS\Member::loggedIn()->member_id ) )->first() + 1;
$redirectAfterSave = TRUE;
}
if ( count( $values['stream_classes'] ) )
else
{
$values['stream_classes_type'] = 1;
if ( !$stream->member or $stream->member != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2C280/9', 403, '' );
}
}
$stream->saveForm( $stream->formatFormValues( $values ) );
$this->_rebuildStreams();
if( $redirectAfterSave )
{
\IPS\Output::i()->redirect( $stream->url() );
@@ -459,7 +688,7 @@ class _streams extends \IPS\Dispatcher\Controller
}
/* Display */
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'streams', 'core' ) ), $stream->id ? ( $stream->member ? 'filterUpdateForm' : 'filterDuplicateForm' ) : 'filterCreateForm' ) );
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'streams', 'core' ) ), $stream->id ? 'filterInlineForm' : 'filterCreateForm' ) );
}
/**
@@ -470,7 +699,7 @@ class _streams extends \IPS\Dispatcher\Controller
protected function _rebuildStreams()
{
$default = \IPS\Member::loggedIn()->defaultStream;
\IPS\Member::loggedIn()->member_streams = json_encode( array( 'default' => $default, 'streams' => iterator_to_array( \IPS\Db::i()->select( 'id, title', 'core_streams', array( 'member=?', \IPS\Member::loggedIn()->member_id ) )->setKeyField('id')->setValueField('title') ) ) );
\IPS\Member::loggedIn()->member_streams = json_encode( array( 'default' => $default, 'streams' => iterator_to_array( \IPS\Db::i()->select( 'id, title', 'core_streams', array( 'member=?', \IPS\Member::loggedIn()->member_id ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->setKeyField('id')->setValueField('title') ) ) );
\IPS\Member::loggedIn()->save();
}
}