<?php
/**
* @brief streams
* @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 02 Jul 2015
*/
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;
}
/**
* streams
*/
class _streams extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
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=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()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_statuses.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();
}
/**
* View Stream
*
* @return void
*/
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 ) )
{
\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 ) )
{
/* Get it */
try
{
$stream = \IPS\core\Stream::load( \IPS\Request::i()->id );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C280/1', 404, '' );
}
/* Suitable for guests? */
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, '' );
}
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;
}
else
{
\IPS\Member::loggedIn()->defaultStream = NULL;
}
if ( \IPS\Request::i()->isAjax() )
{
$defaultStream = \IPS\core\Stream::defaultStream();
if ( ! $defaultStream )
{
\IPS\Output::i()->json( array( 'title' => NULL ) );
}
else
{
\IPS\Output::i()->json( array(
'url' => $defaultStream->url(),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | ENT_DISALLOWED, '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
) );
}
}
\IPS\Output::i()->redirect( $stream->url() );
}
$form = $this->_buildForm( $stream );
/* Set title and breadcrumb */
\IPS\Output::i()->breadcrumb[] = array( $stream->url(), $stream->_title );
\IPS\Output::i()->title = $stream->_title;
}
/* Or just everything? */
else
{
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;
}
else
{
\IPS\Member::loggedIn()->defaultStream = NULL;
}
if ( \IPS\Request::i()->isAjax() )
{
$defaultStream = \IPS\core\Stream::defaultStream();
if ( ! $defaultStream )
{
\IPS\Output::i()->json( array( 'title' => NULL ) );
}
else
{
\IPS\Output::i()->json( array(
'url' => \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ),
'id' => $defaultStream->_id
) );
}
}
\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();
$stream->default_view = "expanded";
/* Set the title to "All Activity" */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('all_activity');
}
/* 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 )
{
$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' );
/* Clubs enabled? */
if( \IPS\Settings::i()->clubs )
{
$streamFields[] = 'clubs';
}
/* Build and format field values */
$_values = array();
foreach ( \IPS\Request::i() as $requestKey => $requestField )
{
$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;
}
}
if ( isset( $_values['stream_club_filter'] ) and !isset( $_values['stream_club_select'] ) )
{
$_values['stream_club_select'] = 'select';
}
$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 ) or ( $k === 'clubs' and ( isset( \IPS\Request::i()->stream_club_select ) or isset( \IPS\Request::i()->stream_club_filter ) ) ) )
{
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 */
$query = $stream->query( $member );
/* Set page or the before/after date */
$currentPage = 1;
if ( isset( \IPS\Request::i()->page ) AND intval( \IPS\Request::i()->page ) > 0 )
{
$currentPage = \IPS\Request::i()->page;
$query->setPage( $currentPage );
}
$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( \IPS\DateTime::ts( \IPS\Request::i()->latest ) );
}
else
{
$query->filterByCreateDate( \IPS\DateTime::ts( \IPS\Request::i()->latest ) );
}
$query->setLimit(350);
}
else if ( $before )
{
if ( $stream->id and !$stream->include_comments )
{
$query->filterByLastUpdatedDate( NULL, \IPS\DateTime::ts( $before ) );
}
else
{
$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, ( $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();
/* Add in extra stuff? */
if ( !isset( \IPS\Request::i()->id ) )
{
/* Is anything turned on? */
$extra = array();
foreach ( array( 'register', 'follow_member', 'follow_content', 'photo', 'like', 'react', 'clubs' ) as $k )
{
$key = "all_activity_{$k}";
if ( \IPS\Settings::i()->$key )
{
$extra[] = $k;
}
}
if ( !empty( $extra ) )
{
$results = $results->addExtraItems( $extra, NULL, ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->after ) ) ? \IPS\DateTime::ts( \IPS\Request::i()->after ) : NULL, ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->before ) ) ? \IPS\DateTime::ts( \IPS\Request::i()->before ) : NULL );
}
}
/* Condensed or expanded? */
$view = 'expanded';
$streamID = ( \IPS\Request::i()->id ) ? \IPS\Request::i()->id : 'all';
if ( isset( \IPS\Request::i()->cookie['stream_view_' . $streamID] ) )
{
$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() )
{
$output = \IPS\Theme::i()->getTemplate('streams')->streamItems( $results, TRUE, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
$return = array(
'title' => htmlspecialchars( $stream->_title, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'blurb' => $stream->blurb(),
'config' => json_encode( $stream->config() ),
'count' => count( $results ),
'results' => $output,
'id' => ( $stream->id ) ? $stream->id : '',
'url' => $stream->url()
);
\IPS\Output::i()->json( $return );
return;
}
/* Display - RSS */
if ( \IPS\Settings::i()->activity_stream_rss and isset( \IPS\Request::i()->rss ) )
{
$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 )
{
if ( $result instanceof \IPS\Content\Search\Result\Content )
{
$result->addToRssFeed( $document );
}
}
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml' );
return;
}
/* Display - HTML */
else
{
/* What's the RSS Link? */
$rssLink = NULL;
if ( \IPS\Settings::i()->activity_stream_rss )
{
if ( isset( \IPS\Request::i()->id ) )
{
$rssLink = \IPS\Http\Url::internal( "app=core&module=discover&controller=streams&id={$stream->id}", 'front', 'discover_rss' );
if ( \IPS\Member::loggedIn()->member_id )
{
$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 ) );
}
}
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, $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 );
}
}
/**
* Create a new stream
*
* @return void
*/
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_module_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
*
* @return void
*/
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 );
$stream->member = \IPS\Member::loggedIn()->member_id;
$stream->save();
$this->_rebuildStreams();
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C280/5', 404, '' );
}
\IPS\Output::i()->redirect( $stream->url() );
}
/**
* Deletes a new stream
*
* @return void
*/
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 );
if ( !$stream->member or $stream->member != \IPS\Member::loggedIn()->member_id )
{
throw new \OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C280/2', 404, '' );
}
$stream->delete();
$this->_rebuildStreams();
\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(), 'clubs' => ( \IPS\Settings::i()->clubs AND \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) ) ), 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;
}
/**
* Get the club selector form element HTML
*
* @return string
*/
protected function getClubElement()
{
if( !\IPS\Settings::i()->clubs )
{
return \IPS\Output::i()->json( array( 'field' => '' ) );
}
$clubOptions = array();
foreach ( \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE ) as $club )
{
$clubOptions[ "c{$club->id}" ] = $club->name;
}
if ( isset( \IPS\Request::i()->stream_club_select ) )
{
switch ( \IPS\Request::i()->stream_club_select )
{
case 'all':
$value = 0;
break;
case 'none':
$value = array();
break;
default:
$value = explode( ',', \IPS\Request::i()->stream_club_filter );
break;
}
}
else
{
$value = 0;
}
$field = new \IPS\Helpers\Form\Select( 'stream_club_filter_dummy', $value, FALSE, array( 'options' => $clubOptions, 'parse' => 'normal', 'multiple' => TRUE, 'noDefault' => TRUE, 'unlimited' => 0, 'unlimitedLang' => 'stream_club_select_all' ), NULL, NULL, NULL, 'stream_club_filter' );
$field->label = \IPS\Member::loggedIn()->language()->addToStack('stream_club_filter');
return \IPS\Output::i()->json( array( 'field' => \IPS\Theme::i()->getTemplate('streams')->filterFormClubs( $field ) ) );
}
/**
* Build form
*
* @param \IPS\core\Stream $stream The stream
* @return string
*/
protected function _buildForm( \IPS\core\Stream &$stream )
{
/* Build form */
$form = new \IPS\Helpers\Form( 'stream', 'continue', ( $stream->id ? $stream->url() : NULL ) );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$stream->form( $form, 'Text', !$stream->id );
$redirectAfterSave = FALSE;
/* Note if it's custom */
if ( $stream->member && \IPS\Member::loggedIn()->member_id )
{
$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() )
{
/* 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. First, if we are editing a stream, we need to get our existing stream filters
and put these into an array. Then we loop over the input and overwrite the existing filters with what was submitted. If the user
never loaded the container filters we'll retain what we had (expected) but if they did and adjusted or removed container filters
then we'll update with what they submitted (expected).
*/
if( $stream->id )
{
$currentContainers = $stream->containers ? json_decode( $stream->containers, TRUE ) : array();
foreach( $currentContainers as $class => $containers )
{
$values['stream_containers_' . $class::$title ] = array_combine( $containers, $containers );
}
}
foreach ( \IPS\Request::i() as $k => $v )
{
if ( mb_substr( $k, 0, 18 ) == 'stream_containers_' )
{
if( $v )
{
$vals = explode( ',', $v );
$values[ $k ] = array_combine( $vals, $vals );
}
elseif( isset( $values[ $k ] ) )
{
$values[ $k ] = NULL;
}
}
}
/* Update only */
if ( isset( \IPS\Request::i()->updateOnly ) )
{
$formattedValues = $stream->formatFormValues( $values );
foreach ( array( 'include_comments', 'classes', 'containers', 'clubs', '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 ( array_key_exists( $k, $formattedValues ) AND $stream->$k != $formattedValues[ $k ] )
{
$stream->$k = $formattedValues[ $k ];
$stream->baseUrl = $stream->baseUrl->setQueryString( 'stream_' . $k, \IPS\Request::i()->$requestKey );
}
}
}
/* 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;
}
else
{
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() );
}
}
}
/* Display */
return $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'streams', 'core' ) ), $stream->id ? 'filterInlineForm' : 'filterCreateForm' ) );
}
/**
* Rebuild logged in member's streams
*
* @return void
*/
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 ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->setKeyField('id')->setValueField('title') ) ) );
\IPS\Member::loggedIn()->save();
}
}