Version 4.2.0

This commit is contained in:
Neo committed 2025-12-19 05:44:59 -08:00
1 parent 0dc2aee5ed
commit 96997ddd8e
2074 files changed
+125454 -55780

No files matched your search

@@ -0,0 +1,314 @@
<?php
/**
* @brief Clubs List
* @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 13 Feb 2017
*/
namespace IPS\core\modules\front\clubs;
/* 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;
}
/**
* Clubs List
*/
class _directory extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
/* Permission check */
if ( !\IPS\Settings::i()->clubs )
{
\IPS\Output::i()->error( 'no_module_permission', '2C349/2', 403, '' );
}
/* CSS */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/clubs.css', 'core', 'front' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/clubs_responsive.css', 'core', 'front' ) );
}
/* JS */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_clubs.js', 'core', 'front' ) );
/* Location for online list */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), array(), 'loc_clubs_directory' );
/* Pass up */
parent::execute();
}
/**
* List
*
* @return void
*/
protected function manage()
{
$baseUrl = \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' );
/* All Clubs: Sort */
$sortOption = \IPS\Settings::i()->clubs_default_sort;
if ( isset( \IPS\Request::i()->sort ) and in_array( \IPS\Request::i()->sort, array( 'last_activity', 'members', 'content', 'created', 'name' ) ) )
{
$sortOption = \IPS\Request::i()->sort;
}
/* All Clubs: Filters */
$filters = array();
$mineOnly = FALSE;
if ( isset( \IPS\Request::i()->filter ) and \IPS\Request::i()->filter === 'mine' )
{
$mineOnly = TRUE;
$baseUrl = $baseUrl->setQueryString( 'filter', 'mine' );
}
foreach ( \IPS\Member\Club\CustomField::fields() as $field )
{
$k = "f{$field->id}";
if ( $field->filterable and isset( \IPS\Request::i()->$k ) )
{
switch ( $field->type )
{
case 'Checkbox':
case 'YesNo':
if ( in_array( \IPS\Request::i()->$k, array( 0, 1 ) ) )
{
$filters[ $field->id ] = \IPS\Request::i()->$k;
$baseUrl = $baseUrl->setQueryString( 'f' . $field->id, \IPS\Request::i()->$k );
}
break;
case 'CheckboxSet':
case 'Radio':
case 'Select':
$options = json_decode( $field->extra, TRUE );
foreach ( \IPS\Request::i()->$k as $id )
{
if ( isset( $options[ $id ] ) )
{
$filters[ $field->id ][ $id ] = $options[ $id ];
}
}
$baseUrl = $baseUrl->setQueryString( 'f' . $field->id, array_keys( $filters[ $field->id ] ) );
break;
}
}
}
/* Get Featured Clubs */
$featuredClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'RAND()', FALSE, array(), 'featured=1' );
/* Get All Clubs */
$perPage = 24;
$page = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
$allClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), array( ( $page - 1 ) * $perPage, $perPage ), $sortOption, $mineOnly, $filters );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $allClubs->count( TRUE ) / $perPage ), $page, $perPage );
/* Get my clubs */
$myClubsActivity = NULL;
if ( \IPS\Member::loggedIn()->member_id )
{
$myClubsActivity = \IPS\Content\Search\Query::init()->filterByClub( \IPS\Member::loggedIn()->clubs() )->setLimit(6)->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_UPDATED )->search();
}
/* Build Map */
$mapMarkers = NULL;
if ( \IPS\Settings::i()->googlemaps and \IPS\Settings::i()->google_maps_api_key )
{
$mapMarkers = array();
$where = array( array( 'location_lat IS NOT NULL' ) );
if ( !\IPS\Member::loggedIn()->member_id )
{
$where[] = array( "type<>?", \IPS\Member\Club::TYPE_PRIVATE );
}
elseif ( !\IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$where[] = array( "( type<>? OR status IN('" . \IPS\Member\Club::STATUS_MEMBER . "','" . \IPS\Member\Club::STATUS_MODERATOR . "','" . \IPS\Member\Club::STATUS_LEADER . "') )", \IPS\Member\Club::TYPE_PRIVATE );
}
$select = \IPS\Db::i()->select( array( 'id', 'name', 'location_lat', 'location_long' ), 'core_clubs', $where );
if ( \IPS\Member::loggedIn()->member_id )
{
$select->join( 'core_clubs_memberships', array( 'club_id=id AND member_id=?', \IPS\Member::loggedIn()->member_id ) );
}
foreach ( $select as $club )
{
$mapMarkers[ $club['id'] ] = array(
'lat' => floatval( $club['location_lat'] ),
'long' => floatval( $club['location_long'] ),
'title' => $club['name']
);
}
}
if ( \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate('clubs')->myClubsSidebar( \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), 10, 'last_activity', TRUE ), $myClubsActivity );
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clubs')->directory( $featuredClubs, $allClubs, $pagination, $baseUrl, $sortOption, $myClubsActivity, $mapMarkers );
}
/**
* Filter Form
*
* @return void
*/
protected function filters()
{
$fields = \IPS\Member\Club\CustomField::roots();
$form = new \IPS\Helpers\Form('filter', 'filter');
if ( \IPS\Member::loggedIn()->member_id )
{
$form->add( new \IPS\Helpers\Form\Radio( 'club_filter_type', isset( \IPS\Request::i()->filter ) ? \IPS\Request::i()->filter : 'all', TRUE, array( 'options' => array(
'all' => 'all_clubs',
'mine' => 'my_clubs'
) ) ) );
}
foreach ( $fields as $field )
{
if ( $field->filterable )
{
$k = "f{$field->id}";
switch ( $field->type )
{
case 'Checkbox':
case 'YesNo':
$input = new \IPS\Helpers\Form\CheckboxSet( 'field_' . $field->id, isset( \IPS\Request::i()->$k ) ? \IPS\Request::i()->$k : array( 1, 0 ), FALSE, array( 'options' => array(
1 => 'yes',
0 => 'no',
) ) );
$input->label = $field->_title;
$form->add( $input );
break;
case 'CheckboxSet':
case 'Radio':
case 'Select':
$options = json_decode( $field->extra, TRUE );
$input = new \IPS\Helpers\Form\CheckboxSet( 'field_' . $field->id, isset( \IPS\Request::i()->$k ) ? \IPS\Request::i()->$k : array_keys( $options ), FALSE, array( 'options' => $options ) );
$input->label = $field->_title;
$form->add( $input );
break;
}
}
}
if ( $values = $form->values() )
{
$url = \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' );
if ( \IPS\Member::loggedIn()->member_id and $values['club_filter_type'] === 'mine' )
{
$url = $url->setQueryString( 'filter', 'mine' );
}
foreach ( $fields as $field )
{
if ( $field->filterable )
{
switch ( $field->type )
{
case 'Checkbox':
case 'YesNo':
if ( count( $values[ 'field_' . $field->id ] ) === 1 )
{
$url = $url->setQueryString( 'f' . $field->id, array_pop( $values[ 'field_' . $field->id ] ) );
}
break;
case 'CheckboxSet':
case 'Radio':
case 'Select':
$options = json_decode( $field->extra, TRUE );
if ( count( $values[ 'field_' . $field->id ] ) > 0 and count( $values[ 'field_' . $field->id ] ) < count( $options ) )
{
$url = $url->setQueryString( 'f' . $field->id, $values[ 'field_' . $field->id ] );
}
break;
}
}
}
\IPS\Output::i()->redirect( $url );
}
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
else
{
\IPS\Output::i()->output = $form;
}
}
/**
* Create
*
* @return void
*/
protected function create()
{
$availableTypes = array();
foreach ( explode( ',', \IPS\Member::loggedIn()->group['g_create_clubs'] ) as $type )
{
if ( $type !== '' )
{
$availableTypes[ $type ] = 'club_type_' . $type;
}
}
if ( !$availableTypes )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->member_id ? 'no_module_permission' : 'no_module_permission_guest', '2C349/1', 403, '' );
}
$club = new \IPS\Member\Club;
if ( $form = $club->form( FALSE, TRUE, $availableTypes ) )
{
$form->class = 'ipsForm_vertical';
}
else
{
if ( !$club->approved and \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$club->approved = TRUE;
$club->save();
}
\IPS\Output::i()->redirect( $club->url() );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('create_club');
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'clubs' )->create( $form );
}
}
}
File diff suppressed because it is too large. Load diff
@@ -1,12 +1,11 @@
<?php
/**
* @brief Contact Form
* @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
* @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 12 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\contact;
@@ -30,7 +29,7 @@ class _contact extends \IPS\Dispatcher\Controller
*/
public function execute()
{
if ( !static::canUseContactUs() )
if ( !\IPS\Member::loggedIn()->canUseContactUs() )
{
\IPS\Output::i()->error( 'no_permission', '2S333/1', 403, '' );
}
@@ -48,7 +47,8 @@ class _contact extends \IPS\Dispatcher\Controller
/* Get extensions */
$extensions = \IPS\Application::allExtensions( 'core', 'ContactUs', FALSE, 'core', 'InternalEmail', TRUE );
/* Don't let robots index this page, it has no value */
\IPS\Output::i()->metaTags['robots'] = 'noindex';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
@@ -100,46 +100,15 @@ class _contact extends \IPS\Dispatcher\Controller
}
}
/**
* Is the current user allowed to use the contact us form
* Can Use Contact Us
*
* @return bool
* @return bool
* @deprecated 4.3
*/
public static function canUseContactUs()
{
try
{
$module = \IPS\Application\Module::get( 'core', 'contact' );
}
catch ( \OutOfRangeException $e )
{
return FALSE;
}
if ( !\IPS\Member::loggedIn()->canAccessModule( $module ) )
{
return FALSE;
}
/* If all groups have access, we can */
if( \IPS\Settings::i()->contact_access != '*' )
{
/* Check member */
$member = \IPS\Member::loggedIn();
$memberGroups = array_merge( array( $member->member_group_id ), array_filter( explode( ',', $member->mgroup_others ) ) );
$accessGroups = explode( ',', \IPS\Settings::i()->contact_access );
/* Are we in an allowed group? */
if( count( array_intersect( $accessGroups, $memberGroups ) ) )
{
return TRUE;
}
else
{
return FALSE;
}
}
return TRUE;
return \IPS\Member::loggedIn()->canUseContactUs();
}
}
@@ -1,12 +1,11 @@
<?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
* @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 21 Oct 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\discover;
@@ -83,120 +82,44 @@ class _popular extends \IPS\Dispatcher\Controller
*/
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 )
/* Get filters */
$filters = array_merge( array( 'overview' => \IPS\Member::loggedIn()->language()->addToStack('overview') ), \IPS\Member::topMembersOptions( \IPS\Member::TOP_MEMBERS_FILTERS ) );
$activeFilter = 'overview';
if ( isset( \IPS\Request::i()->filter ) )
{
$classes = array_merge( $object->classes, $classes );
}
foreach( $classes as $item )
{
$commentClass = NULL;
if ( isset( $item::$commentClass ) )
if ( array_key_exists( \IPS\Request::i()->filter, $filters ) )
{
$commentClass = $item::$commentClass;
$activeFilter = \IPS\Request::i()->filter;
}
if ( $item::$firstCommentRequired and isset( $commentClass::$databaseColumnMap['author'] ) )
else
{
$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")
);
$possibleFilter = 'IPS\\' . str_replace( '_', '\\', \IPS\Request::i()->filter );
if ( array_key_exists( $possibleFilter, $filters ) )
{
$activeFilter = $possibleFilter;
}
}
}
$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_' )
/* Get results */
if ( $activeFilter == 'overview' )
{
$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 );
}
$output = \IPS\Theme::i()->getTemplate('popular')->topMembersOverview( \IPS\Member::topMembersOptions( \IPS\Member::TOP_MEMBERS_OVERVIEW ) );
}
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' ) );
$output = \IPS\Theme::i()->getTemplate('popular')->topMembersResults( $activeFilter, NULL, \IPS\Member::topMembers( $activeFilter, \IPS\Settings::i()->reputation_max_members ) );
}
$contentLabel = 'members_member_posts';
$contentCount = 'member_posts';
if ( isset( $filters[ $activeFilter ][2] ) )
{
$contentLabel = $filters[ $activeFilter ][2];
$contentCount = 'custom_count';
}
/* Output */
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=members", 'front', 'leaderboard_members' );
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] ) );
\IPS\Output::i()->json( array( 'rows' => $output, 'extraHtml' => $filters[ $activeFilter ] ) );
}
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 );
return \IPS\Theme::i()->getTemplate('popular')->topMembers( \IPS\Http\Url::internal( 'app=core&module=discover&controller=popular&tab=members', 'front', 'leaderboard_members' ), $filters, $activeFilter, $output );
}
}
@@ -244,7 +167,7 @@ class _popular extends \IPS\Dispatcher\Controller
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 );
@@ -277,111 +200,111 @@ class _popular extends \IPS\Dispatcher\Controller
$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'];
$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;
$dates[ 'year' ] = $aYearAgo;
}
if ( $month->getTimeStamp() > $oldestStamp )
{
$dates['month'] = $month;
$dates[ 'month' ] = $month;
}
if ( $week->getTimeStamp() > $oldestStamp )
{
$dates['week'] = $week;
$dates[ 'week' ] = $week;
}
if ( $today->getTimeStamp() > $oldestStamp )
{
$dates['today'] = $today;
$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'] ) )
else if ( isset( $dates[ 'month' ] ) )
{
/* Set the default to month */
\IPS\Request::i()->time = 'month';
$date = $dates['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 )
foreach ( $classes as $item )
{
$commentClass = NULL;
$reviewClass = NULL;
if ( in_array( 'IPS\Content\Reputation', class_implements( $item ) ) and isset( $item::$reputationType ) )
if ( \IPS\IPS::classUsesTrait( $item, 'IPS\Content\Reactable' ) )
{
$areas[ $item::$application . '-' . $item::$reputationType ] = array( $item, \IPS\Member::loggedIn()->language()->addToStack("{$item::$title}_pl") );
$areas[ $item::$application . '-' . $item::reactionType() ] = 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 ) )
if ( \IPS\IPS::classUsesTrait( $commentClass, 'IPS\Content\Reactable' ) )
{
$areas[ $item::$application . '-' . $commentClass::$reputationType ] = array( $commentClass, \IPS\Member::loggedIn()->language()->addToStack("{$commentClass::$title}_pl") );
$areas[ $item::$application . '-' . $commentClass::reactionType() ] = 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 ) )
if ( \IPS\IPS::classUsesTrait( $reviewClass, 'IPS\Content\Reactable' ) )
{
$areas[ $item::$application . '-' . $reviewClass::$reputationType ] = array( $reviewClass, \IPS\Member::loggedIn()->language()->addToStack("{$reviewClass::$title}_pl") );
$areas[ $item::$application . '-' . $reviewClass::reactionType() ] = array( $reviewClass, \IPS\Member::loggedIn()->language()->addToStack( "{$reviewClass::$title}_pl" ) );
}
}
}
$form = new \IPS\Helpers\Form('popular_date', 'continue');
$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 ) ) ) );
$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 = \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() );
$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 )
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() );
$url = $url->setQueryString( 'custom_date_end', $values[ 'custom_date' ][ 'end' ]->getTimeStamp() );
}
\IPS\Output::i()->redirect( $url );
}
else
@@ -390,20 +313,30 @@ class _popular extends \IPS\Dispatcher\Controller
{
$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] ) ) );
$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 ] ) ) );
}
else
{
$repAreas = array();
foreach( $areas as $area )
{
$repAreas[] = $area[0] ;
}
$appWhere = " AND " . \IPS\Db::i()->in( 'rep_class', $repAreas );
}
$storeKey = NULL;
@@ -432,27 +365,16 @@ class _popular extends \IPS\Dispatcher\Controller
\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 )' ) );
/* Get rep hashes */
$inner = \IPS\Db::i()->select( 'class_type_id_hash, SUM(rep_rating) as total_rep', array( 'core_reputation_index', 'x' ), array( 'rep_date BETWEEN ' . $date->getTimeStamp() . ' AND ' . $endDate->getTimeStamp() . $appWhere ), NULL, NULL, 'class_type_id_hash' );
$repHashes = iterator_to_array( \IPS\Db::i()->select( 'class_type_id_hash, total_rep', $inner, NULL, 'x.total_rep desc', array( 0, 500 ) )->setKeyField('class_type_id_hash') );
/* Now filter through permissions */
$searchHashes = iterator_to_array( \IPS\Db::i()->select( 'index_class_type_id_hash', array( 'core_search_index', 'si' ), array( array( "( si.index_permissions = '*' OR " . \IPS\Db::i()->findInSet( 'si.index_permissions', \IPS\Member::loggedIn()->groups ) . ' AND si.index_hidden=0 )' ), array( \IPS\Db::i()->in( 'si.index_class_type_id_hash', array_keys( $repHashes ) ) ) ) )->setKeyField('index_class_type_id_hash') );
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' );
}
/* Filter out rep hashes not in search results */
$hashes = array_slice( array_intersect_key( $repHashes, $searchHashes ), 0, 50 );
$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 );
@@ -557,6 +479,8 @@ class _popular extends \IPS\Dispatcher\Controller
}
catch( \Exception $ex ) { }
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=leaderboard", 'front', 'leaderboard_leaderboard' );
/* 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 );
}
@@ -1,13 +1,12 @@
<?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
* @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 13 Oct 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\discover;
@@ -1,12 +1,11 @@
<?php
/**
* @brief streams
* @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
* @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
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\discover;
@@ -178,6 +177,7 @@ class _streams extends \IPS\Dispatcher\Controller
/* 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');
@@ -187,7 +187,7 @@ class _streams extends \IPS\Dispatcher\Controller
/* 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' );
$streamFields = array( 'include_comments', 'classes', 'clubs', '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();
@@ -220,6 +220,11 @@ class _streams extends \IPS\Dispatcher\Controller
}
}
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 */
@@ -227,7 +232,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
$requestKey = 'stream_' . $k;
if ( isset( \IPS\Request::i()->$requestKey ) )
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 ] )
{
@@ -341,7 +346,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
/* Is anything turned on? */
$extra = array();
foreach ( array( 'register', 'follow_member', 'follow_content', 'photo', 'like', 'rep_neg' ) as $k )
foreach ( array( 'register', 'follow_member', 'follow_content', 'photo', 'like', 'react', 'clubs' ) as $k )
{
$key = "all_activity_{$k}";
if ( \IPS\Settings::i()->$key )
@@ -594,7 +599,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
$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 = 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\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 ) ) );
@@ -604,6 +609,47 @@ class _streams extends \IPS\Dispatcher\Controller
return NULL;
}
/**
* Get the club selector form element HTML
*
* @return string
*/
protected function getClubElement()
{
$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
*
@@ -650,7 +696,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
$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 )
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 ( isset( $formattedValues[ $k ] ) AND $stream->$k != $formattedValues[ $k ] )
@@ -1,12 +1,11 @@
<?php
/**
* @brief Profile
* @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
* @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 19 Jul 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\members;
@@ -171,6 +170,12 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
/* What tabs are available? */
$tabs = array( 'activity' => 'users_activity_feed' );
if ( \IPS\Settings::i()->clubs )
{
$tabs['clubs'] = 'users_clubs';
}
foreach( $mainFields as $group => $fields )
{
foreach( $fields as $field => $value )
@@ -262,6 +267,27 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$tabContents = \IPS\Theme::i()->getTemplate( 'profile' )->profileActivity( $this->member, $latestActivity, $statusForm );
}
elseif ( $tab == 'clubs' )
{
if ( !\IPS\Settings::i()->clubs )
{
\IPS\Output::i()->error( 'no_module_permission', '2C138/J', 403, '' );
}
/* Get All User Clubs */
$baseUrl = \IPS\Request::i()->url()->setQueryString('tab', 'clubs');
$perPage = 24;
$page = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
$allClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), array( ( $page - 1 ) * $perPage, $perPage ), 'last_activity', $this->member );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $allClubs->count( TRUE ) / $perPage ), $page, $perPage );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/clubs.css', 'core', 'front' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/clubs_responsive.css', 'core', 'front' ) );
}
$tabContents = \IPS\Theme::i()->getTemplate( 'profile' )->profileClubs( $this->member, $allClubs, $pagination );
}
elseif ( mb_substr( $tab, 0, 6 ) == 'field_' )
{
$fieldId = mb_substr( $tab, 6 );
@@ -344,6 +370,39 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
$addWarningUrl = $addWarningUrl->setQueryString( 'ref', \IPS\Request::i()->wr );
}
/* Set JSON-LD output */
\IPS\Output::i()->jsonLd['profile'] = array(
'@context' => "http://schema.org",
'@type' => "ProfilePage",
'url' => (string) $this->member->url(),
'name' => htmlspecialchars( $this->member->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'primaryImageOfPage' => array(
'@type' => "ImageObject",
'contentUrl' => (string) $this->member->get_photo(),
'representativeOfPage' => true,
'thumbnail' => array(
'@type' => "ImageObject",
'contentUrl' => (string) $this->member->get_photo( TRUE ),
)
),
'thumbnailUrl' => (string) $this->member->get_photo( TRUE ),
'image' => (string) $this->member->get_photo(),
'relatedLink' => (string) \IPS\Http\Url::internal( "app=core&module=members&controller=profile&do=content&id={$this->member->member_id}", "front", "profile_content", array( $this->member->members_seo_name ) ),
'dateCreated' => $this->member->joined->format( \IPS\DateTime::ISO8601 ),
'interactionStatistic' => array(
array(
"@type" => "InteractionCounter",
"interactionType" => "http://schema.org/CommentAction",
'userInteractionCount' => $this->member->member_posts
),
array(
"@type" => "InteractionCounter",
"interactionType" => "http://schema.org/ViewAction",
'userInteractionCount' => $this->member->members_profile_views
),
),
);
/* Output */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_profile.js', 'core' ) );
@@ -507,7 +566,8 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
else
{
/* Display */
$title = ( isset( \IPS\Request::i()->page ) and \IPS\Request::i()->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $this->member->name, \IPS\Request::i()->page ) ) ) : $this->member->name;
$profileTitle = \IPS\Member::loggedIn()->language()->addToStack( 'members_content', FALSE, array( 'sprintf' => array( $this->member->name ) ) );
$title = ( isset( \IPS\Request::i()->page ) and \IPS\Request::i()->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $profileTitle, \IPS\Request::i()->page ) ) ) : $profileTitle;
\IPS\Output::i()->title = $title;
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/statuses.css' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userContent( $this->member, $types, $currentAppModule, $currentType, (string) $output );
@@ -533,22 +593,22 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'profile.css', $class::$application ) );
if ( in_array( 'IPS\Content\Reputation', class_implements( $class ) ) )
if ( \IPS\IPS::classUsesTrait( $class, 'IPS\Content\Reactable' ) )
{
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ) ] = $class;
}
if ( isset( $class::$commentClass ) and in_array( 'IPS\Content\Reputation', class_implements( $class::$commentClass ) ) )
if ( isset( $class::$commentClass ) and \IPS\IPS::classUsesTrait( $class::$commentClass, 'IPS\Content\Reactable' ) )
{
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class::$commentClass, 4 ) ) ) ] = $class::$commentClass;
}
if ( isset( $class::$reviewClass ) and in_array( 'IPS\Content\Reputation', class_implements( $class::$reviewClass ) ) )
if ( isset( $class::$reviewClass ) and \IPS\IPS::classUsesTrait( $class::$reviewClass, 'IPS\Content\Reactable' ) )
{
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class::$reviewClass, 4 ) ) ) ] = $class::$reviewClass;
}
}
/* What type are we looking at? */
$currentAppModule = NULL;
$currentType = NULL;
@@ -589,9 +649,9 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$table->sortBy = 'rep_date';
$table->joins = array(
array(
'select' => "core_reputation_index.id AS rep_id, core_reputation_index.rep_date, core_reputation_index.rep_rating, core_reputation_index.member_received as rep_member_received, core_reputation_index.member_id as rep_member",
'select' => "core_reputation_index.id AS rep_id, core_reputation_index.rep_date, core_reputation_index.rep_rating, core_reputation_index.member_received as rep_member_received, core_reputation_index.member_id as rep_member, core_reputation_index.reaction as rep_reaction",
'from' => 'core_reputation_index',
'where' => array( "core_reputation_index.type_id=" . $currentClass::$databaseTable . "." . $currentClass::$databasePrefix . $currentClass::$databaseColumnId . " AND ( core_reputation_index.member_id=? OR core_reputation_index.member_received=? ) AND core_reputation_index.app=? AND core_reputation_index.type=?", $this->member->member_id, $this->member->member_id, $currentClass::$application, $currentClass::$reputationType ),
'where' => array( "core_reputation_index.type_id=" . $currentClass::$databaseTable . "." . $currentClass::$databasePrefix . $currentClass::$databaseColumnId . " AND ( core_reputation_index.member_id=? OR core_reputation_index.member_received=? ) AND core_reputation_index.app=? AND core_reputation_index.type=?", $this->member->member_id, $this->member->member_id, $currentClass::$application, $currentClass::reactionType() ),
'type' => 'INNER'
)
);
@@ -728,8 +788,12 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
/* Set Session Location */
\IPS\Session::i()->setLocation( $this->member->url(), array(), 'loc_editing_profile', array( $this->member->name => FALSE ) );
if ( \IPS\Request::i()->isAjax() )
if( !count( $form->elements ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->genericBlock( \IPS\Member::loggedIn()->language()->addToStack( 'profile_nothing_to_edit' ), NULL, 'ipsPad' );
}
else if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
@@ -754,7 +818,16 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
/* The basics */
$form->addTab( 'profile_edit_basic_tab', 'user');
$form->addHeader( 'profile_edit_basic_header' );
$canChangeTitle = ( \IPS\Settings::i()->post_titlechange != -1 and ( isset( \IPS\Settings::i()->post_titlechange ) and $this->member->member_posts >= \IPS\Settings::i()->post_titlechange ) );
$canChangeBirthday = ( \IPS\Settings::i()->profile_birthday_type !== 'none' );
$canEnableDisableStatuses = ( \IPS\Settings::i()->profile_comments and $this->member->canAccessModule( \IPS\Application\Module::get( 'core', 'status' ) ) AND !$this->member->members_bitoptions['bw_no_status_update'] );
if( $canChangeTitle or $canChangeBirthday or $canEnableDisableStatuses )
{
$form->addHeader( 'profile_edit_basic_header' );
}
if( \IPS\Settings::i()->post_titlechange != -1 and ( isset( \IPS\Settings::i()->post_titlechange ) and $this->member->member_posts >= \IPS\Settings::i()->post_titlechange ) )
{
$form->add( new \IPS\Helpers\Form\Text( 'member_title', $this->member->member_title, FALSE, array( 'maxLength' => 64 ) ) );
@@ -770,7 +843,22 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
'YY' => \IPS\Theme::i()->getTemplate( 'members', 'core', 'global' )->bdayForm_year( $element->name, $element->value, $element->error ),
'YYYY' => \IPS\Theme::i()->getTemplate( 'members', 'core', 'global' )->bdayForm_year( $element->name, $element->value, $element->error ),
) );
} ) ) );
} ), function( $val )
{
$date = $val['day'];
$month = $val['month'];
$year = $val['year'];
try
{
new \IPS\DateTime( $year."-".$month."-" . $date );
}
catch ( \Exception $e)
{
throw new \InvalidArgumentException( 'invalid_bdate') ;
}
}
) );
if ( \IPS\Settings::i()->profile_birthday_type == 'private' )
{
$form->addMessage( 'profile_birthday_display_private', 'ipsMessage ipsMessage_info' );
@@ -933,6 +1021,9 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->signature = $values['signature'];
}
}
/* Reset Profile Complete flag in case this was an optional step */
$this->member->members_bitoptions['profile_completed'] = FALSE;
/* Save */
\IPS\Db::i()->replace( 'core_pfields_content', $profileFields );
@@ -959,7 +1050,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$toggles = array( 'custom' => array( 'member_photo_upload' ), 'url' => array( 'member_photo_url' ) );
$extra = array();
$options = array();
$defaultType = $this->member->pp_photo_type;
$defaultType = ( $this->member->pp_photo_type == 'letter' ) ? 'none' : $this->member->pp_photo_type;
/* Can we upload? */
if ( $photoVars[0] )
@@ -996,8 +1087,21 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
}
/* And of course we can always not have a photo */
$options['none'] = 'member_photo_none';
/* And of course we can always not have a photo... except when we can't */
$photoRequired = FALSE;
foreach( \IPS\Member\ProfileStep::loadAll() AS $step )
{
if ( $step->completion_act === 'photo' AND $step->required )
{
$photoRequired = TRUE;
break;
}
}
if ( $photoRequired === FALSE )
{
$options['none'] = 'member_photo_none';
}
/* iOS doesn't like upload forms being hidden by a toggle; and it makes sense if we do not have a profile photo to show the upload as the selected option */
if ( $defaultType == 'none' and $photoVars[0] )
@@ -1084,6 +1188,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
break;
case 'none':
$this->member->pp_photo_type = NULL;
$this->member->pp_main_photo = NULL;
$this->member->members_bitoptions['bw_disable_gravatar'] = 1;
$this->member->photo_last_update = NULL;
@@ -1101,6 +1206,9 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$obj->save( array( 'profilesync_photo' => TRUE ) );
}
}
/* Reset Profile Complete flag in case this was an optional step */
$this->member->members_bitoptions['profile_completed'] = FALSE;
$this->member->save();
@@ -1273,31 +1381,42 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
/**
* Rep Status/Comment
* React to a status / comment
*
* @return void
*/
protected function rep()
{
protected function react()
{
\IPS\Session::i()->csrfCheck();
try
{
$item = ( \IPS\Request::i()->type == 'status' ) ? \IPS\core\Statuses\Status::load( \IPS\Request::i()->status ) : \IPS\core\Statuses\Reply::load( \IPS\Request::i()->reply );
$type = intval( \IPS\Request::i()->rep ) === 1 ? 1 : -1;
$item->giveReputation( $type );
if ( \IPS\Request::i()->isAjax() )
if ( !isset( \IPS\Request::i()->reaction ) )
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->reputationMini( $item->reputation(), $item->canGiveReputation( 1 ), $item->canGiveReputation( -1 ), $item->url('showRep'), $item->url('rep') ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->reputationMini( $item );
}
else
{
\IPS\Output::i()->redirect( $item->url() );
$item->react( \IPS\Content\Reaction::load( \IPS\Request::i()->reaction ) );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array(
'status' => 'ok',
'count' => count( $item->reactions() ),
'score' => $item->reactionCount(),
'blurb' => ( \IPS\Settings::i()->reaction_count_display == 'count' ) ? '' : \IPS\Theme::i()->getTemplate( 'global', 'core' )->reactionBlurb( $item )
));
}
else
{
\IPS\Output::i()->redirect( $item->url() );
}
}
}
catch ( \DomainException $e )
catch( \DomainException $e )
{
if ( \IPS\Request::i()->isAjax() )
{
@@ -1305,27 +1424,100 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
\IPS\Output::i()->error( $e->getMessage(), '1C138/2', 403, '' );
\IPS\Output::i()->error( $e->getMessage(), '1C138/H', 403, '' );
}
}
}
/**
* Show Comment/Review Rep
* Unreact to a status / comment
*
* @return void
*/
protected function showRep()
protected function unreact()
{
\IPS\Session::i()->csrfCheck();
try
{
$item = ( \IPS\Request::i()->type == 'status' ) ? \IPS\core\Statuses\Status::load( \IPS\Request::i()->status ) : \IPS\core\Statuses\Reply::load( \IPS\Request::i()->reply );
$item->removeReaction();
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array(
'status' => 'ok',
'count' => count( $item->reactions() ),
'score' => $item->reactionCount(),
'blurb' => ( \IPS\Settings::i()->reaction_count_display == 'count' ) ? '' : \IPS\Theme::i()->getTemplate( 'global', 'core' )->reactionBlurb( $item )
));
}
else
{
\IPS\Output::i()->redirect( $item->url() );
}
}
catch( \DomainException $e )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'error' => \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() ) ), 403 );
}
else
{
\IPS\Output::i()->error( $e->getMessage(), '1C138/I', 403, '' );
}
}
}
/**
* Show Reactions
*
* @return void
*/
protected function showReactions()
{
try
{
$item = ( \IPS\Request::i()->type == 'status' ) ? \IPS\core\Statuses\Status::load( \IPS\Request::i()->status ) : \IPS\core\Statuses\Reply::load( \IPS\Request::i()->reply );
\IPS\Output::i()->output = $item->reputationTable();
$tabs = array();
$tabs['all'] = \IPS\Member::loggedIn()->language()->addToStack('all');
foreach( \IPS\Content\Reaction::roots() AS $reaction )
{
$tabs[ $reaction->id ] = $reaction->_title;
}
$activeTab = 'all';
if ( isset( \IPS\Request::i()->reaction ) )
{
$activeTab = \IPS\Request::i()->reaction;
}
$url = $item->url('showReactions');
$url = $url->setQueryString( 'changed', 1 );
if ( $activeTab !== 'all' )
{
$url = $url->setQueryString( 'reaction', $activeTab );
}
if ( \IPS\Request::i()->isAjax() AND isset( \IPS\Request::i()->changed ) )
{
\IPS\Output::i()->output = $item->reactionTable( $activeTab !== 'all' ? $activeTab : NULL, $url, 'reaction', FALSE );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, $item->reactionTable( $activeTab !== 'all' ? $activeTab : NULL ), $url, 'reaction', FALSE );
}
}
catch ( \LogicException $e )
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'cannot_view_reputation', '2C138/8', 403, '' );
\IPS\Output::i()->error( 'node_error', '2S136/18', 404, '' );
}
catch( \DomainException $e )
{
\IPS\Output::i()->error( 'no_module_permission', '2S136/19', 403, '' );
}
}
@@ -1442,6 +1634,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->pp_cover_photo = (string) $photo->file;
$this->member->pp_cover_offset = (int) $photo->offset;
/* Reset Profile Complete flag in case this was an optional step */
$this->member->members_bitoptions['profile_completed'] = FALSE;
$this->member->save();
}
@@ -1454,12 +1650,20 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
\IPS\Output::i()->error( 'no_module_permission', '1C138/G', 403, '' );
}
$table = new \IPS\Helpers\Table\Db( 'core_dnames_change', $this->member->url()->setQueryString( 'do', 'namehistory' ), array( 'dname_member_id=?', $this->member->member_id ) );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'profile' ), 'nameHistoryTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'profile' ), 'nameHistoryRows' );
$table->sortBy = 'dname_date';
$table = new \IPS\Helpers\Table\Db( 'core_member_history', $this->member->url()->setQueryString( 'do', 'namehistory' ), array( 'log_member=? AND log_app=? AND log_type=?', $this->member->member_id, 'core', 'display_name' ) );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'members', 'core', 'global' ), 'nameHistoryTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'members', 'core', 'global' ), 'nameHistoryRows' );
$table->sortBy = 'log_date';
$table->sortDirection = 'desc';
$table->parsers = array(
'log_data' => function( $val )
{
return json_decode( $val, TRUE );
}
);
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addtoStack( 'members_dname_history', FALSE, array( 'sprintf' => ( $this->member->name ) ) );
\IPS\Output::i()->output = $table;
@@ -1474,4 +1678,26 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
return $this->member->coverPhoto();
}
/**
* Hide a status reply or status update
*
* @return void
*/
protected function hide()
{
\IPS\Request::i()->action = 'hide';
return $this->moderate();
}
/**
* Delete a status reply or status update
*
* @return void
*/
protected function delete()
{
\IPS\Request::i()->action = 'delete';
return $this->moderate();
}
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Messenger
* @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
* @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 5 Jul 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\messaging;
@@ -233,9 +232,9 @@ class _messenger extends \IPS\Content\Controller
{
$where[] = array( 'core_message_topic_user_map.map_has_unread=1' );
}
/* Add a folder filter */
if ( !isset( \IPS\Request::i()->overview ) )
if ( isset( \IPS\Request::i()->folder ) or !is_null( $folder ) )
{
if ( !is_null( $folder ) AND isset( $folders[ $folder ] ) )
{
@@ -248,11 +247,13 @@ class _messenger extends \IPS\Content\Controller
}
/* If we're searching, get the results */
$perPage = 25;
$iterator = array();
$perPage = 25;
$iterator = array();
if ( \IPS\Request::i()->q )
{
$subQuery = \IPS\Db::i()->select( 'map_topic_id', array( 'core_message_topic_user_map', 'core_message_topic_user_map' ), $where );
$where = array( array( 'core_message_posts.msg_topic_id IN (?)', $subQuery ) );
$query = array();
if ( isset( \IPS\Request::i()->search ) and $searchValues = \IPS\Request::i()->valueFromArray('search') )
{
@@ -275,7 +276,7 @@ class _messenger extends \IPS\Content\Controller
if ( count( $query ) )
{
$where[] = '(' . implode( ' OR ', $query ) . ')';
$where[] = array( '(' . implode( ' OR ', $query ) . ')' );
}
}
@@ -477,7 +478,7 @@ class _messenger extends \IPS\Content\Controller
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=messaging&controller=messenger&folder=' . \IPS\Request::i()->move_message_to, 'front', 'messenger' ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=messaging&controller=messenger&folder=' . \IPS\Request::i()->move_message_to, 'front', 'messaging' ) );
}
\IPS\Output::i()->title = 'messenger_move';
@@ -690,7 +691,7 @@ class _messenger extends \IPS\Content\Controller
if ( isset( \IPS\Request::i()->member_names ) )
{
foreach ( explode( ',', \IPS\Request::i()->member_names ) as $name )
foreach ( explode( "\n", \IPS\Request::i()->member_names ) as $name )
{
/* We have to html_entity_decode because the javascript code sends the encoded name here */
$memberToAdd = \IPS\Member::load( html_entity_decode( $name, ENT_QUOTES, 'UTF-8' ), 'name' );
@@ -1,12 +1,11 @@
<?php
/**
* @brief Moderator Control Panel
* @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
* @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 24 Oct 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\modcp;
@@ -123,6 +122,10 @@ class _modcp extends \IPS\Dispatcher\Controller
catch ( \OutOfRangeException $e )
{
$approvalQueueCount = \IPS\Content\Search\Query::init()->setHiddenFilter( \IPS\Content\Search\Query::HIDDEN_UNAPPROVED )->count();
if ( \IPS\Settings::i()->clubs and \IPS\Settings::i()->clubs_require_approval and \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$approvalQueueCount += \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs', 'approved=0' )->first();
}
\IPS\Data\Cache::i()->storeWithExpire( 'modCpApprovalQueueCount_' . \IPS\Member::loggedIn()->member_id, $approvalQueueCount, \IPS\DateTime::create()->add( new \DateInterval( 'PT15M' ) ), TRUE );
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Online Users
* @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
* @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 21 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\online;
@@ -0,0 +1,52 @@
<?php
/**
* @brief Promote Items
* @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 1 Feb 2017
*/
namespace IPS\core\modules\front\promote;
/* 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;
}
/**
* Curated "Our Picks" listing. (Very technical description there)
*/
class _ourpicks extends \IPS\Dispatcher\Controller
{
/**
* List promoted internally promoted items
*
* @return void
*/
protected function manage()
{
if ( ! \IPS\Settings::i()->promote_community_enabled )
{
\IPS\Output::i()->error( 'promote_no_permission', '2C356/9', 403, '' );
}
/* Create the table */
$table = new \IPS\core\Promote\PublicTable( \IPS\Http\Url::internal( 'app=core&module=promote&controller=ourpicks', 'front', 'promote_show' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote_responsive.css' ) );
}
\IPS\Output::i()->breadcrumb['module'] = array( \IPS\Http\Url::internal( "app=core&module=promote&controller=ourpicks", 'front', 'promote_show' ), \IPS\Member::loggedIn()->language()->addToStack('promoted_items_title') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_table_header');
\IPS\Output::i()->output = $table;
}
}
@@ -0,0 +1,514 @@
<?php
/**
* @brief Promote Items
* @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 1 Feb 2017
*/
namespace IPS\core\modules\front\promote;
/* 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;
}
/**
* Promote things. (Very technical description there)
*/
class _promote extends \IPS\Dispatcher\Controller
{
/**
* Edit internal data
*
* @return void
*/
protected function edit()
{
\IPS\Session::i()->csrfCheck();
try
{
$promote = \IPS\core\Promote::load( \IPS\Request::i()->promote_id );
$id = $promote->class_id;
$class = $promote->class;
}
catch( \OutOfRangeException $ex )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/5', 404, '' );
}
try
{
$object = $class::load( $id );
}
catch ( \Exception $ex )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/6', 404, '' );
}
/* Do we have viewing perms? */
if ( ! \IPS\core\Promote::objectCanView( $object ) )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/7', 404, '' );
}
$form = new \IPS\Helpers\Form( 'form', 'save' );
$form->class = 'ipsForm_vertical cPromoteDialog';
$form->add( new \IPS\Helpers\Form\TextArea( 'promote_internal_text', $promote->getText('internal'), FALSE, array( 'rows' => 10 ) ) );
/* Saving? */
if ( $values = $form->values() )
{
$promote->setText( 'internal', $values['promote_internal_text'] );
$promote->save();
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( '`key`=?', 'promote' ) );
/* Redirect back to the list */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ), 'saved' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_internal_edit');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'promote' )->edit( $form );
}
/**
* View sent history
*
* @return void
*/
protected function history()
{
/* Guests can't promote things */
if( ! \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C356/1', 403, '' );
}
if ( ! \IPS\core\Promote::canPromote() )
{
\IPS\Output::i()->error( 'promote_no_permission', '2C356/2', 403, '' );
}
try
{
$promote = \IPS\core\Promote::load( \IPS\Request::i()->promote_id );
}
catch( \OutOfRangeException $ex )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/5', 404, '' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_view_history');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'promote' )->history( $promote->history() );
}
/**
* List promoted items for moderators
*
* @return void
*/
protected function view()
{
/* Guests can't promote things */
if( ! \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C356/1', 403, '' );
}
if ( ! \IPS\core\Promote::canPromote() )
{
\IPS\Output::i()->error( 'promote_no_permission', '2C356/2', 403, '' );
}
/* Create the table */
$table = new \IPS\core\Promote\Table( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_promote.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote_responsive.css' ) );
}
\IPS\Output::i()->breadcrumb['module'] = array( \IPS\Http\Url::internal( "app=core&module=promote&controller=promote&do=view", 'front', 'promote_manage' ), \IPS\Member::loggedIn()->language()->addToStack('promote_manage_link') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_manage_link');
\IPS\Output::i()->output = $table;
}
/**
* Delete a promote item
*
* @return void
*/
protected function delete()
{
\IPS\Session::i()->csrfCheck();
if ( ! \IPS\core\Promote::canPromote() )
{
\IPS\Output::i()->error( 'no_promote_permission', '2C356/B', 403, '' );
}
try
{
$item = \IPS\core\Promote::load( \IPS\Request::i()->promote_id );
$item->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ), 'promote_item_deleted' );
}
catch( \OutOfRangeException $ex )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/3', 404, '' );
}
}
/**
* Promote dialog
*
* @return void
*/
protected function manage()
{
$promote = NULL;
$existing = NULL;
/* Guests can't promote things */
if( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C356/4', 403, '' );
}
/* Can we promote anything at all? */
if ( ! \IPS\core\Promote::canPromote() )
{
\IPS\Output::i()->error( 'no_promote_permission', '2S356/A', 403, '' );
}
/* Editing? */
if ( isset( \IPS\Request::i()->promote_id ) )
{
try
{
$promote = \IPS\core\Promote::load( \IPS\Request::i()->promote_id );
$id = $promote->class_id;
$class = $promote->class;
if ( isset( \IPS\Request::i()->repromote ) )
{
$promote->skipCloneDuplication = TRUE;
$existing = clone $promote;
/* We're repromoting, so reset the scheduled data so we don't pre-fill an old date */
$promote->schedule_auto = 0;
$promote->scheduled = NULL;
}
}
catch( \OutOfRangeException $ex )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/5', 404, '' );
}
}
else
{
/* Nope... */
$class = \IPS\Request::i()->class;
$id = intval( \IPS\Request::i()->id );
/* Do we have an existing promotion waiting to be sent? */
$existing = \IPS\core\Promote::loadByClassAndId( $class, $id );
}
try
{
$object = $class::load( $id );
}
catch ( \Exception $ex )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/6', 404, '' );
}
/* Do we have viewing perms? */
if ( ! \IPS\core\Promote::objectCanView( $object ) )
{
\IPS\Output::i()->error( 'page_not_found', '2C356/7', 404, '' );
}
/* Links */
$normalLink = $object->url();
$shortLink = NULL;
$images = NULL;
try
{
$shortLink = \IPS\core\Promote::shortenUrl( $normalLink );
}
catch ( \Exception $e ) { }
/* Do we have access to any share services? */
if ( $services = \IPS\core\Promote::promoteServices() )
{
$form = new \IPS\Helpers\Form( 'form', 'promote_submit' );
$form->class = 'ipsForm_horizontal cPromoteDialog';
$form->attributes = array( 'data-controller' => 'core.front.system.promote' );
$form->addTab('promote_links');
$form->addHtml( \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialogLinks( $normalLink, $shortLink ) );
$form->addTab('promote_content');
foreach( $services as $service )
{
$text = \IPS\core\Promote::objectTitle( $object );
$content = \IPS\core\Promote::objectContent( $object );
if ( $promote )
{
$service->promote = $promote;
$promoteText = $promote->text;
$text = isset( $promoteText[ mb_strtolower( $service->key ) ] ) ? $promoteText[ mb_strtolower( $service->key ) ] : '';
foreach( $service->form( $text ) as $element )
{
if ( ! ( $element instanceof \IPS\Helpers\Form\FormAbstract ) )
{
$form->addHtml( $element );
}
else
{
$form->add( $element );
}
}
}
else
{
foreach( $service->form( $text, ( $shortLink ?: $normalLink ), $content ) as $element )
{
if ( ! ( $element instanceof \IPS\Helpers\Form\FormAbstract ) )
{
$form->addHtml( $element );
}
else
{
$form->add( $element );
}
}
}
}
$form->addTab( 'promote_meta' );
/* Existing media */
try
{
if ( $images = $object->contentImages( 20 ) )
{
$form->addHtml( \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialogImages( $images, $promote ) );
}
}
catch( \BadMethodCallException $e ) { }
/* Upload box */
$existingMedia = array();
if ( $promote )
{
foreach( $promote->media as $file )
{
try
{
$existingMedia[] = \IPS\File::get( 'core_Promote', $file );
}
catch ( \OutOfRangeException $e ) { }
}
}
$uploader = new \IPS\Helpers\Form\Upload( 'promote_media', $existingMedia, FALSE, array(
'multiple' => TRUE,
'storageExtension' => 'core_Promote',
'maxFiles' => 10,
'image' => TRUE,
'maxFileSize' => 3,
'template' => "promote.imageUpload",
) );
$uploader->template = array( \IPS\Theme::i()->getTemplate( 'promote', 'core', 'front' ), 'promoteAttachments' );
$form->add( $uploader );
/* Scheduling */
$form->addTab('promote_schedule');
$schedule = 'now';
if ( $promote )
{
if ( ! isset( \IPS\Request::i()->repromote ) )
{
if ( $promote->schedule_auto )
{
$schedule = 'auto';
}
else
{
$schedule = 'custom';
}
}
}
\IPS\Member::loggedIn()->language()->words['promote_custom_schedule_desc'] = sprintf( \IPS\Member::loggedIn()->language()->get('promote_custom_schedule__desc'), \IPS\Member::loggedIn()->language()->get( 'timezone__' . \IPS\Settings::i()->promote_tz ) );
/* Sort out some language strings */
if ( $promote and $promote->schedule_auto )
{
$currentSlot = \IPS\DateTime::ts( $promote->scheduled )->setTimezone( new \DateTimeZone( \IPS\Settings::i()->promote_tz ) );
/* Keep the current slot */
\IPS\Member::loggedIn()->language()->words['promote_auto_schedule_desc'] = sprintf( \IPS\Member::loggedIn()->language()->get('promote_auto_schedule__desc'), $currentSlot->html() . ' ' . $currentSlot->localeTime( FALSE ), \IPS\Settings::i()->promote_tz );
}
else
{
$nextAuto = \IPS\core\Promote::getNextAutoSchedule();
if ( $nextAuto )
{
\IPS\Member::loggedIn()->language()->words['promote_auto_schedule_desc'] = sprintf( \IPS\Member::loggedIn()->language()->get('promote_auto_schedule__desc'), $nextAuto->html() . ' ' . $nextAuto->localeTime( FALSE ), \IPS\Settings::i()->promote_tz );
}
}
$dateOptions = array(
'now' => 'promote_send_now',
'auto' => 'promote_auto_schedule',
'custom' => 'promote_custom_schedule'
);
if ( ! \IPS\Settings::i()->promote_scheduled )
{
unset( $dateOptions['auto'] );
}
$form->add( new \IPS\Helpers\Form\Radio( 'promote_schedule', $schedule, FALSE, array(
'options' => $dateOptions
) ) );
$form->add( new \IPS\Helpers\Form\Date( 'promote_custom_date', ( ( $promote and ! $promote->schedule_auto and $promote->scheduled ) ? \IPS\DateTime::ts( $promote->scheduled )->setTimezone( new \DateTimeZone( \IPS\Settings::i()->promote_tz ) ) : NULL ), FALSE, array( 'time' => true, 'timezone' => new \DateTimeZone( \IPS\Settings::i()->promote_tz ) ), NULL, NULL, NULL, 'promote_custom_date' ) );
}
else
{
\IPS\Output::i()->error( 'promote_no_permission', '2C266/1', 403, '' ); //error code needed
}
/* Saving? */
if ( $values = $form->values() )
{
$text = array();
$shareTo = array();
foreach( $services as $service )
{
$key = mb_strtolower( $service->key );
if ( isset( $values[ 'promote_social_content_' . $key ] ) and $values[ 'promote_social_content_' . $key ] )
{
$text[ $key ] = $values[ 'promote_social_content_' . $key ];
$shareTo[] = $key;
}
}
$media = array();
if ( is_array( $values['promote_media'] ) )
{
foreach( $values['promote_media'] as $key => $file )
{
$media[] = (string) $file;
}
}
$scheduled = time();
$scheduleAuto = 0;
if ( $values['promote_schedule'] == 'custom' )
{
$scheduled = $values['promote_custom_date']->getTimestamp();
}
else if ( $values['promote_schedule'] == 'auto' )
{
$scheduleAuto = 1;
if ( $promote and $promote->schedule_auto )
{
$scheduled = $promote->scheduled;
}
else
{
$scheduled = \IPS\core\Promote::getNextAutoSchedule()->getTimestamp();
}
}
/* Content images */
$saveImages = array();
if ( $images )
{
foreach( $images as $image )
{
foreach( $image as $extension => $path )
{
if ( \IPS\Request::i()->attach_files and in_array( $path, array_keys( \IPS\Request::i()->attach_files ) ) )
{
$saveImages[] = array( $extension => $path );
}
}
}
}
if ( ! $promote )
{
$promote = new \IPS\core\Promote;
$promote->class = $class;
$promote->class_id = $id;
$promote->added_by = \IPS\Member::loggedIn()->member_id;
}
$promote->internal = ( in_array( 'internal', $shareTo ) ? 1 : 0 );
$promote->text = $text;
$promote->short_link = $shortLink ?: $normalLink;
$promote->images = $saveImages;
$promote->media = $media;
$promote->added = time();
$promote->scheduled = $scheduled;
$promote->schedule_auto = $scheduleAuto;
$promote->share_to = $shareTo;
$promote->failed = 0; # Reset the failed flag if we're re-promoting
$promote->sent = 0;
$promote->save();
if ( isset( \IPS\Request::i()->promote_id ) )
{
/* Redirect back to the list */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ), 'saved' );
}
else
{
/* Show a we're done page */
$output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteScheduled( $promote );
}
}
else
{
$output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialog( \IPS\Member::loggedIn()->language()->addToStack('promote_social_title'), $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'promote', 'core' ) ), 'promoteDialogTemplate' ) ), $existing, $object );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_promote.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/promote_responsive.css' ) );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_social_button');
\IPS\Output::i()->output = $output;
}
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Search
* @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
* @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 18 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\search;
@@ -209,6 +208,23 @@ class _search extends \IPS\Dispatcher\Controller
$where[] = \IPS\Db::i()->in( 'core_members.member_group_id', $groups );
}
}
else
{
$exclude = array();
/* Groups not specified but we still want to omit non searchable groups */
foreach( \IPS\Member\Group::groups() as $group )
{
if ( $group->g_bitoptions['gbw_hide_group'] )
{
$exclude[] = $group->g_id;
}
}
if ( count( $exclude ) )
{
$where[] = \IPS\Db::i()->in( 'core_members.member_group_id', $exclude, TRUE );
}
}
/* Figure out member custom field filters */
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::SEARCH ) as $group => $fields )
@@ -412,6 +428,34 @@ class _search extends \IPS\Dispatcher\Controller
}
}
/* Filter by club */
if ( isset( \IPS\Request::i()->club ) )
{
$clubIds = array();
$clubNames = array();
foreach ( explode( ',', \IPS\Request::i()->club ) as $clubId )
{
try
{
$club = \IPS\Member\Club::load( ltrim( $clubId, 'c' ) );
if ( $club->canRead() )
{
$clubIds[] = $club->id;
$clubNames[] = $club->name;
}
}
catch ( \OutOfRangeException $e ) { }
}
if ( count( $clubIds ) )
{
$query->filterByClub( $clubIds );
$baseUrl = $baseUrl->setQueryString( 'club', \IPS\Request::i()->club );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_club', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->formatList( $clubNames, \IPS\Member::loggedIn()->language()->get('or_list_format') ) ) ) );
}
}
/* Set time cutoffs */
foreach ( array( 'start' => 'filterByCreateDate', 'updated' => 'filterByLastUpdatedDate' ) as $k => $method )
{
@@ -649,7 +693,7 @@ class _search extends \IPS\Dispatcher\Controller
$contentTypes = $this->_contentTypes();
$contentToggles = array();
$typeFields = array();
$typeFieldToggles = array('' => array() );
$typeFieldToggles = array('' => array( 'club' ) );
$haveCommentClass = FALSE;
$haveReplyClass = FALSE;
$haveReviewClass = FALSE;
@@ -730,6 +774,19 @@ class _search extends \IPS\Dispatcher\Controller
/* Author */
$form->add( new \IPS\Helpers\Form\Member( 'author', NULL, FALSE, array(), NULL, NULL, NULL, 'author' ), NULL, 'search_tab_content' );
/* Club */
$clubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE );
if ( count( $clubs ) )
{
$clubOptions = array();
foreach ( $clubs as $club )
{
$clubOptions[ "c{$club->id}" ] = $club->name;
}
$form->add( new \IPS\Helpers\Form\Select( 'club', NULL, FALSE, array( 'options' => $clubOptions, 'parse' => 'normal', 'multiple' => TRUE, 'noDefault' => TRUE, 'class' => 'ipsContained' ), NULL, NULL, NULL, 'club' ), NULL, 'search_tab_content' );
}
/* Dates */
$form->add( new \IPS\Helpers\Form\Select( 'startDate', ( isset( \IPS\Request::i()->start_before ) or ( isset( \IPS\Request::i()->start_after ) and is_numeric( \IPS\Request::i()->start_after ) ) ) ? 'custom' : \IPS\Request::i()->start_after, FALSE, array( 'options' => $dateOptions, 'toggles' => array( 'custom' => array( 'elCustomDate_startDate' ) ) ), NULL, NULL, NULL, 'startDate' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\DateRange( 'startDateCustom', array( 'start' => ( isset( \IPS\Request::i()->start_after ) and is_numeric( \IPS\Request::i()->start_after ) ) ? \IPS\DateTime::ts( \IPS\Request::i()->start_after ) : NULL, 'end' => isset( \IPS\Request::i()->start_before ) ? \IPS\DateTime::ts( \IPS\Request::i()->start_before ) : NULL ) ), NULL, 'search_tab_content' );
@@ -746,7 +803,7 @@ class _search extends \IPS\Dispatcher\Controller
if ( isset( $class::$containerNodeClass ) )
{
$nodeClass = $class::$containerNodeClass;
$field = new \IPS\Helpers\Form\Node( $k . '_node', ( isset( \IPS\Request::i()->nodes ) ) ? \IPS\Request::i()->nodes : NULL, FALSE, array( 'class' => $nodeClass, 'multiple' => TRUE, 'permissionCheck' => $nodeClass::searchableNodesPermission(), 'forceOwner' => FALSE ), NULL, NULL, NULL, $k . '_node' );
$field = new \IPS\Helpers\Form\Node( $k . '_node', ( isset( \IPS\Request::i()->nodes ) ) ? \IPS\Request::i()->nodes : NULL, FALSE, array( 'class' => $nodeClass, 'multiple' => TRUE, 'permissionCheck' => $nodeClass::searchableNodesPermission(), 'forceOwner' => FALSE, 'clubs' => \IPS\IPS::classUsesTrait( $nodeClass, 'IPS\Content\ClubContainer' ) ), NULL, NULL, NULL, $k . '_node' );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( $nodeClass::$nodeTitle );
$form->add( $field, NULL, 'search_tab_nodes' );
}
@@ -893,6 +950,10 @@ class _search extends \IPS\Dispatcher\Controller
{
$url = $url->setQueryString( 'author', $values['author']->name );
}
if ( isset( $values['club'] ) and $values['club'] )
{
$url = $url->setQueryString( 'club', $values['club'] );
}
if ( isset( $values['group'] ) and $values['group'] )
{
@@ -1,12 +1,11 @@
<?php
/**
* @brief Print out sitemap
* @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
* @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 30 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\sitemap;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Staff directory
* @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
* @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 19 Sep 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\staffdirectory;
@@ -1,10 +1,10 @@
<?php
/**
* @brief Status Updates Feed
* @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
* @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 15 Aug 2014
* @version SVN_VERSION_NUMBER
*/
@@ -1,12 +1,11 @@
<?php
/**
* @brief AJAX actions
* @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
* @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 04 Apr 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -91,7 +90,7 @@ class _ajax extends \IPS\Dispatcher\Controller
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack( 'form_maxlength', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->max_user_name_length ) ) ) );
}
elseif ( \IPS\Settings::i()->username_characters and !preg_match( '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/i', $name ) )
elseif ( \IPS\Settings::i()->username_characters and !preg_match( '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/iu', $name ) )
{
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_bad_value') );
}
@@ -187,6 +186,26 @@ class _ajax extends \IPS\Dispatcher\Controller
}
}
/* Check it's an allowed domain */
if ( \IPS\Settings::i()->allowed_reg_email !== '' AND $allowedEmailDomains = explode( ',', \IPS\Settings::i()->allowed_reg_email ) )
{
$matched = FALSE;
foreach ( $allowedEmailDomains AS $domain )
{
if( \mb_stripos( $email, "@" . $domain ) !== FALSE )
{
$matched = TRUE;
break;
}
}
if ( count( $allowedEmailDomains ) AND !$matched )
{
$result = array( 'result' => 'fail', 'message' => $email );
}
}
\IPS\Output::i()->json( $result );
}
@@ -378,4 +397,20 @@ class _ajax extends \IPS\Dispatcher\Controller
\IPS\Output::i()->json( $response );
}
/**
* Show information about chart timezones
*
* @return void
*/
public function chartTimezones()
{
$mysqlTimezone = \IPS\Db::i()->query( "SELECT TIMEDIFF( NOW(), CONVERT_TZ( NOW(), @@session.time_zone, '+00:00' ) );" )->fetch_row()[0];
if ( preg_match( '/^(-?)(\d{2}):00:00/', $mysqlTimezone, $matches ) )
{
$mysqlTimezone = "GMT" . ( ( $matches[2] == 0 ) ? '' : ( ( $matches[1] ?: '+' ) . intval( $matches[2] ) ) );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->chartTimezoneInfo( $mysqlTimezone );
}
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Announcement
* @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
* @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 Oct 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief My Attachments Controller
* @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
* @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 22 Jul 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief "Content" functions Controller
* @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
* @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 29 Apr 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Designer mode controller
* @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
* @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 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Editor AJAX functions Controller
* @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
* @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 29 Apr 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -116,9 +115,9 @@ class _editor extends \IPS\Dispatcher\Controller
{
try
{
if ( \IPS\Request::i()->image )
if ( \IPS\Request::i()->image and \IPS\Request::i()->width and \IPS\Request::i()->height )
{
$embed = \IPS\Text\Parser::_imageEmbed( $url, FALSE, TRUE );
$embed = \IPS\Text\Parser::imageEmbed( $url, intval( \IPS\Request::i()->width ), intval( \IPS\Request::i()->height ) );
}
else
{
@@ -1,12 +1,11 @@
<?php
/**
* @brief Embed iframe display
* @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
* @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 15 Sep 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -36,7 +35,7 @@ class _embed extends \IPS\Content\Controller
{
$return = \IPS\Data\Cache::i()->getWithExpire( $cacheKey, TRUE );
}
/* Not in cache - fetch */
catch ( \OutOfRangeException $e )
{
@@ -48,13 +47,18 @@ class _embed extends \IPS\Content\Controller
{
$return = '';
}
/* And cache */
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $return, \IPS\DateTime::create()->add( new \DateInterval('P1D') ), TRUE );
}
/* Output */
$js = \IPS\Output::i()->js( 'js/embedHandler.js', 'core', 'interface' );
$js = array(
\IPS\Output::i()->js( 'js/commonEmbedHandler.js', 'core', 'interface' ),
\IPS\Output::i()->js( 'js/externalEmbedHandler.js', 'core', 'interface' )
);
/* Intentionally replace the cssFiles array with a single file here, since we don't need the complete CSS framework in external embeds */
\IPS\Output::i()->cssFiles = \IPS\Theme::i()->css( 'styles/embeds.css', 'core', 'front' );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->embedExternal( $return, $js ), 200 );
}
}
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief My followed content
* @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
* @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 16 Apr 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Guidelines
* @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
* @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 Sept 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Ignore Preferences
* @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
* @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 20 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Language Changer
* @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
* @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 17 Dec 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Login
* @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
* @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 7 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -52,7 +51,7 @@ class _login extends \IPS\Dispatcher\Controller
$member = $login->authenticate();
if ( $member !== NULL )
{
$this->_doLogin( $member, $login->flags['signin_anonymous'], $login->flags['remember_me'], \IPS\Login::getDestination() );
$this->_doLogin( $member, $login->flags['signin_anonymous'], $login->flags['remember_me'], \IPS\Login::getDestination(), FALSE, $login->usedHandler );
}
}
catch ( \IPS\Login\Exception $e )
@@ -99,9 +98,10 @@ class _login extends \IPS\Dispatcher\Controller
* @param bool $rememberMe If the "remember me" checkbox was checked
* @param \IPS\Http\Url $destination Where to redirect to
* @param bool $bypass2FA If true, will not perform 2FA check
* @param string $loginHandler Which login handler processed the login
* @return void
*/
protected function _doLogin( $member, $anonymous=FALSE, $rememberMe=TRUE, $destination=NULL, $bypass2FA=FALSE )
protected function _doLogin( $member, $anonymous=FALSE, $rememberMe=TRUE, $destination=NULL, $bypass2FA=FALSE, $loginHandler=NULL )
{
/* Get destination */
if ( !$destination )
@@ -109,36 +109,26 @@ class _login extends \IPS\Dispatcher\Controller
$destination = \IPS\Http\Url::internal( '' );
}
/* Is this a known device? */
$device = \IPS\Member\Device::loadOrCreate( $member );
/* Do we need to do 2FA? */
if ( !$bypass2FA and $output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'AuthenticateFront', \IPS\Http\Url::internal( '' ), $member ) )
if ( !$bypass2FA and $output = \IPS\MFA\MFAHandler::accessToArea( 'core', $device->known ? 'AuthenticateFrontKnown' : 'AuthenticateFront', \IPS\Http\Url::internal( '' ), $member ) )
{
$_SESSION['processing2FA'] = array( 'memberId' => $member->member_id, 'anonymous' => $anonymous, 'remember' => $rememberMe, 'destination' => (string) $destination );
$_SESSION['processing2FA'] = array( 'memberId' => $member->member_id, 'anonymous' => $anonymous, 'remember' => $rememberMe, 'destination' => (string) $destination, 'handler' => $loginHandler );
\IPS\Output::i()->redirect( $destination->setQueryString( '_mfaLogin', 1 ) );
}
/* Set anonymous cookie */
/* Log in */
\IPS\Session::i()->setMember( $member );
if ( $anonymous and !\IPS\Settings::i()->disable_anonymous )
{
\IPS\Session::i()->setAnon();
\IPS\Request::i()->setCookie( 'anon_login', 1 );
}
/* Log in */
\IPS\Session::i()->setMember( $member );
/* Set remember me cookie */
if ( $rememberMe )
{
$expire = new \IPS\DateTime;
$expire->add( new \DateInterval( 'P3M' ) );
\IPS\Request::i()->setCookie( 'member_id', $member->member_id, $expire );
\IPS\Request::i()->setCookie( 'pass_hash', $member->member_login_key, $expire );
if ( $anonymous and !\IPS\Settings::i()->disable_anonymous )
{
\IPS\Request::i()->setCookie( 'anon_login', 1, $expire );
}
}
/* Log device */
$device->anonymous = $anonymous and !\IPS\Settings::i()->disable_anonymous;
$device->updateAfterAuthentication( $rememberMe, $loginHandler );
/* Member sync */
$member->memberSync( 'onLogin', array( \IPS\Login::getDestination() ) );
@@ -174,10 +164,11 @@ class _login extends \IPS\Dispatcher\Controller
catch ( \Exception $e ) { }
/* Have we already done 2FA? */
$output = \IPS\MFA\MFAHandler::accessToArea( 'core', 'AuthenticateFront', \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=mfa', 'front', 'login' ), $member );
$device = \IPS\Member\Device::loadOrCreate( $member );
$output = \IPS\MFA\MFAHandler::accessToArea( 'core', $device->known ? 'AuthenticateFrontKnown' : 'AuthenticateFront', \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=mfa', 'front', 'login' ), $member );
if ( !$output )
{
$this->_doLogin( $member, $_SESSION['processing2FA']['anonymous'], $_SESSION['processing2FA']['remember'], $destination, TRUE );
$this->_doLogin( $member, $_SESSION['processing2FA']['anonymous'], $_SESSION['processing2FA']['remember'], $destination, TRUE, $_SESSION['processing2FA']['handler'] );
}
/* Nope, just send us where we want to go not logged in */
@@ -249,7 +240,7 @@ class _login extends \IPS\Dispatcher\Controller
}
catch ( \Exception $e ) { }
}
$this->_doLogin( $member, FALSE, TRUE, $destination );
$this->_doLogin( $member, FALSE, TRUE, $destination, FALSE, $details['handler'] );
}
catch ( \IPS\Login\Exception $e )
{
@@ -270,8 +261,12 @@ class _login extends \IPS\Dispatcher\Controller
*/
protected function logout()
{
$member = \IPS\Member::loggedIn();
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Work out where we will be going after log out */
if( !empty( $_SERVER['HTTP_REFERER'] ) )
{
$referrer = \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] );
@@ -281,8 +276,6 @@ class _login extends \IPS\Dispatcher\Controller
{
$redirectUrl = \IPS\Http\Url::internal( '' );
}
$member = \IPS\Member::loggedIn();
/* Are we logging out back to an admin user? */
if( isset( $_SESSION['logged_in_as_key'] ) )
@@ -295,28 +288,25 @@ class _login extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( $redirectUrl );
}
\IPS\Request::i()->setCookie( 'member_id', NULL );
\IPS\Request::i()->setCookie( 'pass_hash', NULL );
\IPS\Request::i()->setCookie( 'anon_login', NULL );
foreach( \IPS\Request::i()->cookie as $name => $value )
/* Do not allow the login_key to be re-used */
if ( isset( \IPS\Request::i()->cookie['device_key'] ) )
{
if( mb_strpos( $name, "ipbforumpass_" ) !== FALSE )
try
{
\IPS\Request::i()->setCookie( $name, NULL );
$device = \IPS\Member\Device::loadAndAuthenticate( \IPS\Request::i()->cookie['device_key'], $member );
$device->login_key = NULL;
$device->save();
}
catch ( \OutOfRangeException $e ) { }
}
/* Clear cookies */
\IPS\Request::i()->clearLoginCookies();
/* Reset session global parameters */
$_SESSION = array();
/* We have to explicitly reset the session cookie
@link http://php.net/manual/en/function.session-destroy.php */
/* Destroy the session (we have to explicitly reset the session cookie, see http://php.net/manual/en/function.session-destroy.php) */
$_SESSION = array();
$params = session_get_cookie_params();
setcookie( session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] );
/* Then destroy the session itself */
session_destroy();
/* Login handler callback */
@@ -332,6 +322,7 @@ class _login extends \IPS\Dispatcher\Controller
/* Member sync callback */
$member->memberSync( 'onLogout', array( $redirectUrl ) );
/* Redirect */
\IPS\Output::i()->redirect( $redirectUrl->setQueryString( '_fromLogout', 1 ) );
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Lost Password
* @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
* @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 26 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -147,11 +146,15 @@ class _lostpass extends \IPS\Dispatcher\Controller
catch( \BadMethodCallException $e ){}
}
/* Log in, and invalidate all other sessions */
\IPS\Session::i()->setMember( $member );
$member->invalidateSessionsAndLogins( \IPS\Session::i()->id );
\IPS\Member\Device::loadOrCreate( $member )->updateAfterAuthentication( isset( \IPS\Request::i()->cookie['login_key'] ), '' );
/* Delete validating record and log in */
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) );
/* Log in and redirect */
\IPS\Session::i()->setMember( $member );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Mark site as read
* @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
* @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 19 May 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Live meta tag editor
* @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
* @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 4 Sept 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Moderation
* @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
* @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 23 Jul 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Notification Settings Controller
* @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
* @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 27 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -435,7 +434,6 @@ class _notifications extends \IPS\Dispatcher\Controller
/* Display */
$output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'system', 'core' ) ), 'followForm' ) );
/* @see http://community.invisionpower.com/4bugtrack/follow-button-adds-meta-title-and-link-tags-r3209/ */
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $output, 200, 'text/html', \IPS\Output::i()->httpHeaders );
@@ -1,12 +1,11 @@
<?php
/**
* @brief A deliberately empty controller intended for use by plugins which need to add small actions
* @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
* @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 Aug 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Poll View Voters Controller
* @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
* @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 13 Jan 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Privacy Policy
* @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
* @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 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief External redirector with key checks
* @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
* @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 12 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -138,8 +137,6 @@ class _redirect extends \IPS\Dispatcher\Controller
if( $advertisement->maximum_unit == 'c' AND $advertisement->maximum_value > -1 AND $advertisement->clicks + 1 >= $advertisement->maximum_value )
{
$update .= ", ad_active=0";
unset( \IPS\Data\Cache::i()->advertisements );
}
/* Update the database */
@@ -1,12 +1,11 @@
<?php
/**
* @brief Register
* @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
* @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 3 July 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -58,7 +57,31 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->showOffline();
}
if( isset( $_SESSION['coppa_user'] ) )
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=register', NULL, 'register' ), array(), 'loc_registering' );
\IPS\Output::i()->allowDefaultWidgets = FALSE;
/* Quick registration does not work with COPPA */
if ( \IPS\Settings::i()->quick_register )
{
$form = $this->_registrationForm();
$form->class = 'ipsForm_fullWidth';
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('registration');
if( (string) \IPS\Request::i()->url() == (string) \IPS\Http\Url::internal( 'app=core&module=system&controller=register', NULL, 'register' ) )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupRegisterTemplate' ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
}
else
{
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupRegisterTemplate' ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
}
return;
}
if( isset( $_SESSION['coppa_user'] ) AND ( \IPS\Settings::i()->use_coppa OR \IPS\Settings::i()->minimum_age > 0 ) )
{
if ( \IPS\Settings::i()->minimum_age > 0 )
{
@@ -112,14 +135,30 @@ class _register extends \IPS\Dispatcher\Controller
$steps['basic_info'] = function ( $data ) use ( $self )
{
$form = \IPS\core\modules\front\system\register::buildRegistrationForm();
$form = $this->_registrationForm();
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form, new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
};
/* Output */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('registration');
\IPS\Output::i()->output = (string) new \IPS\Helpers\Wizard( $steps, \IPS\Http\Url::internal( 'app=core&module=system&controller=register' ), FALSE );
}
/**
* Normal registration form
*
* @return \IPS\Form
*/
protected function _registrationForm()
{
$form = \IPS\core\modules\front\system\register::buildRegistrationForm();
/* Handle submissions */
if ( $values = $form->values() )
/* Handle submissions */
if ( $values = $form->values() )
{
if( !\IPS\Settings::i()->quick_register )
{
/* Custom Fields */
$profileFields = array();
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
{
foreach ( $fields as $id => $field )
@@ -133,63 +172,111 @@ class _register extends \IPS\Dispatcher\Controller
if ( $fields instanceof \IPS\Helpers\Form\Editor )
{
$field->claimAttachments( $self->id );
$field->claimAttachments( $this->id );
}
}
}
if ( \IPS\Settings::i()->security_questions_enabled and ( \IPS\Settings::i()->security_questions_prompt === 'register' or ( \IPS\Settings::i()->security_questions_prompt === 'optional' and !$values['security_questions_optout_title'] ) ) )
{
$answers = array();
foreach ( $values as $k => $v )
{
if ( preg_match( '/^security_question_q_(\d+)$/', $k, $matches ) )
{
if ( isset( $answers[ $v ] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'security_questions_unique', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->security_questions_number ?: 3 ) ) );
break;
}
else
{
$answers[ $v ] = $v;
}
}
}
}
if ( !$form->error )
{
/* Create Member */
$member = \IPS\core\modules\front\system\register::_createMember( $values, $profileFields );
/* Log them in */
\IPS\Session::i()->setMember( $member );
$redirectUrl = \IPS\Login::getRegistrationDestination( $member );
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'redirect' => (string) $redirectUrl ) );
}
else
{
\IPS\Output::i()->redirect( $redirectUrl );
}
}
}
else
{
$profileFields = array();
}
if ( \IPS\Settings::i()->security_questions_enabled and ( \IPS\Settings::i()->security_questions_prompt === 'register' or ( \IPS\Settings::i()->security_questions_prompt === 'optional' and !$values['security_questions_optout_title'] ) ) )
{
$answers = array();
foreach ( $values as $k => $v )
{
if ( preg_match( '/^security_question_q_(\d+)$/', $k, $matches ) )
{
if ( isset( $answers[ $v ] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'security_questions_unique', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->security_questions_number ?: 3 ) ) );
break;
}
else
{
$answers[ $v ] = $v;
}
}
}
}
if ( !$form->error )
{
/* Create Member */
$member = \IPS\core\modules\front\system\register::_createMember( $values, $profileFields );
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->register( $form, new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) ) );
};
/* Log them in */
\IPS\Session::i()->setMember( $member );
\IPS\Member\Device::loadOrCreate( $member, FALSE )->updateAfterAuthentication( TRUE, '' );
$redirectUrl = \IPS\Login::getRegistrationDestination( $member );
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'redirect' => (string) $redirectUrl ) );
}
else
{
\IPS\Output::i()->redirect( $redirectUrl );
}
}
}
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=register', NULL, 'register' ), array(), 'loc_registering' );
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('registration');
\IPS\Output::i()->output = (string) new \IPS\Helpers\Wizard( $steps, \IPS\Http\Url::internal( 'app=core&module=system&controller=register' ), FALSE );
return $form;
}
/**
* Finish
*
* @return void
*/
public function finish()
{
$steps = \IPS\Member\ProfileStep::loadAll();
/* Do we need to bother? We should only show this form if there are required items, but will show both required and suggested where possible to allow the user to complete as much of their profile as possible */
$haveRequired = FALSE;
foreach( $steps AS $id => $step )
{
if ( $step->required )
{
$haveRequired = TRUE;
break;
}
}
if ( $haveRequired === FALSE )
{
/* Nope, forward */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
}
$wizardSteps = array();
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=finish', 'front', 'register' );
foreach( \IPS\Application::allExtensions( 'core', 'ProfileSteps' ) AS $extension )
{
if ( method_exists( $extension, 'wizard') AND count( $extension::wizard() ) )
{
$wizardSteps = array_merge( $wizardSteps, $extension::wizard() );
}
}
$wizardSteps = array_merge( $wizardSteps, array( 'profile_done' => function( $data ) {
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'saved' );
} ) );
$wizard = new \IPS\Helpers\Wizard( $wizardSteps, $url, TRUE, NULL, TRUE );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( '2fa.css', 'core', 'global' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/settings.css' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('complete_profile_registration');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->finishRegistration( $wizard );
}
/**
* Build Registration Form
*
@@ -205,14 +292,21 @@ class _register extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password' ) ) );
/* Profile fields */
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
if ( ! \IPS\Settings::i()->quick_register )
{
foreach ( $fields as $field )
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
{
$form->add( $field );
foreach ( $fields as $field )
{
$form->add( $field );
}
}
$form->addSeparator();
}
else
{
$form->class = 'ipsForm_vertical';
}
$form->addSeparator();
$question = FALSE;
try
@@ -221,53 +315,8 @@ class _register extends \IPS\Dispatcher\Controller
}
catch ( \UnderflowException $e ) {}
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
{
$numberOfQuestions = \IPS\Settings::i()->security_questions_number ?: 3;
$securityQuestions = array();
foreach ( \IPS\MFA\SecurityQuestions\Question::roots() as $securityQuestion )
{
$securityQuestions[ $securityQuestion->id ] = $securityQuestion->_title;
}
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack('security_questions_setup_blurb', FALSE, array( 'pluralize' => array( $numberOfQuestions ) ) ) );
if ( \IPS\Settings::i()->security_questions_prompt === 'optional' )
{
$securityOptoutToggles = array();
foreach ( range( 1, min( $numberOfQuestions, count( $securityQuestions ) ) ) as $i )
{
$securityOptoutToggles[] = 'security_question_q_' . $i;
$securityOptoutToggles[] = 'security_question_a_' . $i;
}
$optOutCheckbox = new \IPS\Helpers\Form\Checkbox( 'security_questions_optout_title', FALSE, FALSE, array( 'togglesOff' => $securityOptoutToggles ) );
if ( \IPS\Member::loggedIn()->language()->checkKeyExists('security_questions_opt_out_warning_value') )
{
$optOutCheckbox->description = \IPS\Member::loggedIn()->language()->addToStack('security_questions_opt_out_warning_value');
}
$form->add( $optOutCheckbox );
}
foreach ( range( 1, min( $numberOfQuestions, count( $securityQuestions ) ) ) as $i )
{
$securityValidation = function( $val ) {
if ( !$val and ( \IPS\Settings::i()->security_questions_prompt === 'register' or !isset( \IPS\Request::i()->security_questions_optout_title_checkbox ) ) )
{
throw new \DomainException('form_required');
}
};
$questionField = new \IPS\Helpers\Form\Select( 'security_question_q_' . $i, NULL, FALSE, array( 'options' => $securityQuestions ), $securityValidation, NULL, NULL, 'security_question_q_' . $i );
$questionField->label = \IPS\Member::loggedIn()->language()->addToStack('security_question_q');
$answerField = new \IPS\Helpers\Form\Text( 'security_question_a_' . $i, NULL, NULL, array(), $securityValidation, NULL, NULL, 'security_question_a_' . $i );
$answerField->label = \IPS\Member::loggedIn()->language()->addToStack('security_question_a');
$form->add( $questionField );
$form->add( $answerField );
}
$form->addSeparator();
}
/* 2FA Q&A? */
static::addQuestion2FA( $form );
/* Random Q&A */
if( $question )
@@ -354,15 +403,74 @@ class _register extends \IPS\Dispatcher\Controller
} ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_system.js', 'core', 'front' ), \IPS\Output::i()->js( 'front_templates.js', 'core', 'front' ) );
return $form;
}
/**
* Add in the Q&A 2FA if it is enforced
*
* @param \IPS\Form $form Form
* @return void
*/
protected static function addQuestion2FA( &$form )
{
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
{
$numberOfQuestions = \IPS\Settings::i()->security_questions_number ?: 3;
$securityQuestions = array();
foreach ( \IPS\MFA\SecurityQuestions\Question::roots() as $securityQuestion )
{
$securityQuestions[ $securityQuestion->id ] = $securityQuestion->_title;
}
$form->addMessage( \IPS\Member::loggedIn()->language()->addToStack('security_questions_setup_blurb', FALSE, array( 'pluralize' => array( $numberOfQuestions ) ) ) );
if ( \IPS\Settings::i()->security_questions_prompt === 'optional' )
{
$securityOptoutToggles = array();
foreach ( range( 1, min( $numberOfQuestions, count( $securityQuestions ) ) ) as $i )
{
$securityOptoutToggles[] = 'security_question_q_' . $i;
$securityOptoutToggles[] = 'security_question_a_' . $i;
}
$optOutCheckbox = new \IPS\Helpers\Form\Checkbox( 'security_questions_optout_title', FALSE, FALSE, array( 'togglesOff' => $securityOptoutToggles ) );
if ( \IPS\Member::loggedIn()->language()->checkKeyExists('security_questions_opt_out_warning_value') )
{
$optOutCheckbox->description = \IPS\Member::loggedIn()->language()->addToStack('security_questions_opt_out_warning_value', TRUE, array( 'returnBlank' => TRUE ) );
}
$form->add( $optOutCheckbox );
}
foreach ( range( 1, min( $numberOfQuestions, count( $securityQuestions ) ) ) as $i )
{
$securityValidation = function( $val ) {
if ( !$val and ( \IPS\Settings::i()->security_questions_prompt === 'register' or !isset( \IPS\Request::i()->security_questions_optout_title_checkbox ) ) )
{
throw new \DomainException('form_required');
}
};
$questionField = new \IPS\Helpers\Form\Select( 'security_question_q_' . $i, NULL, FALSE, array( 'options' => $securityQuestions ), $securityValidation, NULL, NULL, 'security_question_q_' . $i );
$questionField->label = \IPS\Member::loggedIn()->language()->addToStack('security_question_q');
$answerField = new \IPS\Helpers\Form\Text( 'security_question_a_' . $i, NULL, NULL, array(), $securityValidation, NULL, NULL, 'security_question_a_' . $i );
$answerField->label = \IPS\Member::loggedIn()->language()->addToStack('security_question_a');
$form->add( $questionField );
$form->add( $answerField );
}
$form->addSeparator();
}
}
/**
* Create Member
*
* @param array $values Values from form
* @param array $profileFields Profile field values from registration
* @return \IPS\Member
* @param array $values Values from form
* @param array $profileFields Profile field values from registration
* @return \IPS\Member
*/
public static function _createMember( $values, $profileFields )
{
@@ -385,15 +493,28 @@ class _register extends \IPS\Dispatcher\Controller
}
}
/* Save */
/* Initial Save */
$member->save();
/* This looks a bit weird, but the extensions expect an account to exist at this point, so we'll let the system save it now, then do what we need to do, then save again */
foreach( \IPS\Member\ProfileStep::loadAll() AS $step )
{
$extension = $step->extension;
$extension::formatFormValues( $values, $member, $form );
}
/* Save anything the profile extensions did */
$member->save();
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
{
if ( $values['security_questions_optout_title'] )
if ( isset( $values['security_questions_optout_title'] ) )
{
$member->members_bitoptions['security_questions_opt_out'] = TRUE;
/* Log MFA Opt-out */
$member->logHistory( 'core', 'mfa', array( 'handler' => 'questions', 'enable' => FALSE, 'optout' => TRUE ) );
}
else
{
@@ -417,12 +538,18 @@ class _register extends \IPS\Dispatcher\Controller
}
$member->members_bitoptions['has_security_answers'] = TRUE;
/* Log MFA Enable */
$member->logHistory( 'core', 'mfa', array( 'handler' => 'questions', 'enable' => TRUE ) );
}
$member->save();
}
/* Save custom field values */
\IPS\Db::i()->replace( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ) );
if ( ! \IPS\Settings::i()->quick_register )
{
\IPS\Db::i()->replace( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ) );
}
/* Handle validation */
$member->postRegistration();
@@ -548,6 +675,7 @@ class _register extends \IPS\Dispatcher\Controller
/* Log in and Redirect */
\IPS\Session::i()->setMember( $member );
\IPS\Member\Device::loadOrCreate( $member )->updateAfterAuthentication( TRUE );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'validate_email_confirmation' );
}
}
@@ -678,6 +806,13 @@ class _register extends \IPS\Dispatcher\Controller
}
\IPS\Member::loggedIn()->save();
/* Invalidate sessions except this one */
\IPS\Member::loggedIn()->invalidateSessionsAndLogins( \IPS\Session::i()->id );
if( isset( \IPS\Request::i()->cookie['login_key'] ) )
{
\IPS\Member\Device::loadOrCreate( \IPS\Member::loggedIn() )->updateAfterAuthentication( TRUE );
}
/* If email validation is required, do that... */
if ( in_array( \IPS\Settings::i()->reg_auth_type, array( 'user', 'admin_user' ) ) )
{
@@ -728,17 +863,7 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Request::i()->confirmedDelete( 'reg_cancel', 'reg_cancel_confirm', 'reg_cancel' );
/* Log the user out. Previously, we immediately deleted the account however this has been changed to let the cleanup task handle this instead. */
\IPS\Request::i()->setCookie( 'member_id', NULL );
\IPS\Request::i()->setCookie( 'pass_hash', NULL );
\IPS\Request::i()->setCookie( 'anon_login', NULL );
foreach( \IPS\Request::i()->cookie as $name => $value )
{
if( mb_strpos( $name, "ipbforumpass_" ) !== FALSE )
{
\IPS\Request::i()->setCookie( $name, NULL );
}
}
\IPS\Request::i()->clearLoginCookies();
/* Reset session global parameters */
$_SESSION = array();
@@ -1,12 +1,11 @@
<?php
/**
* @brief User CP Controller
* @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
* @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 10 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -144,8 +143,21 @@ class _settings extends \IPS\Dispatcher\Controller
{
$services[$key] = new $class( \IPS\Member::loggedIn() );
}
$nextStep = NULL;
if ( $completed = \IPS\Member::loggedIn()->profileCompletion() AND count( $completed['suggested'] ) )
{
foreach( $completed['suggested'] AS $id => $complete )
{
if ( !$complete )
{
$nextStep = \IPS\Member\ProfileStep::load( $id );
break;
}
}
}
return \IPS\Theme::i()->getTemplate( 'system' )->settingsOverview( $services );
return \IPS\Theme::i()->getTemplate( 'system' )->settingsOverview( $services, $nextStep );
}
/**
@@ -169,17 +181,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
\IPS\Output::i()->output = $mfaOutput;
}
/* Do we have any pending validation emails? */
try
{
$pending = \IPS\Db::i()->select( '*', 'core_validating', array( 'member_id=? AND email_chg=1', \IPS\Member::loggedIn()->member_id ), 'entry_date DESC' )->first();
}
catch( \UnderflowException $e )
{
$pending = null;
}
/* Build the form */
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_collapseTablet';
@@ -202,12 +204,16 @@ class _settings extends \IPS\Dispatcher\Controller
}
catch( \BadMethodCallException $e ){}
}
/* Invalidate sessions except this one */
\IPS\Member::loggedIn()->invalidateSessionsAndLogins( \IPS\Session::i()->id );
if( isset( \IPS\Request::i()->cookie['login_key'] ) )
{
\IPS\Member\Device::loadOrCreate( \IPS\Member::loggedIn() )->updateAfterAuthentication( TRUE );
}
/* Delete any pending validation emails */
if ( $pending['vid'] )
{
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND email_chg=1', \IPS\Member::loggedIn()->member_id ) );
}
\IPS\Db::i()->delete( 'core_validating', array( 'member_id=? AND email_chg=1', \IPS\Member::loggedIn()->member_id ) );
/* Send a validation email if we need to */
if ( \IPS\Settings::i()->reg_auth_type == 'user' or \IPS\Settings::i()->reg_auth_type == 'admin_user' )
@@ -285,12 +291,11 @@ class _settings extends \IPS\Dispatcher\Controller
catch( \BadMethodCallException $e ){}
}
/* If we have a pass_hash cookie, update it so we stay logged in on the next page load */
if( isset( \IPS\Request::i()->cookie['pass_hash'] ) )
/* Invalidate sessions except this one */
\IPS\Member::loggedIn()->invalidateSessionsAndLogins( \IPS\Session::i()->id );
if( isset( \IPS\Request::i()->cookie['login_key'] ) )
{
$expire = new \IPS\DateTime;
$expire->add( new \DateInterval( 'P3M' ) );
\IPS\Request::i()->setCookie( 'pass_hash', \IPS\Member::loggedIn()->member_login_key, $expire );
\IPS\Member\Device::loadOrCreate( \IPS\Member::loggedIn() )->updateAfterAuthentication( TRUE );
}
/* Send a confirmation email */
@@ -301,6 +306,128 @@ class _settings extends \IPS\Dispatcher\Controller
return \IPS\Theme::i()->getTemplate( 'system' )->settingsPassword( $form );
}
/**
* Devices
*
* @return string
*/
protected function _devices()
{
$mfaOutput = \IPS\MFA\MFAHandler::accessToArea( 'core', 'DeviceManagement', \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=devices', 'front', 'settings_devices' ) );
if ( $mfaOutput )
{
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=devices', 'front', 'settings_devices' ) );
}
\IPS\Output::i()->output = $mfaOutput;
return \IPS\Theme::i()->getTemplate( 'system' )->settingsDevices( array(), array() );
}
$devices = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members_known_devices', array( 'member_id=? AND last_seen>?', \IPS\Member::loggedIn()->member_id, ( new \DateTime )->sub( new \DateInterval( \IPS\Member\Device::LOGIN_KEY_VALIDITY ) )->getTimestamp() ), 'last_seen DESC' ), 'IPS\Member\Device' );
$locations = array();
$ipAddresses = array();
foreach ( \IPS\Db::i()->select( '*', 'core_members_known_ip_addresses', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), 'last_seen DESC' ) as $log )
{
if ( \IPS\Settings::i()->ipsgeoip )
{
if ( !array_key_exists( $log['ip_address'], $locations ) )
{
try
{
$locations[ $log['ip_address'] ] = \IPS\GeoLocation::getByIp( $log['ip_address'] );
}
catch ( \Exception $e )
{
$locations[ $log['ip_address'] ] = \IPS\Member::loggedIn()->language()->addToStack('unknown');
}
}
$ipAddresses[ $log['device_key'] ][ $log['ip_address'] ] = array(
'location' => $locations[ $log['ip_address'] ],
'date' => $log['last_seen']
);
}
else
{
$ipAddresses[ $log['device_key'] ][ $log['ip_address'] ] = array(
'date' => $log['last_seen']
);
}
}
return \IPS\Theme::i()->getTemplate( 'system' )->settingsDevices( $devices, $ipAddresses );
}
/**
* Secure Account
*
* @return string
*/
protected function secureAccount()
{
/* Only logged in members */
if ( !\IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission_guest', '2C122/Q', 403, '' );
}
$canChangePassword = FALSE;
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
if ( $handler->canChange( 'password', \IPS\Member::loggedIn() ) )
{
$canChangePassword = TRUE;
}
}
$canConfigureMfa = FALSE;
$hasConfiguredMfa = FALSE;
foreach ( \IPS\MFA\MFAHandler::handlers() as $handler )
{
if ( $handler->isEnabled() and $handler->memberCanUseHandler( \IPS\Member::loggedIn() ) )
{
$canConfigureMfa = TRUE;
if ( $handler->memberHasConfiguredHandler( \IPS\Member::loggedIn() ) )
{
$hasConfiguredMfa = TRUE;
break;
}
}
}
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'secure_account' );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings', 'front', 'settings' ), \IPS\Member::loggedIn()->language()->addToStack('settings') );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('secure_account') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->settingsSecureAccount( $canChangePassword, $canConfigureMfa, $hasConfiguredMfa, $services );
}
/**
* Disable Automatic Login
*
* @return string
*/
protected function disableAutomaticLogin()
{
\IPS\Session::i()->csrfCheck();
try
{
$device = \IPS\Member\Device::loadAndAuthenticate( \IPS\Request::i()->device, \IPS\Member::loggedIn() );
$device->login_key = NULL;
$device->save();
\IPS\Db::i()->delete( 'core_sessions', array( 'member_id=? AND browser=? AND id<>?', $device->member_id, $device->user_agent, \IPS\Session::i()->id ) );
}
catch ( \Exception $e ) { }
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=devices', 'front', 'settings_devices' ) );
}
/**
* MFA
@@ -376,6 +503,8 @@ class _settings extends \IPS\Dispatcher\Controller
if ( isset( \IPS\Request::i()->mfa_setup ) )
{
\IPS\Session::i()->csrfCheck();
foreach ( $handlers as $key => $handler )
{
if ( ( count( $handlers ) == 1 ) or $key == \IPS\Request::i()->mfa_method )
@@ -399,6 +528,8 @@ class _settings extends \IPS\Dispatcher\Controller
if ( isset( \IPS\Request::i()->_mfa ) and \IPS\Request::i()->_mfa == 'optout' )
{
\IPS\Session::i()->csrfCheck();
\IPS\Member::loggedIn()->members_bitoptions['security_questions_opt_out'] = TRUE;
\IPS\Member::loggedIn()->save();
\IPS\Output::i()->redirect( $ref );
@@ -416,6 +547,8 @@ class _settings extends \IPS\Dispatcher\Controller
*/
protected function enableMfa()
{
\IPS\Session::i()->csrfCheck();
/* Get the handler */
$handlers = \IPS\MFA\MFAHandler::handlers();
$key = \IPS\Request::i()->type;
@@ -433,6 +566,8 @@ class _settings extends \IPS\Dispatcher\Controller
/* Did we just submit it? */
if ( isset( \IPS\Request::i()->mfa_setup ) and $handlers[ $key ]->configurationScreenSubmit( \IPS\Member::loggedIn() ) )
{
$_SESSION['MFAAuthenticated'] = time();
\IPS\Member::loggedIn()->members_bitoptions['security_questions_opt_out'] = FALSE;
\IPS\Member::loggedIn()->save();
@@ -451,6 +586,8 @@ class _settings extends \IPS\Dispatcher\Controller
*/
protected function disableMfa()
{
\IPS\Session::i()->csrfCheck();
/* Get the handler */
$handlers = \IPS\MFA\MFAHandler::handlers();
$key = \IPS\Request::i()->type;
@@ -572,13 +709,13 @@ class _settings extends \IPS\Dispatcher\Controller
{
$member = \IPS\Member::loggedIn();
}
/* Can we use this? */
if ( !$member->member_id or !( ( $member->failed_mfa_attempts >= \IPS\Settings::i()->security_questions_tries and \IPS\Settings::i()->mfa_lockout_behaviour == 'email' ) or in_array( 'email', explode( ',', \IPS\Settings::i()->mfa_forgot_behaviour ) ) ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C122/L', 403, '' );
}
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
@@ -703,9 +840,11 @@ class _settings extends \IPS\Dispatcher\Controller
}
/* How many changes */
$nameCount = \IPS\Db::i()->select( 'COUNT(*) as count, MIN(dname_date) as min_date', 'core_dnames_change', array(
'dname_member_id=? AND dname_date>?',
$nameCount = \IPS\Db::i()->select( 'COUNT(*) as count, MIN(log_date) as min_date', 'core_member_history', array(
'log_member=? AND log_app=? AND log_type=? AND log_date>?',
\IPS\Member::loggedIn()->member_id,
'core',
'display_name',
\IPS\DateTime::create()->sub( new \DateInterval( 'P' . \IPS\Member::loggedIn()->group['g_dname_date'] . 'D' ) )->getTimestamp()
) )->first();
@@ -854,8 +993,22 @@ class _settings extends \IPS\Dispatcher\Controller
{
$src = $image->getAttribute('src');
\IPS\Output::i()->parseFileObjectUrls( $src );
$imageProperties = @getimagesize( $src );
/* If we do not have any properties - remote fetch, and then check against the actual content as a fallback. We do this as a fallback as it can be slower. */
if ( !$imageProperties )
{
try
{
$imageContent = \IPS\Http\Url::external( $src )->request()->get();
$imageProperties = @getimagesizefromstring( (string) $imageContent );
}
catch( \IPS\Http\Request\Exception $e ) { }
}
}
else
{
$src = (string) \IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->url;
}
if( is_array( $imageProperties ) AND count( $imageProperties ) )
@@ -981,8 +1134,21 @@ class _settings extends \IPS\Dispatcher\Controller
$obj->save( $values );
}
$permissionRequest = 'permissionRequest_' . $service;
$extraPermissions = NULL;
$extraPermissionsButton = NULL;
if ( isset( \IPS\Request::i()->$permissionRequest ) )
{
$login = \IPS\Login\LoginAbstract::load( $class::$loginKey );
$url = \IPS\Http\Url::internal( "app=core&module=system&controller=settings&area=profilesync&service={$service}", 'front', "settings_{$service}" );
$extraPermissions = \IPS\Request::i()->$permissionRequest;
$extraPermissionsButton = $login->loginForm( $url, TRUE );
}
$photo = ( method_exists( $obj, 'photo' ) ) ? $obj->photo() : NULL;
return \IPS\Theme::i()->getTemplate( 'system' )->settingsProfileSync( $photo instanceof \IPS\File ? $photo->url : $photo, $headline, method_exists( $obj, 'status' ) ? $obj->status() : NULL, $form, $service, "profilesync__{$service}", ( $settings['photo'] or $settings['cover'] or $settings['status'] ) );
return \IPS\Theme::i()->getTemplate( 'system' )->settingsProfileSync( $photo instanceof \IPS\File ? $photo->url : $photo, $headline, method_exists( $obj, 'status' ) ? $obj->status() : NULL, $form, $service, "profilesync__{$service}", ( $settings['photo'] or $settings['cover'] or $settings['status'] ), $extraPermissions, $extraPermissionsButton );
}
else
{
@@ -1036,4 +1202,59 @@ class _settings extends \IPS\Dispatcher\Controller
$redirectUrl = ( !empty( $_SERVER['HTTP_REFERER'] ) ) ? \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( "app=core&module=system&controller=settings", 'front', 'settings' );
\IPS\Output::i()->redirect( $redirectUrl, 'signature_pref_toggled' );
}
/**
* Dismiss Profile Completion
*
* @return void
*/
protected function dismissProfile()
{
\IPS\Session::i()->csrfCheck();
\IPS\Member::loggedIn()->members_bitoptions['profile_completion_dismissed'] = TRUE;
\IPS\Member::loggedIn()->save();
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( 'OK' );
}
else
{
$redirectUrl = ( !empty( $_SERVER['HTTP_REFERER'] ) ) ? \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( "app=core&module=system&controller=settings", 'front', 'settings' );
\IPS\Output::i()->redirect( $redirectUrl );
}
}
/**
* Completion Wizard
*
* @return void
*/
protected function completion()
{
$steps = array();
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&do=completion', 'front', 'settings' );
foreach( \IPS\Application::allExtensions( 'core', 'ProfileSteps' ) AS $extension )
{
if ( method_exists( $extension, 'wizard') AND count( $extension::wizard() ) )
{
$steps = array_merge( $steps, $extension::wizard() );
}
}
$steps = array_merge( $steps, array( 'profile_done' => function( $data ) {
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=settings", 'front', 'settings' ), 'saved' );
} ) );
$wizard = new \IPS\Helpers\Wizard( $steps, $url, TRUE, NULL, TRUE );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( '2fa.css', 'core', 'global' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/settings.css' ) );
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'complete_your_profile' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->completeWizard( $wizard );
}
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Splash Controller
* @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
* @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 21 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Terms of Use
* @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
* @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 25 Sept 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Theme Changer
* @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
* @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 17 Dec 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -0,0 +1,81 @@
<?php
/**
* @brief Twitter Authentication
* @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 24 February 2017
*/
namespace IPS\core\modules\front\system;
/* 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;
}
/**
* Twitter auth for ACP
*/
class _twitter extends \IPS\Dispatcher\Controller
{
/**
* View Announcement
*
* @return void
*/
protected function manage()
{
if ( ! \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https )->setQueryString( 'ref', base64_encode( \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' ) ) ) );
}
$twitter = \IPS\Login::getHandler('Twitter');
$promote = \IPS\core\Promote::getPromoter( 'Twitter' );
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' );
try
{
/* Get a request token */
if ( !isset( \IPS\Request::i()->oauth_token ) )
{
$callback = $url->setQueryString( 'csrf', \IPS\Session::i()->csrfKey );
$response = $twitter->sendRequest( 'get', 'https://api.twitter.com/oauth/request_token', array( 'oauth_callback' => (string) $callback ) )->decodeQueryString('oauth_token');
\IPS\Output::i()->redirect( "https://api.twitter.com/oauth/authorize?force_login=1&oauth_token={$response['oauth_token']}" );
}
/* CSRF Check */
if ( \IPS\Request::i()->csrf !== \IPS\Session::i()->csrfKey )
{
throw new \IPS\Login\Exception( 'CSRF_FAIL', \IPS\Login\Exception::INTERNAL_ERROR );
}
/* Authenticate */
$response = $twitter->sendRequest( 'post', 'https://api.twitter.com/oauth/access_token', array( 'oauth_verifier' => \IPS\Request::i()->oauth_verifier ), \IPS\Request::i()->oauth_token )->decodeQueryString('user_id');
$user = $twitter->sendRequest( 'get', 'https://api.twitter.com/1.1/account/verify_credentials.json', array(), $response['oauth_token'], $response['oauth_token_secret'] )->decodeJson();
/* Store the settings */
$promote->saveSettings( array(
'id' => $response['user_id'],
'owner' => \IPS\Member::loggedIn()->member_id,
'secret' => $response['oauth_token_secret'],
'token' => $response['oauth_token'],
'name' => $user['screen_name']
) );
/* Show a done page */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('promote_twitter_sorted');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteTwitterComplete( $user );
}
catch ( \Exception $e )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
}
}
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Allow users to unsubscribe from site updates
* @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
* @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 12 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Visual Language Editor
* @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
* @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 27 Jun 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
+16 -7
View File
@@ -1,12 +1,11 @@
<?php
/**
* @brief Visual Theme Editor
* @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
* @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 7 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -98,7 +97,7 @@ class _vse extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form( 'form', NULL );
$settings = $theme->getThemeSettings();
$settingKeyValues = array();
foreach( $settings as $key => $data )
{
$settingKeyValues[ $key ] = $data['_value'];
@@ -121,7 +120,17 @@ class _vse extends \IPS\Dispatcher\Controller
// No break
case 'Radio':
$content = json_decode( $data['sc_content'], TRUE );
$options['options'] = ( is_array( $content ) ) ? $content : array();
$options = array();
if( is_array( $content ) )
{
foreach( $content as $_content )
{
$options[ $_content['key'] ] = $_content['value'];
}
}
$options['options'] = $options;
break;
}
@@ -1,12 +1,11 @@
<?php
/**
* @brief Member Warnings
* @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
* @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 18 Jul 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -1,12 +1,11 @@
<?php
/**
* @brief Sidebar Widgets
* @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
* @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 19 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\modules\front\system;
@@ -155,10 +154,11 @@ class _widgets extends \IPS\Dispatcher\Controller
try
{
$blocks = \IPS\Db::i()->select( '*', 'core_widget_areas', array( 'app=? AND module=? AND controller=? AND area=?', \IPS\Request::i()->pageApp, \IPS\Request::i()->pageModule, \IPS\Request::i()->pageController, \IPS\Request::i()->pageArea ) )->first();
$blocks = json_decode( $blocks['widgets'], TRUE );
$where = ( $key[0] ) == 'app' ? '`key`=? AND `app`=?' : '`key`=? AND `plugin`=?';
$widgetMaster = \IPS\Db::i()->select( '*', 'core_widgets', array( $where, $key[2], $key[1] ) )->first();
$blocks = \IPS\Db::i()->select( '*', 'core_widget_areas', array( 'app=? AND module=? AND controller=? AND area=?', \IPS\Request::i()->pageApp, \IPS\Request::i()->pageModule, \IPS\Request::i()->pageController, \IPS\Request::i()->pageArea ) )->first();
$blocks = json_decode( $blocks['widgets'], TRUE );
}
catch ( \UnderflowException $e )
{
@@ -219,7 +219,7 @@ class _widgets extends \IPS\Dispatcher\Controller
\IPS\Db::i()->insert( 'core_widget_areas', array( 'app' => \IPS\Request::i()->pageApp, 'module' => \IPS\Request::i()->pageModule, 'controller' => \IPS\Request::i()->pageController, 'area' => \IPS\Request::i()->pageArea, 'widgets' => json_encode( $blocks ) ), TRUE );
\IPS\Output::i()->json( 'OK' );
}
\IPS\Output::i()->sendOutput( $widget->configuration()->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'widgets', 'core' ) ), 'formTemplate' ), $widget ) );
\IPS\Output::i()->output = $widget->configuration()->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'widgets', 'core' ) ), 'formTemplate' ), $widget );
}
}
}