Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

@@ -60,6 +60,10 @@ class _directory extends \IPS\Dispatcher\Controller
protected function manage()
{
$baseUrl = \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' );
if ( isset( \IPS\Request::i()->view ) and in_array( \IPS\Request::i()->view, array( 'grid', 'list' ) ) )
{
$baseUrl = $baseUrl->setQueryString( 'view', \IPS\Request::i()->view );
}
/* All Clubs: Sort */
$sortOption = \IPS\Settings::i()->clubs_default_sort;
@@ -71,11 +75,25 @@ class _directory extends \IPS\Dispatcher\Controller
/* All Clubs: Filters */
$filters = array();
$mineOnly = FALSE;
$extraWhere = NULL;
if ( isset( \IPS\Request::i()->filter ) and \IPS\Request::i()->filter === 'mine' )
{
$mineOnly = TRUE;
$baseUrl = $baseUrl->setQueryString( 'filter', 'mine' );
}
if ( isset( \IPS\Request::i()->type ) and in_array( \IPS\Request::i()->type, array( 'free', 'paid' ) ) )
{
$baseUrl = $baseUrl->setQueryString( 'type', \IPS\Request::i()->type );
if ( \IPS\Request::i()->type === 'free' )
{
$extraWhere[] = array( 'fee IS NULL' );
}
else
{
$extraWhere[] = array( 'fee IS NOT NULL' );
}
}
foreach ( \IPS\Member\Club\CustomField::fields() as $field )
{
$k = "f{$field->id}";
@@ -100,7 +118,14 @@ class _directory extends \IPS\Dispatcher\Controller
{
if ( isset( $options[ $id ] ) )
{
$filters[ $field->id ][ $id ] = $options[ $id ];
if( $field->type == 'CheckboxSet' )
{
$filters[ $field->id ][ $id ] = $id;
}
else
{
$filters[ $field->id ][ $id ] = $options[ $id ];
}
}
}
$baseUrl = $baseUrl->setQueryString( 'f' . $field->id, array_keys( $filters[ $field->id ] ) );
@@ -116,8 +141,8 @@ class _directory extends \IPS\Dispatcher\Controller
/* 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 );
$allClubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), array( ( $page - 1 ) * $perPage, $perPage ), $sortOption, $mineOnly, $filters, $extraWhere );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( ( is_object( $allClubs ) ? $allClubs->count( TRUE ) : 0 ) / $perPage ), $page, $perPage );
/* Get my clubs */
$myClubsActivity = NULL;
@@ -128,7 +153,7 @@ class _directory extends \IPS\Dispatcher\Controller
/* Build Map */
$mapMarkers = NULL;
if ( \IPS\Settings::i()->googlemaps and \IPS\Settings::i()->google_maps_api_key )
if ( \IPS\GeoLocation::enabled() )
{
$mapMarkers = array();
@@ -139,7 +164,7 @@ class _directory extends \IPS\Dispatcher\Controller
}
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 );
$where[] = array( "( type<>? OR status IN('" . \IPS\Member\Club::STATUS_MEMBER . "','" . \IPS\Member\Club::STATUS_MODERATOR . "','" . \IPS\Member\Club::STATUS_LEADER . "','" . \IPS\Member\Club::STATUS_EXPIRED . "','" . \IPS\Member\Club::STATUS_EXPIRED_MODERATOR . "') )", \IPS\Member\Club::TYPE_PRIVATE );
}
$select = \IPS\Db::i()->select( array( 'id', 'name', 'location_lat', 'location_long' ), 'core_clubs', $where );
@@ -164,8 +189,21 @@ class _directory extends \IPS\Dispatcher\Controller
}
/* Display */
$view = \IPS\Settings::i()->clubs_default_view;
if ( \IPS\Settings::i()->clubs_allow_view_change )
{
if ( isset( \IPS\Request::i()->view ) and in_array( \IPS\Request::i()->view, array( 'grid', 'list' ) ) )
{
\IPS\Request::i()->setCookie( 'clubs_view', \IPS\Request::i()->view, \IPS\DateTime::create()->add( new \DateInterval('P1Y' ) ) );
$view = \IPS\Request::i()->view;
}
elseif ( isset( \IPS\Request::i()->cookie['clubs_view'] ) and in_array( \IPS\Request::i()->cookie['clubs_view'], array( 'grid', 'list' ) ) )
{
$view = \IPS\Request::i()->cookie['clubs_view'];
}
}
\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 );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clubs')->directory( $featuredClubs, $allClubs, $pagination, $baseUrl, $sortOption, $myClubsActivity, $mapMarkers, $view );
}
/**
@@ -187,6 +225,15 @@ class _directory extends \IPS\Dispatcher\Controller
) ) ) );
}
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on )
{
$form->add( new \IPS\Helpers\Form\Radio( 'club_membership_fee', isset( \IPS\Request::i()->type ) ? \IPS\Request::i()->type : 'all', TRUE, array( 'options' => array(
'all' => 'all_clubs',
'free' => 'club_membership_free',
'paid' => 'club_membership_paid'
) ) ) );
}
foreach ( $fields as $field )
{
if ( $field->filterable )
@@ -225,6 +272,11 @@ class _directory extends \IPS\Dispatcher\Controller
$url = $url->setQueryString( 'filter', 'mine' );
}
if ( \IPS\Application::appIsEnabled( 'nexus' ) and \IPS\Settings::i()->clubs_paid_on and $values['club_membership_fee'] !== 'all' )
{
$url = $url->setQueryString( 'type', $values['club_membership_fee'] );
}
foreach ( $fields as $field )
{
if ( $field->filterable )
@@ -273,11 +325,14 @@ class _directory extends \IPS\Dispatcher\Controller
protected function create()
{
$availableTypes = array();
foreach ( explode( ',', \IPS\Member::loggedIn()->group['g_create_clubs'] ) as $type )
if ( \IPS\Member::loggedIn()->member_id ) // Guests can't create any type of clubs
{
if ( $type !== '' )
foreach ( explode( ',', \IPS\Member::loggedIn()->group['g_create_clubs'] ) as $type )
{
$availableTypes[ $type ] = 'club_type_' . $type;
if ( $type !== '' )
{
$availableTypes[ $type ] = 'club_type_' . $type;
}
}
}
if ( !$availableTypes )
@@ -285,6 +340,14 @@ class _directory extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( \IPS\Member::loggedIn()->member_id ? 'no_module_permission' : 'no_module_permission_guest', '2C349/1', 403, '' );
}
if ( \IPS\Member::loggedIn()->group['g_club_limit'] )
{
if ( \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs', array( 'owner=?', \IPS\Member::loggedIn()->member_id ) )->first() >= \IPS\Member::loggedIn()->group['g_club_limit'] )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'too_many_clubs', FALSE, array( 'pluralize' => array( \IPS\Member::loggedIn()->group['g_club_limit'] ) ) ), '2C349/3', 403, '' );
}
}
$club = new \IPS\Member\Club;
if ( $form = $club->form( FALSE, TRUE, $availableTypes ) )
{
+473 -36
View File
@@ -105,6 +105,12 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*/
protected function manage()
{
/* Club info in sidebar */
if ( \IPS\Settings::i()->clubs_header == 'sidebar' )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'clubs', 'core' )->header( $this->club, NULL, 'sidebar' );
}
/* If this is a closed club, and we don't have permission to read it, show the member page instead */
if ( $this->club->type == \IPS\Member\Club::TYPE_CLOSED && !$this->club->canRead() )
{
@@ -113,7 +119,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get the activity stream */
$activity = \IPS\Content\Search\Query::init()->filterByClub( $this->club )->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_UPDATED )->search();
$activity = \IPS\Content\Search\Query::init()->filterByClub( $this->club )->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_CREATED )->search();
/* Get who joined the club in between those results */
if ( $this->club->type != \IPS\Member\Club::TYPE_PUBLIC )
@@ -121,7 +127,14 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$lastTime = NULL;
foreach ( $activity as $key => $result )
{
$lastTime = $result->createdDate->getTimestamp();
if ( $result !== NULL )
{
$lastTime = $result->createdDate->getTimestamp();
}
else
{
unset( $activity[ $key ] );
}
}
$joins = array();
$joinWhere = array( array( 'club_id=?', $this->club->id ), array( \IPS\Db::i()->in( 'status', array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER ) ) ) );
@@ -132,7 +145,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$select = 'core_clubs_memberships.joined' . ',' . implode( ',', array_map( function( $column ) {
return 'core_members.' . $column;
}, \IPS\Member::columnsForPhoto() ) );
foreach ( \IPS\Db::i()->select( $select, 'core_clubs_memberships', $joinWhere, 'joined DESC', NULL, NULL, NULL, \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS )->join( 'core_members', 'core_members.member_id=core_clubs_memberships.member_id' ) as $join )
foreach ( \IPS\Db::i()->select( $select, 'core_clubs_memberships', $joinWhere, 'joined DESC', array( 0, 50 ), NULL, NULL, \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS )->join( 'core_members', 'core_members.member_id=core_clubs_memberships.member_id' ) as $join )
{
$joins[] = new \IPS\Content\Search\Result\Custom(
\IPS\DateTime::ts( $join['core_clubs_memberships']['joined'] ),
@@ -144,7 +157,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Merge them in */
if ( !empty( $joins ) )
{
$activity = array_merge( iterator_to_array( $activity ), $joins );
$activity = array_filter( array_merge( iterator_to_array( $activity ), $joins ) );
uasort( $activity, function( $a, $b )
{
if ( $a->createdDate->getTimestamp() == $b->createdDate->getTimestamp() )
@@ -163,7 +176,8 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
}
/* Display */
/* Display */
\IPS\Output::i()->linkTags['canonical'] = (string) $this->club->url();
\IPS\Output::i()->title = $this->club->name;
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('clubs')->view( $this->club, $activity, $this->club->fieldValues() );
}
@@ -215,7 +229,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*/
protected function editPhoto()
{
if ( !( $this->club->owner and $this->club->owner == \IPS\Member::loggedIn() ) and !\IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
if ( !$this->club->isLeader() )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/R', 403, '' );
}
@@ -301,7 +315,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$form->add( new \IPS\Helpers\Form\Custom('photo_crop', array( 0, 0, $suggestedWidth, $suggestedHeight ), FALSE, array(
'getHtml' => function( $field ) use ( $original )
{
return \IPS\Theme::i()->getTemplate('profile')->photoCrop( $field->name, $field->value, $this->club->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
return \IPS\Theme::i()->getTemplate('members', 'core', 'global')->photoCrop( $field->name, $field->value, $this->club->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
}
) ) );
@@ -323,7 +337,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Save it */
$croppedFilename = mb_substr( $original->originalFilename, 0, mb_strrpos( $original->originalFilename, '.' ) ) . '.cropped' . mb_substr( $original->originalFilename, mb_strrpos( $original->originalFilename, '.' ) );
$cropped = \IPS\File::create( 'core_Profile', $original->originalFilename, (string) $image );
$cropped = \IPS\File::create( 'core_Clubs', $croppedFilename, (string) $image );
$this->club->profile_photo = (string) $cropped;
$this->club->save();
@@ -389,12 +403,21 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
break;
case \IPS\Member\Club::STATUS_WAITING_PAYMENT:
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_WAITING_PAYMENT;
$statuses = array( \IPS\Member\Club::STATUS_WAITING_PAYMENT );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_WAITING_PAYMENT );
}
break;
case \IPS\Member\Club::STATUS_BANNED:
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_BANNED;
$statuses = array( \IPS\Member\Club::STATUS_DECLINED, \IPS\Member\Club::STATUS_BANNED );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_REQUESTED );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_BANNED );
}
break;
@@ -402,10 +425,19 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_INVITED;
$statuses = array( \IPS\Member\Club::STATUS_INVITED );
$statuses = array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_INVITED );
}
break;
case \IPS\Member\Club::STATUS_EXPIRED:
if ( $this->club->isLeader() )
{
$filter = \IPS\Member\Club::STATUS_EXPIRED;
$statuses = array( \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR );
$baseUrl = $baseUrl->setQueryString( 'filter', \IPS\Member\Club::STATUS_EXPIRED );
}
break;
}
}
@@ -420,11 +452,18 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Sort out the offset */
$perPage = 28;
$activePage = isset( \IPS\Request::i()->page ) ? intval( \IPS\Request::i()->page ) : 1;
if( $activePage < 1 )
{
$activePage = 1;
}
$offset = ( $activePage - 1 ) * $perPage;
/* Fetch them */
$members = $this->club->members( $statuses, array( $offset, $perPage ), $orderByClause, $this->club->isLeader() ? 3 : 1 );
$members = $this->club->members( $statuses, array( $offset, $perPage ), $orderByClause, $this->club->isLeader() ? 5 : 1 );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $members->count(TRUE) / $perPage ), $activePage, $perPage );
/* Display */
@@ -434,9 +473,16 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
$staffStatuses = array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR );
if ( $this->club->isLeader( \IPS\Member::loggedIn() ) )
{
$staffStatuses[] = \IPS\Member\Club::STATUS_EXPIRED_MODERATOR;
}
$clubStaff = $this->club->members( $staffStatuses, NULL, "IF(core_clubs_memberships.status='leader',0,1), core_clubs_memberships.joined ASC", $this->club->isLeader( \IPS\Member::loggedIn() ) ? 5 : 3 );
\IPS\Output::i()->title = $this->club->name;
\IPS\Output::i()->breadcrumb[] = array( $this->club->url()->setQueryString( 'do', 'members' ), \IPS\Member::loggedIn()->language()->addToStack('club_members') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'clubs' )->members( $this->club, $members, $pagination, $sortBy, $filter );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'clubs' )->members( $this->club, $members, $pagination, $sortBy, $filter, $clubStaff );
}
}
@@ -464,7 +510,12 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Add them */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE, \IPS\Member::loggedIn(), NULL, TRUE );
$status = \IPS\Member\Club::STATUS_MEMBER;
if ( $this->club->isPaid() and !isset( \IPS\Request::i()->waiveFee ) )
{
$status = \IPS\Member\Club::STATUS_WAITING_PAYMENT;
}
$this->club->addMember( $member, $status, TRUE, \IPS\Member::loggedIn(), NULL, TRUE );
$this->club->recountMembers();
/* Notify the member */
@@ -574,7 +625,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR ) ) )
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/7', 403, '' );
}
@@ -603,14 +654,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
$member = ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on ) ? \IPS\nexus\Customer::load( \IPS\Request::i()->member ) : \IPS\Member::load( \IPS\Request::i()->member );
if ( $this->club->memberStatus( $member ) != \IPS\Member\Club::STATUS_LEADER )
{
\IPS\Output::i()->error( 'node_error', '2C350/9', 403, '' );
}
/* Are they expired? */
$status = \IPS\Member\Club::STATUS_MEMBER;
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->club->renewal_price )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
if ( $purchase->expire and $purchase->expire->getTimestamp() < time() )
{
$status = \IPS\Member\Club::STATUS_EXPIRED;
}
}
}
/* Promote */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
$this->club->addMember( $member, $status, TRUE );
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
@@ -633,14 +697,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_LEADER ) ) )
$member = ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on ) ? \IPS\nexus\Customer::load( \IPS\Request::i()->member ) : \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_LEADER ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/L', 403, '' );
}
/* Are they expired? */
$status = \IPS\Member\Club::STATUS_MODERATOR;
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->club->renewal_price )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
if ( $purchase->expire and $purchase->expire->getTimestamp() < time() )
{
$status = \IPS\Member\Club::STATUS_EXPIRED_MODERATOR;
}
}
}
/* Promote */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MODERATOR, TRUE );
$this->club->addMember( $member, $status, TRUE );
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
@@ -663,14 +740,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
if ( $this->club->memberStatus( $member ) != \IPS\Member\Club::STATUS_MODERATOR )
$member = ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on ) ? \IPS\nexus\Customer::load( \IPS\Request::i()->member ) : \IPS\Member::load( \IPS\Request::i()->member );
if ( !in_array( $this->club->memberStatus( $member ), array( \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/N', 403, '' );
}
/* Are they expired? */
$status = \IPS\Member\Club::STATUS_MEMBER;
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on and $this->club->renewal_price )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
if ( $purchase->expire and $purchase->expire->getTimestamp() < time() )
{
$status = \IPS\Member\Club::STATUS_EXPIRED;
}
}
}
/* Promote */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
$this->club->addMember( $member, $status, TRUE );
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
@@ -695,17 +785,218 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Get member */
$member = \IPS\Member::load( \IPS\Request::i()->member );
$status = $this->club->memberStatus( $member );
if ( !in_array( $status, array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER ) ) )
/* If this was just an invite, then just remove that */
if ( in_array( $status, array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/9', 403, '' );
}
if ( $this->club->owner and $this->club->owner->member_id === $member->member_id )
{
\IPS\Output::i()->error( 'club_cannot_remove_owner', '2C350/E', 403, '' );
$this->club->removeMember( $member );
\IPS\Db::i()->delete( 'core_notifications', array( 'member=? AND notification_app=? AND notification_key=? and item_id=?', $member->member_id, 'core', 'club_invitation', $this->club->id ) );
$member->recountNotifications();
}
/* Remove */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_BANNED, TRUE, \IPS\Member::loggedIn() );
/* If they were previously accepted and waiting for payment, treat it as a decline */
elseif ( in_array( $status, array( \IPS\Member\Club::STATUS_WAITING_PAYMENT ) ) )
{
/* Decline them */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_DECLINED, TRUE, \IPS\Member::loggedIn() );
/* Notify the member */
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'club_response', $this->club, array( $this->club, FALSE ) );
$notification->recipients->attach( $member );
$notification->send();
}
/* Otherwise check they are actually a member that can be removed */
else
{
if ( !in_array( $status, array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'node_error', '2C350/9', 403, '' );
}
if ( $this->club->owner and $this->club->owner->member_id === $member->member_id )
{
\IPS\Output::i()->error( 'club_cannot_remove_owner', '2C350/E', 403, '' );
}
/* Cancel purchase */
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( \IPS\nexus\Customer::load( \IPS\Request::i()->member ), $this->club->id ) as $purchase )
{
$purchase->cancelled = TRUE;
$purchase->member->log( 'purchase', array( 'type' => 'cancel', 'id' => $purchase->id, 'name' => $purchase->name ) );
$purchase->can_reactivate = FALSE;
$purchase->save();
}
}
/* Remove */
$this->club->addMember( $member, \IPS\Member\Club::STATUS_BANNED, TRUE, \IPS\Member::loggedIn() );
}
/* Recount */
$this->club->recountMembers();
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
}
/**
* Waive membership fee
*
* @return void
*/
protected function bypassPayment()
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Permission check */
if ( !$this->club->isLeader() or !\IPS\Application::appIsEnabled('nexus') or !\IPS\Settings::i()->clubs_paid_on )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/W', 403, '' );
}
/* Get member */
$member = \IPS\nexus\Customer::load( \IPS\Request::i()->member );
/* Do it */
switch ( $this->club->memberStatus( $member ) )
{
/* If they were waiting for payment, just go ahead and promote them to a member */
case \IPS\Member\Club::STATUS_WAITING_PAYMENT:
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
break;
/* If they were already in the club, find their purchase and remove the expiry date */
case \IPS\Member\Club::STATUS_MEMBER:
case \IPS\Member\Club::STATUS_EXPIRED:
case \IPS\Member\Club::STATUS_MODERATOR:
case \IPS\Member\Club::STATUS_EXPIRED_MODERATOR:
case \IPS\Member\Club::STATUS_LEADER:
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
$extra = $purchase->extra;
$extra['originalExpire'] = $purchase->expire ? $purchase->expire->getTimestamp() : NULL;
$purchase->extra = $extra;
$purchase->expire = NULL;
$purchase->save();
$member->log( 'purchase', array( 'type' => 'info', 'info' => 'never_expire', 'id' => $purchase->id, 'name' => $purchase->name ) );
}
break;
/* If they have been invited, just change their status to invited bypassing payment */
case \IPS\Member\Club::STATUS_INVITED:
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT, TRUE );
break;
/* For anything else, we can't do this... */
default:
\IPS\Output::i()->error( 'node_error', '2C350/X', 403, '' );
}
$this->club->recountMembers();
/* Redirect */
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'members' ) );
}
/**
* Restore Payment
*
* @return void
*/
protected function restorePayment()
{
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Permission check */
if ( !$this->club->isLeader() or !\IPS\Application::appIsEnabled('nexus') or !\IPS\Settings::i()->clubs_paid_on )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/W', 403, '' );
}
/* Get member */
$member = \IPS\nexus\Customer::load( \IPS\Request::i()->member );
/* Do it */
$status = $this->club->memberStatus( $member );
switch ( $status )
{
/* If they were already in the club, find their purchase and restore the expiry date */
case \IPS\Member\Club::STATUS_MEMBER:
case \IPS\Member\Club::STATUS_EXPIRED:
case \IPS\Member\Club::STATUS_MODERATOR:
case \IPS\Member\Club::STATUS_EXPIRED_MODERATOR:
case \IPS\Member\Club::STATUS_LEADER:
$foundPurchase = FALSE;
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( $member, $this->club->id ) as $purchase )
{
$foundPurchase = TRUE;
if ( !$purchase->renewals or !$purchase->renewals->cost->amount->isZero() )
{
$purchase->renewals = $this->club->renewalTerm( $purchase->renewal_currency ?: $member->defaultCurrency() );
}
if ( isset( $purchase->extra['originalExpire'] ) )
{
$newExpiry = \IPS\DateTime::ts( $purchase->extra['originalExpire'] );
}
else
{
$newExpiry = \IPS\DateTime::create()->add( $purchase->renewals->interval );
}
$purchase->expire = $newExpiry;
$purchase->save();
$member->log( 'purchase', array( 'type' => 'info', 'info' => 'restored_expire', 'id' => $purchase->id, 'name' => $purchase->name ) );
if ( $newExpiry->getTimestamp() < time() )
{
if ( $status === \IPS\Member\Club::STATUS_MEMBER )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_EXPIRED, TRUE );
}
elseif ( $status === \IPS\Member\Club::STATUS_MODERATOR )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR, TRUE );
}
}
else
{
if ( $status === \IPS\Member\Club::STATUS_EXPIRED )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MEMBER, TRUE );
}
elseif ( $status === \IPS\Member\Club::STATUS_EXPIRED_MODERATOR )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_MODERATOR, TRUE );
}
}
}
/* If we couldn't find a purchase, we'll have to remove them and re-invite them */
if ( !$foundPurchase )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED, TRUE, NULL, \IPS\Member::loggedIn(), TRUE );
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'club_invitation', $this->club, array( $this->club, \IPS\Member::loggedIn() ), array( 'invitedBy' => \IPS\Member::loggedIn()->member_id ) );
$notification->recipients->attach( $member );
$notification->send();
}
break;
/* If they have been invited, just change their status to invited NOT bypassing payment */
case \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT:
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED, TRUE );
break;
/* For anything else, we can't do this... */
default:
\IPS\Output::i()->error( 'node_error', '2C350/X', 403, '' );
}
$this->club->recountMembers();
/* Redirect */
@@ -729,11 +1020,55 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Session::i()->csrfCheck();
/* If this is an open club, or the member was invited, or they have mod access anyway go ahead and add them */
if ( $this->memberStatus === \IPS\Member\Club::STATUS_INVITED or $this->club->type === \IPS\Member\Club::TYPE_OPEN or \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
if ( in_array( $this->memberStatus, array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT, \IPS\Member\Club::STATUS_WAITING_PAYMENT ) ) or $this->club->type === \IPS\Member\Club::TYPE_OPEN or \IPS\Member::loggedIn()->modPermission('can_access_all_clubs') )
{
$this->club->addMember( \IPS\Member::loggedIn(), \IPS\Member\Club::STATUS_MEMBER, TRUE, NULL, NULL, TRUE );
$this->club->recountMembers();
$notificationKey = 'club_join';
/* Unless they have to pay */
if ( $this->club->isPaid() and $this->memberStatus !== \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT )
{
if ( $fee = $this->club->joiningFee() )
{
/* Create the item */
$item = new \IPS\core\extensions\nexus\Item\ClubMembership( $this->club->name, $fee );
$item->id = $this->club->id;
try
{
$item->tax = \IPS\Settings::i()->clubs_paid_tax ? \IPS\nexus\Tax::load( \IPS\Settings::i()->clubs_paid_tax ) : NULL;
}
catch ( \OutOfRangeException $e ) { }
if ( \IPS\Settings::i()->clubs_paid_gateways )
{
$item->paymentMethodIds = explode( ',', \IPS\Settings::i()->clubs_paid_gateways );
}
$item->renewalTerm = $this->club->renewalTerm( $fee->currency );
$item->payTo = $this->club->owner;
$item->commission = \IPS\Settings::i()->clubs_paid_commission;
if ( $fees = \IPS\Settings::i()->clubs_paid_transfee and isset( $fees[ $fee->currency ] ) )
{
$item->fee = new \IPS\nexus\Money( $fees[ $fee->currency ]['amount'], $fee->currency );
}
/* Generate the invoice */
$invoice = new \IPS\nexus\Invoice;
$invoice->currency = $fee->currency;
$invoice->member = \IPS\nexus\Customer::loggedIn();
$invoice->addItem( $item );
$invoice->return_uri = "app=core&module=clubs&controller=view&id={$this->club->id}";
$invoice->save();
/* Take them to it */
\IPS\Output::i()->redirect( $invoice->checkoutUrl() );
}
else
{
\IPS\Output::i()->error( 'club_paid_unavailable', '1C350/N', 403, '' );
}
}
else
{
$this->club->addMember( \IPS\Member::loggedIn(), \IPS\Member\Club::STATUS_MEMBER, TRUE, NULL, NULL, TRUE );
$this->club->recountMembers();
$notificationKey = 'club_join';
}
}
/* Otherwise, add the request */
else
@@ -762,7 +1097,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
protected function leave()
{
/* Can we leave? */
if ( !in_array( $this->club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER ) ) or ( $this->club->owner and $this->club->owner->member_id == \IPS\Member::loggedIn()->member_id ) )
if ( !in_array( $this->club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR, \IPS\Member\Club::STATUS_WAITING_PAYMENT, \IPS\Member\Club::STATUS_INVITED ) ) or ( $this->club->owner and $this->club->owner->member_id == \IPS\Member::loggedIn()->member_id ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/S', 403, '' );
}
@@ -770,15 +1105,57 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Cancel purchase */
if ( \IPS\Application::appIsEnabled('nexus') and \IPS\Settings::i()->clubs_paid_on )
{
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( \IPS\nexus\Customer::loggedIn(), $this->club->id ) as $purchase )
{
$purchase->cancelled = TRUE;
$purchase->member->log( 'purchase', array( 'type' => 'cancel', 'id' => $purchase->id, 'name' => $purchase->name ) );
$purchase->can_reactivate = FALSE;
$purchase->save();
}
}
/* Leave */
$this->club->removeMember( \IPS\Member::loggedIn() );
$this->club->recountMembers();
$this->club->save();
/* Delete the invitation */
\IPS\Db::i()->delete( 'core_notifications', array( 'member=? AND notification_app=? AND notification_key=? and item_id=?', \IPS\Member::loggedIn()->member_id, 'core', 'club_invitation', $this->club->id ) );
\IPS\Member::loggedIn()->recountNotifications();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ) );
}
/**
* Renew
*
* @return void
*/
protected function renew()
{
/* Can we renew? */
if ( !in_array( $this->club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/Y', 403, '' );
}
/* CSRF Check */
\IPS\Session::i()->csrfCheck();
/* Find the purchase */
foreach ( \IPS\core\extensions\nexus\Item\ClubMembership::getPurchases( \IPS\nexus\Customer::loggedIn(), $this->club->id ) as $purchase )
{
\IPS\Output::i()->redirect( $purchase->url()->setQueryString( array( 'do' => 'renew', 'cycles' => 1 ) )->csrf() );
}
/* Couldn't find it? */
\IPS\Output::i()->error( 'no_module_permission', '2C350/Z', 500, '' );
}
/**
* Invite Members
*
@@ -794,9 +1171,23 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$form = new \IPS\Helpers\Form( 'form', 'club_send_invitations' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Member( 'members', NULL, TRUE, array( 'multiple' => NULL ) ) );
if ( $this->club->isPaid() and $this->club->isLeader() )
{
$form->add( new \IPS\Helpers\Form\YesNo( 'club_invite_waive_fee', FALSE ) );
if ( $this->club->renewal_price )
{
\IPS\Member::loggedIn()->language()->words['club_invite_waive_fee_desc'] = \IPS\Member::loggedIn()->language()->addToStack('club_invite_waive_fee_renewal');
}
}
if ( $values = $form->values() )
{
$status = \IPS\Member\Club::STATUS_INVITED;
if ( $this->club->isPaid() and $this->club->isLeader() and $values['club_invite_waive_fee'] )
{
$status = \IPS\Member\Club::STATUS_INVITED_BYPASSING_PAYMENT;
}
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'club_invitation', $this->club, array( $this->club, \IPS\Member::loggedIn() ), array( 'invitedBy' => \IPS\Member::loggedIn()->member_id ) );
foreach ( $values['members'] as $member )
{
@@ -805,7 +1196,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$memberStatus = $this->club->memberStatus( $member );
if ( !$memberStatus or in_array( $memberStatus, array( \IPS\Member\Club::STATUS_INVITED, \IPS\Member\Club::STATUS_REQUESTED, \IPS\Member\Club::STATUS_DECLINED, \IPS\Member\Club::STATUS_BANNED ) ) )
{
$this->club->addMember( $member, \IPS\Member\Club::STATUS_INVITED, TRUE, NULL, \IPS\Member::loggedIn(), TRUE );
$this->club->addMember( $member, $status, TRUE, NULL, \IPS\Member::loggedIn(), TRUE );
$notification->recipients->attach( $member );
}
}
@@ -999,6 +1390,52 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->output = \IPS\Request::i()->isAjax() ? $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) ) : $form;
}
/**
* Delete a node
*
* @return void
*/
protected function nodeDelete()
{
\IPS\Session::i()->csrfCheck();
/* Permission check */
if ( !$this->club->isLeader() )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/AA', 403, '' );
}
/* Load */
$class = \IPS\Request::i()->type;
try
{
$node = $class::load( \IPS\Request::i()->node );
$club = $node->club();
if ( !$club or $club->id !== $this->club->id )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '2C350/AB', 404, '' );
}
/* Permission check */
$itemClass = $node::$contentItemClass;
if ( !$node->modPermission( 'delete', \IPS\Member::loggedIn() ) and $itemClass::contentCount( $node, TRUE, TRUE, TRUE, 1 ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C350/AC', 403, '' );
}
/* Delete */
\IPS\Db::i()->delete( 'core_clubs_node_map', array( 'club_id=? AND node_class=? AND node_id=?', $club->id, $class, $node->_id ) );
$node->deleteOrMoveFormSubmit( array() );
/* Redirect */
\IPS\Output::i()->redirect( $club->url() );
}
/* !Cover Photo */
/**
@@ -31,7 +31,7 @@ class _contact extends \IPS\Dispatcher\Controller
{
if ( !\IPS\Member::loggedIn()->canUseContactUs() )
{
\IPS\Output::i()->error( 'no_permission', '2S333/1', 403, '' );
\IPS\Output::i()->error( 'no_module_permission', '2S333/1', 403, '' );
}
/* Execute */
@@ -100,15 +100,4 @@ class _contact extends \IPS\Dispatcher\Controller
}
}
/**
* Can Use Contact Us
*
* @return bool
* @deprecated 4.3
*/
public static function canUseContactUs()
{
return \IPS\Member::loggedIn()->canUseContactUs();
}
}
@@ -145,7 +145,7 @@ class _popular extends \IPS\Dispatcher\Controller
$table->sortDirection = $table->sortDirection ?: 'DESC';
/* Like or what? */
if ( \IPS\Settings::i()->reputation_point_types == 'like' )
if ( \IPS\Content\Reaction::isLikeMode() )
{
\IPS\Member::loggedIn()->language()->words['leader_rep_total'] = \IPS\Member::loggedIn()->language()->addToStack( 'leader_rep_total_likes' );
\IPS\Member::loggedIn()->language()->words['leaderboard_history__desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_desc', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_history_likes') ) ) );
@@ -202,7 +202,7 @@ class _popular extends \IPS\Dispatcher\Controller
$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();
$firstIndexDate = \IPS\Content\Search\Index::i()->firstIndexDate();
$appWhere = null;
$descApp = \IPS\Member::loggedIn()->language()->addToStack( 'leaderboard_in_all_apps' );
@@ -320,13 +320,14 @@ class _popular extends \IPS\Dispatcher\Controller
}
}
/* Got an app? */
$appWhere = '';
/* Do we want results for a specific app */
$customApp = FALSE;
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 ] ) ) );
$customApp = TRUE;
}
else
{
@@ -341,7 +342,7 @@ class _popular extends \IPS\Dispatcher\Controller
$storeKey = NULL;
$hashes = NULL;
if ( ! $customStart and ! $customEnd AND ! $appWhere )
if ( ! $customStart and ! $customEnd AND ! $customApp )
{
$storeKey = 'leaderHashes_' . \IPS\Request::i()->time . '-' . md5( implode( ',', \IPS\Member::loggedIn()->groups ) );
@@ -368,9 +369,9 @@ class _popular extends \IPS\Dispatcher\Controller
/* 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') );
$searchHashes = \IPS\Content\Search\Index::i()->hashesWithPermission( array_keys( $repHashes ), \IPS\Member::loggedIn() );
/* Filter out rep hashes not in search results */
$hashes = array_slice( array_intersect_key( $repHashes, $searchHashes ), 0, 50 );
@@ -386,7 +387,7 @@ class _popular extends \IPS\Dispatcher\Controller
$or = array();
$results = array();
$preLoadMembers = array();
if ( count( $hashes ) )
{
/* Now get the reputation data */
@@ -395,25 +396,15 @@ class _popular extends \IPS\Dispatcher\Controller
$data['total_rep'] = $hashes[ $data['class_type_id_hash'] ]['total_rep'];
$repData[ $data['rep_class'] . '-' . $data['type_id'] ] = $data;
$classes[ $data['rep_class'] ][] = $data['type_id'];
if ( ! empty( $data['member_id'] ) )
{
$preLoadMembers[] = $data['member_id'];
}
}
foreach( $classes as $class => $ids )
{
$or[] = '( index_class=\'' . \IPS\Db::i()->escape_string( $class ) . '\' AND ' . \IPS\Db::i()->in( 'index_object_id', $ids ) . ')';
$or[] = \IPS\Content\Search\ContentFilter::init( $class )->onlyInIds( $ids );
}
/* Construct the query */
$query = \IPS\Db::i()->select( '*', array( 'core_search_index', 'main' ), array( implode( ' OR ', $or ) ), NULL, NULL, NULL, NULL );
$array = iterator_to_array( $query );
$sorted = array();
/* Manually sort */
/* Query and manually sort */
$array = \IPS\Content\Search\Query::init()->filterByContent( $or )->search()->getArrayCopy();
foreach( $array as $index => $data )
{
if ( isset( $repData[ $data['index_class'] . '-' . $data['index_object_id'] ] ) )
@@ -433,8 +424,13 @@ class _popular extends \IPS\Dispatcher\Controller
/* Get top rated contributors */
$topContributors = array();
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', array( 'member_received>0 ' . $appWhere . ' and rep_date BETWEEN ' . intval( $date->getTimeStamp() ) . ' AND ' . intval( $endDate->getTimeStamp() ) ), NULL, NULL, 'member' );
$innerQueryWhere = array();
$innerQueryWhere[] = array( 'member_received>0 ' . $appWhere . ' and rep_date BETWEEN ' . intval( $date->getTimeStamp() ) . ' AND ' . intval( $endDate->getTimeStamp() ) );
$innerQueryWhere[] = \IPS\Db::i()->in( 'member_group_id', \IPS\Settings::i()->leaderboard_excluded_groups, TRUE );
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', $innerQueryWhere, NULL, NULL, 'member' )->join( 'core_members', array( 'core_reputation_index.member_received = core_members.member_id' ) );
foreach( \IPS\Db::i()->select( 'member, rep', array( $innerQuery, 'in' ), NULL, 'rep DESC', 4 )->setKeyField('member')->setValueField('rep') as $member => $rep )
{
$topContributors[ $member ] = $rep;
@@ -455,7 +451,7 @@ class _popular extends \IPS\Dispatcher\Controller
}
/* Work out the description for popular content */
if ( \IPS\Settings::i()->reputation_point_types == 'like' )
if ( \IPS\Content\Reaction::isLikeMode() )
{
$popularResultsSingle = 'popular_results_single_desc';
$popularResultsMany = 'popular_results_desc';
@@ -481,6 +477,12 @@ class _popular extends \IPS\Dispatcher\Controller
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=leaderboard", 'front', 'leaderboard_leaderboard' );
/* If there are no results tell search engines not to index the page */
if( !count( $results ) )
{
\IPS\Output::i()->metaTags['robots'] = 'noindex';
}
/* 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 );
}
@@ -5,7 +5,6 @@
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 13 Oct 2016
*/
@@ -39,7 +39,8 @@ class _streams extends \IPS\Dispatcher\Controller
/* Necessary CSS/JS */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_streams.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_statuses.js', 'core' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
@@ -121,7 +122,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->json( array(
'url' => $defaultStream->url(),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ),
'tooltip' => $defaultStream->_title, // We need to pass this individually for the tooltip that shows, but the JS itself will escape any entities
'id' => $defaultStream->_id
) );
@@ -166,7 +167,7 @@ class _streams extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->json( array(
'url' => \IPS\Http\Url::internal( "app=core&module=discover&controller=streams", 'front', 'discover_all' ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $defaultStream->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ),
'id' => $defaultStream->_id
) );
}
@@ -187,7 +188,13 @@ 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', 'clubs', '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', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' );
/* Clubs enabled? */
if( \IPS\Settings::i()->clubs )
{
$streamFields[] = 'clubs';
}
/* Build and format field values */
$_values = array();
@@ -379,7 +386,7 @@ class _streams extends \IPS\Dispatcher\Controller
$output = \IPS\Theme::i()->getTemplate('streams')->streamItems( $results, TRUE, ( $stream->id and !$stream->include_comments ) ? 'last_comment' : 'date', $view );
$return = array(
'title' => htmlspecialchars( $stream->_title, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $stream->_title, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'blurb' => $stream->blurb(),
'config' => json_encode( $stream->config() ),
'count' => count( $results ),
@@ -484,7 +491,7 @@ class _streams extends \IPS\Dispatcher\Controller
if ( $stream->member != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_permission', '2C280/8', 403, '' );
\IPS\Output::i()->error( 'no_module_permission', '2C280/8', 403, '' );
}
$form = new \IPS\Helpers\Form;
@@ -599,7 +606,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(), 'clubs' => \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) ), 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\Settings::i()->clubs AND \IPS\IPS::classUsesTrait( $containerClass, 'IPS\Content\ClubContainer' ) ) ), NULL, NULL, NULL, 'stream_containers_' . $class::$title );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( 'stream_narrow_by_container_label', NULL, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $containerClass::$nodeTitle ) ) ) );
return \IPS\Output::i()->json( array( 'node' => \IPS\Theme::i()->getTemplate('streams')->filterFormContentTypeContent( $field, $class, \IPS\Request::i()->key ) ) );
@@ -616,6 +623,11 @@ class _streams extends \IPS\Dispatcher\Controller
*/
protected function getClubElement()
{
if( !\IPS\Settings::i()->clubs )
{
return \IPS\Output::i()->json( array( 'field' => '' ) );
}
$clubOptions = array();
foreach ( \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE ) as $club )
{
@@ -681,25 +693,48 @@ class _streams extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* As the node container form elements are not in the actual form, we need to work some magic. And by magic, I do mean a sort of hacky thing. */
foreach ( \IPS\Request::i() as $k => $v )
/* As the node container form elements are not in the actual form, we need to work some magic.
And by magic, I do mean a sort of hacky thing. First, if we are editing a stream, we need to get our existing stream filters
and put these into an array. Then we loop over the input and overwrite the existing filters with what was submitted. If the user
never loaded the container filters we'll retain what we had (expected) but if they did and adjusted or removed container filters
then we'll update with what they submitted (expected).
*/
if( $stream->id )
{
if ( mb_substr( $k, 0, 18 ) == 'stream_containers_' and $v )
$currentContainers = $stream->containers ? json_decode( $stream->containers, TRUE ) : array();
foreach( $currentContainers as $class => $containers )
{
$vals = explode( ',', $v );
$values[ $k ] = array_combine( $vals, $vals );
$values['stream_containers_' . $class::$title ] = array_combine( $containers, $containers );
}
}
foreach ( \IPS\Request::i() as $k => $v )
{
if ( mb_substr( $k, 0, 18 ) == 'stream_containers_' )
{
if( $v )
{
$vals = explode( ',', $v );
$values[ $k ] = array_combine( $vals, $vals );
}
elseif( isset( $values[ $k ] ) )
{
$values[ $k ] = NULL;
}
}
}
/* Update only */
if ( isset( \IPS\Request::i()->updateOnly ) )
{
$formattedValues = $stream->formatFormValues( $values );
foreach ( array( 'include_comments', 'classes', 'containers', 'clubs', 'ownership', 'custom_members', 'read', 'follow', 'followed_types', 'date_type', 'date_start', 'date_end', 'date_relative_days', 'sort', 'tags', 'unread_links' ) as $k )
{
$requestKey = 'stream_' . $k;
if ( isset( $formattedValues[ $k ] ) AND $stream->$k != $formattedValues[ $k ] )
if ( array_key_exists( $k, $formattedValues ) AND $stream->$k != $formattedValues[ $k ] )
{
$stream->$k = $formattedValues[ $k ];
$stream->baseUrl = $stream->baseUrl->setQueryString( 'stream_' . $k, \IPS\Request::i()->$requestKey );
@@ -50,6 +50,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_profile.js', 'core' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_statuses.js', 'core' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_core.js', 'core', 'global' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/profiles.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/leaderboard.css' ) );
@@ -57,7 +58,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/profiles_responsive.css' ) );
}
}
}
/* Go */
@@ -103,9 +104,17 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$canAccessStatuses = $canAccessSingleStatuses and ( $this->member->pp_setting_count_comments or \IPS\Member::loggedIn()->member_id == $this->member->member_id );
/* Are we loading a different page of comments? */
if ( \IPS\Request::i()->status && \IPS\Request::i()->isAjax() && \IPS\Request::i()->page && $canAccessStatuses )
if ( \IPS\Request::i()->status && \IPS\Request::i()->isAjax() && \IPS\Request::i()->page && $canAccessStatuses && !isset( \IPS\Request::i()->getUploader ) )
{
$status = \IPS\core\Statuses\Status::loadAndCheckPerms( \IPS\Request::i()->status );
try
{
$status = \IPS\core\Statuses\Status::loadAndCheckPerms( \IPS\Request::i()->status );
}
catch( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2C138/M', 404, '' );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'statuses' )->statusReplies( $status );
return;
}
@@ -167,11 +176,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
/* What tabs are available? */
$tabs = array( 'activity' => 'users_activity_feed' );
if ( \IPS\Settings::i()->clubs )
if ( \IPS\Settings::i()->clubs and count( \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'created', $this->member ) ) )
{
$tabs['clubs'] = 'users_clubs';
}
@@ -279,7 +287,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$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 );
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ( ceil( is_object( $allClubs ) ? $allClubs->count( TRUE ) : 0 ) / $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'] )
@@ -376,7 +384,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
'@context' => "http://schema.org",
'@type' => "ProfilePage",
'url' => (string) $this->member->url(),
'name' => htmlspecialchars( $this->member->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'name' => $this->member->name,
'primaryImageOfPage' => array(
'@type' => "ImageObject",
'contentUrl' => (string) $this->member->get_photo(),
@@ -403,7 +411,9 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
),
),
);
\IPS\Output::i()->linkTags['canonical'] = (string) $this->member->url();
/* Output */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_profile.js', 'core' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->profile( $this->member, $mainContent, $visitors, $sidebarFields, $followers, $addWarningUrl );
@@ -439,15 +449,13 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
foreach( $router->classes as $class )
{
if( !isset( $class::$includeInUserProfiles ) OR !$class::$includeInUserProfiles )
{
continue;
}
/* Add CSS for this app */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'profile.css', $class::$application ) );
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ) ] = $class;
if ( isset( $class::$databaseColumnMap['author'] ) )
{
$types[ $class::$application . '_' . $class::$module ][ mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ) ] = $class;
}
$supportsComments = ( in_array( 'IPS\Content\Item', class_parents( $class ) ) and $class::supportsComments( \IPS\Member::loggedIn() ) );
if ( $supportsComments )
@@ -516,8 +524,16 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->redirect( \IPS\Request::i()->url()->setQueryString( 'page', $highestPage ?: 1 ), NULL, 303 );
}
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $this->member->url()->setQueryString( array( 'do' => 'content' ) ), ceil( $results->count( TRUE ) / $query->resultsToGet ), $page, $query->resultsToGet ) );
$output = \IPS\Theme::i()->getTemplate('profile')->userContentStream( $this->member, $results, $pagination );
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $this->member->url()->setQueryString( array( 'do' => 'content', 'all_activity' => 1 ) ), ceil( $results->count( TRUE ) / $query->resultsToGet ), $page, $query->resultsToGet ) );
if ( \IPS\Request::i()->isAjax() AND \IPS\Request::i()->all_activity )
{
\IPS\Output::i()->json( array( 'rows' => \IPS\Theme::i()->getTemplate('profile')->userContentStream( $this->member, $results, $pagination ) ) );
return;
}
else
{
$output = \IPS\Theme::i()->getTemplate('profile')->userContentStream( $this->member, $results, $pagination );
}
}
else
{
@@ -667,9 +683,35 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
else
{
/* Get the reputation summary */
$reactions = array( 'given' => array(), 'received' => array() );
foreach( \IPS\Db::i()->select( 'reaction, COUNT(*) as count', 'core_reputation_index', array( 'member_id=?', $this->member->member_id ), NULL, NULL, 'reaction' ) as $reaction )
{
try
{
$object = \IPS\Content\Reaction::load( $reaction['reaction'] );
$reactions['given'][] = array( 'count' => $reaction['count'], 'reaction' => $object );
}
catch( \UnderflowException $e ){}
}
foreach( \IPS\Db::i()->select( 'reaction, COUNT(*) as count', 'core_reputation_index', array( 'member_received=?', $this->member->member_id ), NULL, NULL, 'reaction' ) as $reaction )
{
try
{
$object = \IPS\Content\Reaction::load( $reaction['reaction'] );
$reactions['received'][] = array( 'count' => $reaction['count'], 'reaction' => $object );
}
catch( \UnderflowException $e ){}
}
\IPS\Output::i()->title = ( $table->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'member_reputation_from', FALSE, array('sprintf' => $this->member->name ) ), $table->page ) ) ) : \IPS\Member::loggedIn()->language()->addToStack( 'member_reputation_from', FALSE, array('sprintf' => $this->member->name ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userReputation( $this->member, $types, $currentAppModule, $currentType, (string) $table );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userReputation( $this->member, $types, $currentAppModule, $currentType, (string) $table, $reactions );
}
}
@@ -741,7 +783,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
$form = new \IPS\Helpers\Form( 'form', 'status_save' );
$form->class = 'ipsForm_vertical';
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$formElements = \IPS\core\Statuses\Status::formElements( $status );
$form->add( $formElements['status_content'] );
@@ -755,7 +797,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
\IPS\Output::i()->redirect( $status->url() );
}
\IPS\Output::i()->output = $form;
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
catch ( \Exception $e )
{
@@ -763,6 +805,54 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
}
/**
* Edit Status Reply
*
* @return void
*/
protected function editStatusReply()
{
try
{
$reply = \IPS\core\Statuses\Reply::loadAndCheckPerms( \IPS\Request::i()->reply );
if ( !$reply->canEdit() )
{
throw new \DomainException;
}
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Editor( 'comment_value', $reply->content, TRUE, array(
'app' => 'core',
'key' => 'Members',
'autoSaveKey' => 'editComment-core/members-' . $reply->id,
'attachIds' => $reply->attachmentIds()
) ) );
if ( $values = $form->values() )
{
$reply->editContents( $values['comment_value'] );
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = $reply->html();
return;
}
else
{
\IPS\Output::i()->redirect( $reply->url() );
}
}
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
}
catch( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '2C138/K', 404, '' );
}
}
/**
* Edit Profile
*
@@ -931,24 +1021,27 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->member_title = $values['member_title'];
}
if( $values['bday'] and ( ( $values['bday']['day'] and !$values['bday']['month'] ) or ( $values['bday']['month'] and !$values['bday']['day'] ) ) )
if( isset( $values['bday'] ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'bday_month_and_day_required' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->editContentForm( \IPS\Member::loggedIn()->language()->addToStack( 'profile_edit' ), $form );
return;
}
if( $values['bday'] and ( ( $values['bday']['day'] and !$values['bday']['month'] ) or ( $values['bday']['month'] and !$values['bday']['day'] ) ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'bday_month_and_day_required' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->editContentForm( \IPS\Member::loggedIn()->language()->addToStack( 'profile_edit' ), $form );
return;
}
if ( $values['bday'] and $values['bday']['day'] and $values['bday']['month'] )
{
$this->member->bday_day = $values['bday']['day'];
$this->member->bday_month = $values['bday']['month'];
$this->member->bday_year = $values['bday']['year'];
}
else
{
$this->member->bday_day = NULL;
$this->member->bday_month = NULL;
$this->member->bday_year = NULL;
if ( $values['bday'] and $values['bday']['day'] and $values['bday']['month'] )
{
$this->member->bday_day = $values['bday']['day'];
$this->member->bday_month = $values['bday']['month'];
$this->member->bday_year = $values['bday']['year'];
}
else
{
$this->member->bday_day = NULL;
$this->member->bday_month = NULL;
$this->member->bday_year = NULL;
}
}
if ( isset( $values['enable_status_updates'] ) )
@@ -980,14 +1073,21 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
$profileFields = array();
}
$profileFields['member_id'] = $this->member->member_id;
foreach ( \IPS\core\ProfileFields\Field::fields( $profileFields, \IPS\core\ProfileFields\Field::PROFILE ) as $group => $fields )
{
foreach ( $fields as $id => $field )
{
$profileFields[ "field_{$id}" ] = $field::stringValue( $values[ $field->name ] );
if ( $field instanceof \IPS\Helpers\Form\Upload )
{
$profileFields[ "field_{$id}" ] = (string) $values[ $field->name ];
}
else
{
$profileFields[ "field_{$id}" ] = $field::stringValue( $values[ $field->name ] );
}
if ( $field instanceof \IPS\Helpers\Form\Editor )
{
@@ -1076,17 +1176,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
}
/* ProfileSync (Facebook, etc.) */
foreach ( \IPS\core\ProfileSync\ProfileSyncAbstract::services() as $key => $class )
{
$obj = new $class( $this->member );
if ( $obj->connected() )
{
$langKey = 'profilesync__' . $key;
$options[ 'sync-' . $key ] = \IPS\Member::loggedIn()->language()->addToStack( 'member_photo_sync' , FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $langKey ) ) ) );
}
}
/* And of course we can always not have a photo... except when we can't */
$photoRequired = FALSE;
foreach( \IPS\Member\ProfileStep::loadAll() AS $step )
@@ -1097,7 +1186,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
break;
}
}
if ( $photoRequired === FALSE )
{
$options['none'] = 'member_photo_none';
@@ -1116,7 +1204,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
if ( $photoVars[0] )
{
$form->add( new \IPS\Helpers\Form\Upload( 'member_photo_upload', NULL, FALSE, array( 'image' => array( 'maxWidth' => $photoVars[1], 'maxHeight' => $photoVars[2] ), 'storageExtension' => 'core_Profile', 'maxFileSize' => $photoVars[0] ? $photoVars[0] / 1024 : NULL ), function( $val ) {
if ( $val instanceof \IPS\File )
{
$image = \IPS\Image::create( $val->contents() );
@@ -1128,7 +1215,16 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}, NULL, NULL, 'member_photo_upload' ) );
/* Create the URL */
$form->add( new \IPS\Helpers\Form\Url( 'member_photo_url', NULL, FALSE, array( 'file' => 'core_Profile', 'image' => TRUE, 'maxFileSize' => $photoVars[0] ? $photoVars[0] / 1024 : NULL, 'maxDimensions' => array( 'width' => $photoVars[1], 'height' => $photoVars[2] ) ), NULL, NULL, NULL, 'member_photo_url' ) );
$form->add( new \IPS\Helpers\Form\Url( 'member_photo_url', NULL, FALSE, array( 'file' => 'core_Profile', 'image' => TRUE, 'maxFileSize' => $photoVars[0] ? $photoVars[0] / 1024 : NULL, 'maxDimensions' => array( 'width' => $photoVars[1], 'height' => $photoVars[2] ) ), function( $val ) {
if ( $val instanceof \IPS\Http\Url )
{
$image = \IPS\Image::create( (string) $val->request()->get() );
if( $image->isAnimatedGif and !$this->member->group['g_upload_animated_photos'] )
{
throw new \DomainException('member_photo_upload_no_animated');
}
}
}, NULL, NULL, 'member_photo_url' ) );
}
/* Add additional elements */
@@ -1142,16 +1238,12 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
{
$this->member->pp_photo_type = $values['pp_photo_type'];
/* If we are changing our photo, it is safe to assume that any services currently set to sync should no longer do so */
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
if ( !empty( $services ) )
/* Disable syncing */
$profileSync = $this->member->profilesync;
if ( isset( $profileSync['photo'] ) )
{
foreach( $services AS $class )
{
$obj = new $class( $this->member );
$obj->save( array( 'profilesync_photo' => FALSE ) );
}
unset( $profileSync['photo'] );
$this->member->profilesync = $profileSync;
}
switch ( $values['pp_photo_type'] )
@@ -1197,14 +1289,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
case 'gravatar':
$this->member->pp_gravatar = ( !isset( $values['photo_gravatar_email_public'] ) or $values['photo_gravatar_email_public'] === $this->member->email ) ? NULL : $values['photo_gravatar_email_public'];
break;
default:
if ( mb_substr( $values['pp_photo_type'], 0, 5 ) === 'sync-' )
{
$class = 'IPS\core\ProfileSync\\' . mb_substr( $values['pp_photo_type'], 5 );
$obj = new $class( $this->member );
$obj->save( array( 'profilesync_photo' => TRUE ) );
}
}
/* Reset Profile Complete flag in case this was an optional step */
@@ -1212,6 +1296,15 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->save();
if ( $this->member->pp_photo_type )
{
$this->member->logHistory( 'core', 'photo', array( 'action' => 'new', 'type' => $this->member->pp_photo_type ) );
}
else
{
$this->member->logHistory( 'core', 'photo', array( 'action' => 'remove' ) );
}
if ( $this->member->pp_photo_type == 'custom' )
{
if ( \IPS\Request::i()->isAjax() )
@@ -1270,8 +1363,17 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
/* Get the photo */
$original = \IPS\File::get( 'core_Profile', $this->member->pp_main_photo );
$image = \IPS\Image::create( $original->contents() );
try
{
$original = \IPS\File::get( 'core_Profile', $this->member->pp_main_photo );
$image = \IPS\Image::create( $original->contents() );
}
catch( \Exception $e )
{
\IPS\Log::log( $e, 'crop_error' );
\IPS\Output::i()->error( 'no_photo_to_crop', '3C138/N', 404, '' );
}
/* Work out which dimensions to suggest */
if ( $image->width < $image->height )
@@ -1290,7 +1392,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$form->add( new \IPS\Helpers\Form\Custom('photo_crop', array( 0, 0, $suggestedWidth, $suggestedHeight ), FALSE, array(
'getHtml' => function( $field ) use ( $original, $member )
{
return \IPS\Theme::i()->getTemplate('profile')->photoCrop( $field->name, $field->value, $member->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
return \IPS\Theme::i()->getTemplate('members', 'core', 'global')->photoCrop( $field->name, $field->value, $member->url()->setQueryString( 'do', 'cropPhotoGetPhoto' )->csrf() );
}
) ) );
@@ -1328,7 +1430,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
}
catch ( \Exception $e )
{
$form->error = 'photo_crop_bad';
$form->error = \IPS\Member::loggedIn()->language()->addToStack('photo_crop_bad');
}
}
@@ -1485,7 +1587,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$tabs['all'] = \IPS\Member::loggedIn()->language()->addToStack('all');
foreach( \IPS\Content\Reaction::roots() AS $reaction )
{
$tabs[ $reaction->id ] = $reaction->_title;
if ($reaction->_enabled !== FALSE)
{
$tabs[$reaction->id] = $reaction->_title;
}
}
$activeTab = 'all';
@@ -1537,7 +1642,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
if ( $canReport !== TRUE )
{
\IPS\Output::i()->error( 'generic_error', '1C138/6', 403, '' );
\IPS\Output::i()->error( $canReport, '1C138/6', 403, '' );
}
$form = new \IPS\Helpers\Form( NULL, 'report_submit' );
@@ -1613,23 +1718,17 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
* Set Cover Photo
*
* @param \IPS\Helpers\CoverPhoto $photo New Photo
* @param string $type 'new', 'remove', 'reposition'
* @return void
*/
protected function _coverPhotoSet( \IPS\Helpers\CoverPhoto $photo )
protected function _coverPhotoSet( \IPS\Helpers\CoverPhoto $photo, $type=NULL )
{
/* If we are changing our cover photo, it is safe to assume that any services currently set to sync should no longer do so */
$services = \IPS\core\ProfileSync\ProfileSyncAbstract::services();
if ( !empty( $services ) )
/* Disable syncing */
$profileSync = $this->member->profilesync;
if ( isset( $profileSync['cover'] ) )
{
foreach( $services AS $class )
{
$obj = new $class( $this->member );
if ( $obj->connected() )
{
$obj->save( array( 'profilesync_cover' => FALSE ) );
}
}
unset( $profileSync['cover'] );
$this->member->profilesync = $profileSync;
}
$this->member->pp_cover_photo = (string) $photo->file;
@@ -1639,6 +1738,10 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
$this->member->members_bitoptions['profile_completed'] = FALSE;
$this->member->save();
if ( $type != 'reposition' )
{
$this->member->logHistory( 'core', 'coverphoto', array( 'action' => $type ) );
}
}
/**
@@ -232,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()->folder ) or !is_null( $folder ) )
/* Add a folder filter, if we are not coming from the Messages menu */
if ( !isset( \IPS\Request::i()->_fromMenu ) )
{
if ( !is_null( $folder ) AND isset( $folders[ $folder ] ) )
{
@@ -252,6 +252,9 @@ class _messenger extends \IPS\Content\Controller
if ( \IPS\Request::i()->q )
{
/* Limit result set to prevent time outs */
$where[] = array( 'core_message_topic_user_map.map_last_topic_reply > ?', \IPS\DateTime::ts( time() )->sub( new \DateInterval( 'P1Y' ) )->getTimeStamp() );
$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();
@@ -283,7 +286,7 @@ class _messenger extends \IPS\Content\Controller
/* Get a count */
try
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_message_posts', $where, NULL, NULL, 'msg_topic_id' )
$count = \IPS\Db::i()->select( 'COUNT( DISTINCT(msg_topic_id) )', 'core_message_posts', array_merge( $where, array( array( 'core_message_topic_user_map.map_last_topic_reply > ?', \IPS\DateTime::ts( time() )->sub( new \DateInterval( 'P1Y' ) )->getTimeStamp() ) ) ) )
->join(
'core_message_topics',
'core_message_posts.msg_topic_id=core_message_topics.mt_id'
@@ -416,10 +419,17 @@ class _messenger extends \IPS\Content\Controller
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->conversation( $conversation, $folders );
}
elseif( \IPS\Request::i()->q )
{
\IPS\Output::i()->json( array(
'data' => \IPS\Theme::i()->getTemplate('messaging')->messageListRows( $conversations, $pagination, FALSE, $folders ),
'pagination' => $pagination
) );
}
elseif( \IPS\Request::i()->overview )
{
\IPS\Output::i()->json( array(
'data' => \IPS\Theme::i()->getTemplate('messaging')->messageListRows( $conversations, $pagination, TRUE, $folders ),
'data' => \IPS\Theme::i()->getTemplate('messaging')->messageListRows( $conversations, $pagination, \IPS\Request::i()->_fromMenu ? FALSE : TRUE, $folders ),
'pagination' => $pagination,
'listBaseUrl' => $listUrl->setQueryString( array( 'sortBy' => \IPS\Request::i()->sortBy, 'filter' => \IPS\Request::i()->filter ) )->stripQueryString( 'id' )
) );
@@ -431,7 +441,7 @@ class _messenger extends \IPS\Content\Controller
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->template( $folder, $folders, $folderCounts, $conversations, $pagination, $conversation, $baseUrl, ( $conversation ? 'messenger_convo' : 'messenger' ), ( \IPS\Request::i()->sortBy ? htmlspecialchars( \IPS\Request::i()->sortBy, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ): 'mt_last_post_time' ), ( \IPS\Request::i()->filter ? htmlspecialchars( \IPS\Request::i()->filter, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : '' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->template( $folder, $folders, $folderCounts, $conversations, $pagination, $conversation, $baseUrl, ( $conversation ? 'messenger_convo' : 'messenger' ), ( \IPS\Request::i()->sortBy ? htmlspecialchars( \IPS\Request::i()->sortBy, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ): 'mt_last_post_time' ), ( \IPS\Request::i()->filter ? htmlspecialchars( \IPS\Request::i()->filter, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE ) : '' ) );
}
}
@@ -459,8 +469,13 @@ class _messenger extends \IPS\Content\Controller
\IPS\Session::i()->csrfCheck();
$folders = json_decode( \IPS\Member::loggedIn()->pconversation_filters, TRUE );
array_walk( $folders, function( &$val )
{
$val = htmlspecialchars( $val, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8' );
} );
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Select( 'move_message_to', NULL, FALSE, array( 'options' => array_merge( array( 'myconvo' => 'inbox' ), $folders ) ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'move_message_to', NULL, FALSE, array( 'options' => array_merge( array( 'myconvo' => \IPS\Member::loggedIn()->language()->addToStack('inbox') ), $folders ), 'parse' => 'normal' ) ) );
if ( $values = $form->values() )
{
@@ -742,6 +757,7 @@ class _messenger extends \IPS\Content\Controller
$ids[] = $member->member_id;
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'private_message_added', $conversation, array( $conversation, \IPS\Member::loggedIn() ) );
$notification->recipients->attach( $member );
$notification->send();
}
+38 -16
View File
@@ -22,6 +22,35 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _modcp extends \IPS\Dispatcher\Controller
{
/**
* Dispatcher looks for methods to match do param, which may exist in the extension files, so this method
* prevents dispatcher throwing a 2S106/1 and allows the extensions to use the values
*
* @param string $method Desired method
* @param array $args Arguments
* @return void
*/
public function __call( $method, $args )
{
if ( isset( \IPS\Request::i()->do ) )
{
$activeTab = \IPS\Request::i()->tab ?: 'overview';
foreach ( \IPS\Application::allExtensions( 'core', 'ModCp', TRUE ) as $key => $extension )
{
if( method_exists( $extension, 'getTab' ) and mb_strtolower( $extension->getTab() ) == mb_strtolower( $activeTab ) )
{
if ( method_exists( $extension, \IPS\Request::i()->do ) )
{
return $this->manage();
}
}
}
}
/* Still here? */
\IPS\Output::i()->error( 'page_not_found', '2C139/5', 404, '' );
}
/**
* Moderator Control Panel
*
@@ -45,6 +74,9 @@ class _modcp extends \IPS\Dispatcher\Controller
$activeTab = \IPS\Request::i()->tab ?: 'overview';
$tabs = array( 'reports' => array(), 'approval' => array() );
$content = '';
$approvalQueueCount = 0;
foreach ( \IPS\Application::allExtensions( 'core', 'ModCp', TRUE ) as $key => $extension )
{
if( method_exists( $extension, 'getTab' ) )
@@ -55,6 +87,12 @@ class _modcp extends \IPS\Dispatcher\Controller
{
$tabs[ $tab ][] = $key;
}
/* Get the count for the approval queue from the extension */
if( $tab == 'approval' )
{
$approvalQueueCount = $extension->getApprovalQueueCount( false );
}
}
if( mb_strtolower( $extension->getTab() ) == mb_strtolower( $activeTab ) )
@@ -113,22 +151,6 @@ class _modcp extends \IPS\Dispatcher\Controller
}
}
/* Get the count for the approval queue. If the community has a lot of data in the search index, thid can take a long
time, so we cache for a short while */
try
{
$approvalQueueCount = \IPS\Data\Cache::i()->getWithExpire( 'modCpApprovalQueueCount_' . \IPS\Member::loggedIn()->member_id, TRUE );
}
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 );
}
/* Display */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp.css' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/modcp_responsive.css' ) );
@@ -36,76 +36,43 @@ class _online extends \IPS\Dispatcher\Controller
\IPS\Session\Front::i()->setTheme( \IPS\Member::loggedIn()->skin ?: 0 );
session_write_close();
$notInMyName = array();
foreach( \IPS\Member\Group::groups() as $group )
{
if ( $group->g_hide_online_list )
{
$notInMyName[] = $group->g_id;
}
}
/* Initial filters */
$subWhere = array(
array( "s.running_time>?", \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ),
array( "s.login_type!=?", \IPS\Session\Front::LOGIN_TYPE_SPIDER )
);
if ( !\IPS\Member::loggedIn()->isAdmin() )
{
$subWhere[] = array( "s.login_type!=?", \IPS\Session\Front::LOGIN_TYPE_ANONYMOUS );
}
if ( count( $notInMyName ) )
{
$subWhere[] = array( \IPS\Db::i()->in( 's.member_group', $notInMyName, TRUE ) );
}
/* Ok, this looks odd, but the ONLY_FULL_GROUP_BY bites us here, so selecting max(id) allows us to return a session ID even though we're grouping on member_id */
$where = array( array( "( core_sessions.id IN(?) OR ( core_sessions.member_id IS NULL AND core_sessions.login_type != ? AND core_sessions.running_time > ?) )", \IPS\Db::i()->select( 'MAX(id)', array( 'core_sessions', 's' ), $subWhere, NULL, NULL, 'member_id' ), \IPS\Session\Front::LOGIN_TYPE_SPIDER, \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ) );
if ( count( $notInMyName ) )
{
$where[] = array( \IPS\Db::i()->in( 'core_sessions.member_group', $notInMyName, TRUE ) );
}
/* Create the table */
$table = new \IPS\Helpers\Table\Db( 'core_sessions', \IPS\Http\Url::internal( 'app=core&module=online&controller=online', 'front', 'online' ), $where );
$table = new \IPS\core\Online\Table( \IPS\Http\Url::internal( 'app=core&module=online&controller=online', 'front', 'online' ) );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' ), 'onlineUsersTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' ), 'onlineUsersRow' );
$table->langPrefix = 'online_users_';
$table->include = array( 'photo', 'member_name', 'location_lang', 'running_time', 'ip_address', 'login_type' );
$table->limit = 30;
$table->noSort = array( 'photo', 'location_lang' );
/* Custom parsers */
$table->parsers = array(
'location_lang' => function( $val, $row )
'location_lang' => function( $val, $row )
{
return \IPS\Session\Front::getLocation( $row );
},
'photo' => function( $val, $row )
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( \IPS\Member::load( $row['member_id'] ), 'mini' );
},
'running_time' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->relative();
},
'member_name' => function( $val, $row )
{
if( $row['member_id'] )
{
return \IPS\Session\Front::getLocation( $row );
},
'photo' => function( $val, $row )
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $row['member_id'] ) );
}
else
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userPhoto( \IPS\Member::load( $row['member_id'] ), 'mini' );
},
'running_time' => function( $val, $row )
{
return \IPS\DateTime::ts( $val )->relative();
},
'member_name' => function( $val, $row )
{
if( $row['member_id'] )
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->userLink( \IPS\Member::load( $row['member_id'] ) );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( 'guest' );
}
},
return \IPS\Member::loggedIn()->language()->addToStack( 'guest' );
}
},
);
$table->filters = array(
'filter_loggedin' => 'core_sessions.member_id <> 0',
'filter_loggedin' => 'filter_loggedin',
);
foreach ( \IPS\Member\Group::groups( TRUE, TRUE, TRUE ) as $group )
@@ -123,29 +90,18 @@ class _online extends \IPS\Dispatcher\Controller
if( $group->g_id == \IPS\Settings::i()->guest_group )
{
$table->filters[ 'group_' . $group->g_id ] = 'core_sessions.member_id IS NULL';
$table->filters[ 'group_' . $group->g_id ] = $group->g_id;
}
else
{
$table->filters[ 'group_' . $group->g_id ] = 'core_sessions.member_group=' . $group->g_id;
$table->filters[ 'group_' . $group->g_id ] = $group->g_id;
}
}
$table->sortBy = $table->sortBy ?: 'running_time';
$table->sortDirection = $table->sortDirection ?: 'desc';
/* Get the count */
$counter = \IPS\Db::i()->select( 'COUNT(*)', 'core_sessions', $where );
foreach( $table->joins as $join )
{
$counter = $counter->join( $join['from'], $join['where'] );
}
$totalCount = $counter->first();
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('online_users');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' )->onlineUsersList( (string) $table, $totalCount );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'online', 'core', 'front' )->onlineUsersList( (string) $table, $table->count );
}
}
@@ -42,6 +42,11 @@ class _promote extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'page_not_found', '2C356/5', 404, '' );
}
if ( ! \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'promote_manage' ) and $promote->added_by != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2C366/2', 403, '' );
}
try
{
$object = $class::load( $id );
@@ -57,13 +62,87 @@ class _promote extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'page_not_found', '2C356/7', 404, '' );
}
$title = NULL;
$settings = $promote->form_data;
if ( ! empty( $settings['internal']['title'] ) )
{
$title = $settings['internal']['title'];
}
$form = new \IPS\Helpers\Form( 'form', 'save' );
$form->class = 'ipsForm_vertical cPromoteDialog';
$form->attributes = array( 'data-controller' => 'core.front.system.promote' );
$form->add( new \IPS\Helpers\Form\Text( 'promote_social_title_internal', $title, FALSE ) );
$form->add( new \IPS\Helpers\Form\TextArea( 'promote_internal_text', $promote->getText('internal'), FALSE, array( 'rows' => 10 ) ) );
/* 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,
) );
$form->add( $uploader );
/* Saving? */
if ( $values = $form->values() )
{
/* 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 );
}
}
}
}
$media = array();
if ( is_array( $values['promote_media'] ) )
{
foreach( $values['promote_media'] as $key => $file )
{
$media[] = (string) $file;
}
}
$settings['internal']['title'] = $values['promote_social_title_internal'];
$promote->images = $saveImages;
$promote->media = $media;
$promote->form_data = $settings;
$promote->setText( 'internal', $values['promote_internal_text'] );
$promote->save();
@@ -129,6 +208,11 @@ class _promote extends \IPS\Dispatcher\Controller
/* Create the table */
$table = new \IPS\core\Promote\Table( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ) );
if ( ! \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'promote_manage' ) )
{
$table->setMember( \IPS\Member::loggedIn() );
}
\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' ) );
@@ -160,6 +244,12 @@ class _promote extends \IPS\Dispatcher\Controller
try
{
$item = \IPS\core\Promote::load( \IPS\Request::i()->promote_id );
if ( ! \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'promote_manage' ) and $item->added_by != \IPS\Member::loggedIn()->member_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2C366/1', 403, '' );
}
$item->delete();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=promote&controller=promote&do=view', 'front', 'promote_manage' ), 'promote_item_deleted' );
@@ -228,6 +318,11 @@ class _promote extends \IPS\Dispatcher\Controller
try
{
if( !$class OR !class_exists( $class ) )
{
throw new \InvalidArgumentException;
}
$object = $class::load( $id );
}
catch ( \Exception $ex )
@@ -405,6 +500,8 @@ class _promote extends \IPS\Dispatcher\Controller
{
$text = array();
$shareTo = array();
$processedForms = array();
foreach( $services as $service )
{
$key = mb_strtolower( $service->key );
@@ -413,9 +510,10 @@ class _promote extends \IPS\Dispatcher\Controller
$text[ $key ] = $values[ 'promote_social_content_' . $key ];
$shareTo[] = $key;
}
$processedForms[ $key ] = $service->processPromoteForm( $values );
}
$media = array();
if ( is_array( $values['promote_media'] ) )
{
@@ -481,6 +579,7 @@ class _promote extends \IPS\Dispatcher\Controller
$promote->share_to = $shareTo;
$promote->failed = 0; # Reset the failed flag if we're re-promoting
$promote->sent = 0;
$promote->form_data = $processedForms;
$promote->save();
if ( isset( \IPS\Request::i()->promote_id ) )
@@ -496,7 +595,7 @@ class _promote extends \IPS\Dispatcher\Controller
}
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 );
$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 ) );
}
+114 -29
View File
@@ -114,7 +114,7 @@ class _search extends \IPS\Dispatcher\Controller
$baseUrl = $baseUrl->setQueryString( 'tags', \IPS\Request::i()->tags );
}
$types = $this->_contentTypes();
$types = static::contentTypes();
/* Flood control */
\IPS\Request::floodCheck();
@@ -199,8 +199,16 @@ class _search extends \IPS\Dispatcher\Controller
foreach( $groups as $_idx => $groupId )
{
if( \IPS\Member\Group::load( $groupId )->g_bitoptions['gbw_hide_group'] )
try
{
if( \IPS\Member\Group::load( $groupId )->g_bitoptions['gbw_hide_group'] )
{
unset( $groups[ $_idx ] );
}
}
catch( \OutOfRangeException $e )
{
/* Group didn't exist, so let's ignore it */
unset( $groups[ $_idx ] );
}
}
@@ -339,9 +347,10 @@ class _search extends \IPS\Dispatcher\Controller
/* Set content type */
if ( isset( \IPS\Request::i()->type ) and array_key_exists( \IPS\Request::i()->type, $types ) )
{
$class = $types[ \IPS\Request::i()->type ];
if ( isset( \IPS\Request::i()->item ) )
{
$class = $types[ \IPS\Request::i()->type ];
try
{
$item = $class::loadAndCheckPerms( \IPS\Request::i()->item );
@@ -392,19 +401,19 @@ class _search extends \IPS\Dispatcher\Controller
$baseUrl = $baseUrl->setQueryString( 'search_min_comments', \IPS\Request::i()->search_min_comments );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_min_comments', FALSE, array( 'sprintf' => array( \IPS\Request::i()->search_min_comments ) ) );
}
if ( isset( \IPS\Request::i()->search_min_replies ) )
if ( isset( \IPS\Request::i()->search_min_replies ) AND isset( $class::$commentClass ) )
{
$filter->minimumComments( \IPS\Request::i()->search_min_replies + 1 );
$baseUrl = $baseUrl->setQueryString( 'search_min_replies', \IPS\Request::i()->search_min_replies );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_min_replies', FALSE, array( 'sprintf' => array( \IPS\Request::i()->search_min_replies ) ) );
}
if ( isset( \IPS\Request::i()->search_min_reviews ) )
if ( isset( \IPS\Request::i()->search_min_reviews ) AND isset( $class::$reviewClass ) )
{
$filter->minimumReviews( \IPS\Request::i()->search_min_reviews );
$baseUrl = $baseUrl->setQueryString( 'search_min_reviews', \IPS\Request::i()->search_min_reviews );
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_min_reviews', FALSE, array( 'sprintf' => array( \IPS\Request::i()->search_min_reviews ) ) );
}
if ( isset( \IPS\Request::i()->search_min_views ) )
if ( isset( \IPS\Request::i()->search_min_views ) AND isset( $class::$databaseColumnMap['views'] ) )
{
$filter->minimumViews( \IPS\Request::i()->search_min_views );
$baseUrl = $baseUrl->setQueryString( 'search_min_views', \IPS\Request::i()->search_min_views );
@@ -429,7 +438,7 @@ class _search extends \IPS\Dispatcher\Controller
}
/* Filter by club */
if ( isset( \IPS\Request::i()->club ) )
if ( isset( \IPS\Request::i()->club ) AND \IPS\Settings::i()->clubs )
{
$clubIds = array();
$clubNames = array();
@@ -521,12 +530,16 @@ class _search extends \IPS\Dispatcher\Controller
$tagList = array_map( function( $val )
{
return '\'' . htmlentities( $val, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . '\'';
return '\'' . htmlentities( $val, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . '\'';
}, explode( ',', \IPS\Request::i()->tags ) );
}
$title = '';
if ( \IPS\Request::i()->q )
{
\IPS\core\Facebook\Pixel::i()->Search = array(
'search_string' => \IPS\Request::i()->q
);
if ( \IPS\Request::i()->tags )
{
if ( isset( \IPS\Request::i()->eitherTermsOrTags ) and \IPS\Request::i()->eitherTermsOrTags === 'and' )
@@ -588,10 +601,11 @@ class _search extends \IPS\Dispatcher\Controller
$baseUrl = $baseUrl->setQueryString( 'sortby', \IPS\Request::i()->sortby );
$flags = ( isset( \IPS\Request::i()->eitherTermsOrTags ) and \IPS\Request::i()->eitherTermsOrTags === 'and' ) ? \IPS\Content\Search\Query::TERM_AND_TAGS : \IPS\Content\Search\Query::TERM_OR_TAGS;
if ( isset( \IPS\Request::i()->search_and_or ) and \IPS\Request::i()->search_and_or === 'or' )
$operator = NULL;
if ( isset( \IPS\Request::i()->search_and_or ) and in_array( \IPS\Request::i()->search_and_or, array( \IPS\Content\Search\Query::OPERATOR_OR, \IPS\Content\Search\Query::OPERATOR_AND ) ) )
{
$flags = $flags | \IPS\Content\Search\Query::TERM_OR_MODE;
$operator = \IPS\Request::i()->search_and_or;
$baseUrl = $baseUrl->setQueryString( 'search_and_or', \IPS\Request::i()->search_and_or );
}
@@ -605,7 +619,8 @@ class _search extends \IPS\Dispatcher\Controller
$results = $query->search(
isset( \IPS\Request::i()->q ) ? ( \IPS\Request::i()->q ) : NULL,
isset( \IPS\Request::i()->tags ) ? explode( ',', \IPS\Request::i()->tags ) : NULL,
$flags + \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY
$flags + \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY,
$operator
);
/* Get pagination */
@@ -622,7 +637,7 @@ class _search extends \IPS\Dispatcher\Controller
{
/* There's no point resetting the page at this point as the search query has been run and no results have been found */
$_SESSION['lastSearch'] = 0;
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'page', 1 ) );
\IPS\Output::i()->redirect( $baseUrl->setQueryString( 'page', 1 ), NULL, 303 );
}
$pagination = trim( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, $pages, $page, $query->resultsToGet ) );
@@ -690,7 +705,7 @@ class _search extends \IPS\Dispatcher\Controller
/* Types */
$types = array( '' => 'search_everything' );
$contentTypes = $this->_contentTypes();
$contentTypes = static::contentTypes();
$contentToggles = array();
$typeFields = array();
$typeFieldToggles = array('' => array( 'club' ) );
@@ -742,7 +757,13 @@ class _search extends \IPS\Dispatcher\Controller
$types[ $k ] = $k . '_pl';
if ( $k !== 'core_members' )
{
$typeFieldToggles[ $k ] = array_merge( $contentToggles, array( $k . '_node', 'search_min_views' ) );
$typeFieldToggles[ $k ][] = $k . '_node';
if( isset( $class::$databaseColumnMap['views'] ) )
{
$typeFieldToggles[ $k ][] = 'search_min_views';
}
if ( isset( $class::$commentClass ) )
{
if ( $class::$firstCommentRequired )
@@ -768,23 +789,26 @@ class _search extends \IPS\Dispatcher\Controller
/* Term */
$form->add( new \IPS\Helpers\Form\Text( 'q' ), NULL, 'search_tab_all' );
$form->add( new \IPS\Helpers\Form\Text( 'tags', \IPS\Request::i()->tags, FALSE, array( 'autocomplete' => TRUE ), NULL, NULL, NULL, 'tags' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Text( 'tags', \IPS\Request::i()->tags, FALSE, array( 'autocomplete' => array( 'minimized' => FALSE ) ), NULL, NULL, NULL, 'tags' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Radio( 'eitherTermsOrTags', \IPS\Request::i()->eitherTermsOrTags, FALSE, array( 'options' => array( 'or' => 'termsortags_or_desc', 'and' => 'termsortags_and_desc' ) ), NULL, NULL, NULL, 'eitherTermsOrTags' ), NULL, 'search_tab_content' );
/* 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 ) )
if( \IPS\Settings::i()->clubs )
{
$clubOptions = array();
foreach ( $clubs as $club )
$clubs = \IPS\Member\Club::clubs( \IPS\Member::loggedIn(), NULL, 'name', TRUE );
if ( is_object( $clubs ) AND $clubs->count( TRUE ) )
{
$clubOptions[ "c{$club->id}" ] = $club->name;
$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' => 'ipsField_fullWidth' ), NULL, NULL, NULL, 'club' ), NULL, 'search_tab_content' );
}
$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 */
@@ -795,15 +819,29 @@ class _search extends \IPS\Dispatcher\Controller
/* Other filters */
$form->add( new \IPS\Helpers\Form\Radio( 'search_in', \IPS\Request::i()->search_in, FALSE, array( 'options' => array( 'all' => 'titles_and_body', 'titles' => 'titles_only' ) ), NULL, NULL, NULL, 'searchIn' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Radio( 'search_and_or', \IPS\Request::i()->search_and_or, FALSE, array( 'options' => array( 'and' => 'search_and', 'or' => 'search_or' ) ), NULL, NULL, NULL, 'andOr' ), NULL, 'search_tab_content' );
$form->add( new \IPS\Helpers\Form\Radio( 'search_and_or', isset( \IPS\Request::i()->search_and_or ) ? \IPS\Request::i()->search_and_or : \IPS\Settings::i()->search_default_operator, FALSE, array( 'options' => array( 'and' => 'search_and', 'or' => 'search_or' ) ), NULL, NULL, NULL, 'andOr' ), NULL, 'search_tab_content' );
/* Nodes */
foreach ( $contentTypes as $k => $class )
{
if ( isset( $class::$containerNodeClass ) )
{
$nodes = NULL;
/* If we have a node type, we should only select nodes for that type */
if( isset( \IPS\Request::i()->type ) AND !empty( \IPS\Request::i()->type ) )
{
$typeInfo = explode( '_', \IPS\Request::i()->type );
$typeClass = 'IPS\\' . $typeInfo[0] . '\\' . mb_ucfirst( $typeInfo[1] );
if( $typeClass == $class )
{
$nodes = ( isset( \IPS\Request::i()->nodes ) ) ? \IPS\Request::i()->nodes : NULL;
}
}
$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, 'clubs' => \IPS\IPS::classUsesTrait( $nodeClass, 'IPS\Content\ClubContainer' ) ), NULL, NULL, NULL, $k . '_node' );
$field = new \IPS\Helpers\Form\Node( $k . '_node', $nodes, FALSE, array( 'class' => $nodeClass, 'subnodes' => FALSE, 'multiple' => TRUE, 'permissionCheck' => $nodeClass::searchableNodesPermission(), 'forceOwner' => FALSE, 'clubs' => ( \IPS\Settings::i()->clubs AND \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' );
}
@@ -1018,12 +1056,57 @@ class _search extends \IPS\Dispatcher\Controller
return $form;
}
/**
* Handle quicksearch and redirect to correct results page
*
* @return array
*/
public static function quicksearch()
{
$query = array();
if ( \IPS\Request::i()->q )
{
$query['q'] = \IPS\Request::i()->q;
if ( \IPS\Request::i()->type != 'all' )
{
if ( mb_substr( \IPS\Request::i()->type, 0, 11 ) === 'contextual_' )
{
if ( $json = json_decode( mb_substr( \IPS\Request::i()->type, 11 ), TRUE ) )
{
foreach ( $json as $k => $v )
{
$query[ $k ] = $v;
}
}
}
else
{
$query['type'] = \IPS\Request::i()->type;
}
}
if ( \IPS\Request::i()->search_and_or != \IPS\Settings::i()->search_default_operator )
{
$query['search_and_or'] = \IPS\Request::i()->search_and_or;
}
if ( \IPS\Request::i()->search_in == 'titles' )
{
$query['search_in'] = 'titles';
}
}
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=search&controller=search', 'front', 'search' )->setQueryString( $query ) );
}
/**
* Get the different content type extensions
*
* @return array
*/
protected function _contentTypes()
public static function contentTypes()
{
$types = array();
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
@@ -1039,7 +1122,7 @@ class _search extends \IPS\Dispatcher\Controller
/**
* Splits the search term into distinct matches
* e.g. one "two three" beccomes ['one', 'two three']
* e.g. one "two three" becomes ['one', 'two three']
*
* @return string
*/
@@ -1050,10 +1133,12 @@ class _search extends \IPS\Dispatcher\Controller
}
$words = preg_split("/[\s]*\\\"([^\\\"]+)\\\"[\s]*|[\s]*'([^']+)'[\s]*|[\s]+/", \IPS\Request::i()->q, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$words = \IPS\Content\Search\Index::i()->stemmedTerms( $words );
foreach( $words as $idx => $word )
{
$words[ $idx ] = htmlentities( $word, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ); // ENT_QUOTES is because this will go in a HTML attribute (data-term="$value") so if you include a single quote in your search query, it can break
$words[ $idx ] = htmlentities( $word, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ); // ENT_QUOTES is because this will go in a HTML attribute (data-term="$value") so if you include a single quote in your search query, it can break
}
return json_encode( $words );
@@ -1066,6 +1151,6 @@ class _search extends \IPS\Dispatcher\Controller
*/
protected function globalFilterOptions()
{
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'search' )->globalSearchMenuOptions( \IPS\Request::i()->checked ) );
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'search' )->globalSearchMenuOptions( explode( ',', \IPS\Request::i()->exclude ) ) );
}
}
+22 -15
View File
@@ -56,8 +56,8 @@ class _ajax extends \IPS\Dispatcher\Controller
$results[] = array(
'id' => $member->member_id,
'value' => $member->name,
'name' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->group['prefix'] . htmlspecialchars( $member->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) . $member->group['suffix'] : htmlspecialchars( $member->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'extra' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? htmlspecialchars( $member->email, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ) : $member->groupName,
'name' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? $member->group['prefix'] . htmlspecialchars( $member->name, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . $member->group['suffix'] : htmlspecialchars( $member->name, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'extra' => \IPS\Dispatcher::i()->controllerLocation == 'admin' ? htmlspecialchars( $member->email, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : $member->groupName,
'photo' => (string) $member->photo,
);
}
@@ -342,9 +342,9 @@ class _ajax extends \IPS\Dispatcher\Controller
$return['notifications']['data'][] = array(
'id' => $notification->id,
'title' => htmlspecialchars( $data['title'], \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'title' => htmlspecialchars( $data['title'], ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $data['url'],
'content' => isset( $data['content'] ) ? htmlspecialchars( $data['content'], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : NULL,
'content' => isset( $data['content'] ) ? htmlspecialchars( $data['content'], ENT_DISALLOWED, 'UTF-8', FALSE ) : NULL,
'date' => $notification->updated_time->getTimestamp(),
'author_photo' => $data['author'] ? $data['author']->photo : NULL
);
@@ -360,17 +360,24 @@ class _ajax extends \IPS\Dispatcher\Controller
foreach ( \IPS\Db::i()->select( 'map_topic_id', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1 AND map_has_unread=1 AND map_ignore_notification=0', \IPS\Member::loggedIn()->member_id ), 'map_last_topic_reply DESC', $messagesDifference ) as $conversationId )
{
$conversation = \IPS\core\Messenger\Conversation::load( $conversationId );
$message = $conversation->comments( 1, 0, 'date', 'desc' );
$return['messages']['data'][] = array(
'id' => $conversation->id,
'title' => htmlspecialchars( $conversation->title, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $conversation->url()->setQueryString( 'latest', 1 ),
'message' => $message->truncated(),
'date' => $message->mapped('date'),
'author_photo' => (string) $message->author()->photo
);
$conversation = \IPS\core\Messenger\Conversation::load( $conversationId );
$message = $conversation->comments( 1, 0, 'date', 'desc' );
if( $message )
{
$return['messages']['data'][] = array(
'id' => $conversation->id,
'title' => htmlspecialchars( $conversation->title, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ),
'url' => (string) $conversation->url()->setQueryString( 'latest', 1 ),
'message' => $message->truncated(),
'date' => $message->mapped('date'),
'author_photo' => (string) $message->author()->photo
);
}
else
{
\IPS\Log::log( "Private conversation {$conversation->id} titled {$conversation->title} has no messages", 'orphaned_data' );
}
}
}
}
@@ -0,0 +1,41 @@
<?php
/**
* @brief Cookie Policy
* @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 Dec 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;
}
/**
* Cookie Policy
*/
class _cookies extends \IPS\Dispatcher\Controller
{
/**
* Privacy Policy
*
* @return void
*/
protected function manage()
{
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=cookies', NULL, 'cookies' ), array(), 'loc_viewing_cookie_policy' );
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('cookies_about') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cookies_about');
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->cookies();
}
}
@@ -29,6 +29,6 @@ class _designermode extends \IPS\Dispatcher\Controller
*/
protected function missing()
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'theme_designers_mode_error_missing', FALSE, array( 'sprintf' => array( \IPS\Request::i()->id ) ) ), "DESMODE", 500 );
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'theme_designers_mode_error_missing', FALSE, array( 'sprintf' => array( intval( \IPS\Request::i()->id ) ) ) ), "4C370/1", 500 );
}
}
@@ -51,7 +51,7 @@ class _editor extends \IPS\Dispatcher\Controller
protected function code()
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( \IPS\Request::i()->val, \IPS\Request::i()->editorId, md5( uniqid() ), \IPS\Request::i()->lang ?: '' );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( \IPS\Request::i()->val, \IPS\Request::i()->editorId, md5( mt_rand() ), \IPS\Request::i()->lang ?: '' );
}
/**
@@ -155,7 +155,7 @@ class _editor extends \IPS\Dispatcher\Controller
}
else
{
$title = \IPS\Request::i()->title ?: $url;
$title = \IPS\Request::i()->title ?: (string) $url;
$insert = "<a href='{$url}' ipsNoEmbed='true'>{$title}</a>";
}
@@ -178,41 +178,42 @@ class _editor extends \IPS\Dispatcher\Controller
}
/**
* Get Emoticons Configuration
* Get Emoji
*
* @return void
*/
protected function emoticons()
protected function emoji()
{
$emoticons = array();
$emoji = ( \IPS\Settings::i()->emoji_style == 'disabled' or !\IPS\Settings::i()->getFromConfGlobal('sql_utf8mb4') ) ? array() : json_decode( file_get_contents( \IPS\ROOT_PATH . '/applications/core/data/emoji.json' ), TRUE );
foreach ( \IPS\Db::i()->select( '*', 'core_emoticons', NULL, 'emo_set_position,emo_position' ) as $row )
{
if ( !isset( $emoticons[ $row['emo_set'] ] ) )
$shortcode = ( \IPS\Settings::i()->emoji_shortcodes and preg_match( '/^:.*:$/', $row['typed'] ) );
try
{
$setLang = 'core_emoticon_group_' . $row['emo_set'];
$emoticons[ $row['emo_set'] ] = array(
'title' => \IPS\Member::loggedIn()->language()->addToStack( $setLang ),
'total' => 0,
'emoticons' => array(),
);
$categoryName = \IPS\Member::loggedIn()->language()->get( 'core_emoticon_group_' . $row['emo_set'] );
}
catch( \UnderflowException $e )
{
$categoryName = '_default';
}
$emoticons[ $row['emo_set'] ]['emoticons'][] = array(
'src' => \IPS\File::get( 'core_Emoticons', $row['image'] )->url,
'srcset' => $row['image_2x'] ? \IPS\File::get( 'core_Emoticons', $row['image_2x'] )->url . ' 2x' : FALSE,
'height' => $row['height'] ?: FALSE,
'width' => $row['width'] ?: FALSE,
'text' => $row['typed']
$emoji[ $row['emo_set'] ][] = array(
'code' => 'custom-' . $row['emo_set'] . '-' . $row['id'],
'name' => $row['typed'],
'skinTone' => false,
'shortNames' => $shortcode ? array( trim( $row['typed'], ':' ) ) : array(),
'ascii' => $shortcode ? array() : array( $row['typed'] ),
'categoryName' => $categoryName,
'image' => \IPS\File::get( 'core_Emoticons', $row['image'] )->url,
'image2x' => $row['image_2x'] ? \IPS\File::get( 'core_Emoticons', $row['image_2x'] )->url : FALSE,
'width' => $row['width'],
'height' => $row['height'],
);
}
}
foreach ( $emoticons as $set => $data )
{
$emoticons[ $set ]['total'] = count( $data['emoticons'] );
}
\IPS\Output::i()->json( $emoticons );
\IPS\Output::i()->json( $emoji );
}
/**
@@ -37,9 +37,6 @@ class _followed extends \IPS\Dispatcher\Controller
/* Get the different types */
$types = array();
/* Don't forget Members */
$types['core'] = array( 'core_member' => "\IPS\Member" );
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
{
@@ -61,6 +58,9 @@ class _followed extends \IPS\Dispatcher\Controller
}
}
}
/* Don't forget Members - add this on to the end so it never defaults UNLESS we only have apps that do not have followable content */
$types['core'] = array( 'core_member' => "\IPS\Member" );
/* What type are we looking at? */
$currentAppModule = NULL;
@@ -84,11 +84,6 @@ class _followed extends \IPS\Dispatcher\Controller
{
foreach ( $_types as $key => $class )
{
if ( $key == 'core_member' )
{
continue;
}
$currentAppModule = $appModule;
$currentType = $key;
break 2;
@@ -31,11 +31,14 @@ class _guidelines extends \IPS\Dispatcher\Controller
{
if ( \IPS\Settings::i()->gl_type == "none" )
{
\IPS\Output::i()->error( 'node_error', '', 404 ); /* @todo Error code */
\IPS\Output::i()->error( 'node_error', '2C380/1', 404, 'guidelines_set_to_none_admin' );
}
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=guidelines', NULL, 'guidelines' ), array(), 'loc_viewing_guidelines' );
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('guidelines') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('guidelines');
+81 -115
View File
@@ -34,24 +34,47 @@ class _login extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
}
/* Force HTTPs? */
if ( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' and \IPS\Settings::i()->logins_over_https and \IPS\Request::i()->url()->data['scheme'] !== 'https' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
}
/* Init login class */
$login = new \IPS\Login( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ) );
/* Init login class */
$login = new \IPS\Login( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' ) );
/* What's our referrer? */
$ref = \IPS\Request::i()->ref;
/* Process */
$error = isset( \IPS\Request::i()->_err ) && \IPS\Member::loggedIn()->language()->checkKeyExists( \IPS\Request::i()->_err ) ? \IPS\Request::i()->_err : NULL;
$error = NULL;
try
{
$member = $login->authenticate();
if ( $member !== NULL )
if ( $success = $login->authenticate() )
{
$this->_doLogin( $member, $login->flags['signin_anonymous'], $login->flags['remember_me'], \IPS\Login::getDestination(), FALSE, $login->usedHandler );
if ( $ref and $ref = @base64_decode( $ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( $ref );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) or $ref->base !== 'front' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
$ref = \IPS\Http\Url::internal('');
}
}
else
{
$ref = \IPS\Http\Url::internal('');
}
if ( $success->mfa() )
{
$_SESSION['processing2FA'] = array( 'memberId' => $success->member->member_id, 'anonymous' => $success->anonymous, 'remember' => $success->rememberMe, 'destination' => (string) $ref, 'handler' => $success->handler->id );
\IPS\Output::i()->redirect( $ref->setQueryString( '_mfaLogin', 1 ) );
}
$success->process();
\IPS\Output::i()->redirect( $ref->setQueryString( '_fromLogin', 1 ) );
}
}
catch ( \IPS\Login\Exception $e )
@@ -59,91 +82,33 @@ class _login extends \IPS\Dispatcher\Controller
if ( $e->getCode() === \IPS\Login\Exception::MERGE_SOCIAL_ACCOUNT )
{
$e->member = $e->member->member_id;
$e->handler = $e->handler->id;
$_SESSION['linkAccounts'] = json_encode( $e );
$linkUrl = \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' );
if ( isset( \IPS\Request::i()->ref ) )
{
$linkUrl = $linkUrl->setQueryString( 'ref', \IPS\Request::i()->ref );
}
\IPS\Output::i()->redirect( $linkUrl );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' )->setQueryString( 'ref', $ref ), '', 303 );
}
$error = $e->getMessage();
}
if ( \IPS\Request::i()->isAjax() && $error )
{
\IPS\Output::i()->json( array( 'status' => 'error', 'error' => $error ), 401 );
}
else
{
/* Display Login Form */
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('login');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->login( $login->forms(), $error );
}
/* Display Login Form */
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('login');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->login( $login, $ref, $error );
/* Set Session Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', NULL, 'login' ), array(), 'loc_logging_in' );
}
/**
* Process the login
*
* @param \IPS\Member $member The member
* @param bool $anonymous If the login is anonymous
* @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, $loginHandler=NULL )
{
/* Get destination */
if ( !$destination )
{
$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', $device->known ? 'AuthenticateFrontKnown' : 'AuthenticateFront', \IPS\Http\Url::internal( '' ), $member ) )
{
$_SESSION['processing2FA'] = array( 'memberId' => $member->member_id, 'anonymous' => $anonymous, 'remember' => $rememberMe, 'destination' => (string) $destination, 'handler' => $loginHandler );
\IPS\Output::i()->redirect( $destination->setQueryString( '_mfaLogin', 1 ) );
}
/* Log in */
\IPS\Session::i()->setMember( $member );
if ( $anonymous and !\IPS\Settings::i()->disable_anonymous )
{
\IPS\Session::i()->setAnon();
}
/* Log device */
$device->anonymous = $anonymous and !\IPS\Settings::i()->disable_anonymous;
$device->updateAfterAuthentication( $rememberMe, $loginHandler );
/* Member sync */
$member->memberSync( 'onLogin', array( \IPS\Login::getDestination() ) );
/* Redirect */
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ), '', 303 );
}
/**
* MFA
*
* @return void
*/
protected function mfa()
{
{
/* Have we logged in? */
$member = NULL;
if ( isset( $_SESSION['processing2FA'] ) )
@@ -156,7 +121,7 @@ class _login extends \IPS\Dispatcher\Controller
}
/* Where do we want to go? */
$destination = NULL;
$destination = \IPS\Http\Url::internal( '' );
try
{
$destination = \IPS\Http\Url::createFromString( $_SESSION['processing2FA']['destination'] );
@@ -167,8 +132,9 @@ class _login extends \IPS\Dispatcher\Controller
$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, $_SESSION['processing2FA']['handler'] );
{
( new \IPS\Login\Success( $member, \IPS\Login\Handler::load( $_SESSION['processing2FA']['handler'] ), $_SESSION['processing2FA']['remember'], $_SESSION['processing2FA']['anonymous'] ) )->process();
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ), '', 303 );
}
/* Nope, just send us where we want to go not logged in */
@@ -199,35 +165,36 @@ class _login extends \IPS\Dispatcher\Controller
*/
protected function link()
{
/* Get the member we're linking with */
if ( !isset( $_SESSION['linkAccounts'] ) )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
$details = json_decode( $_SESSION['linkAccounts'], TRUE );
$member = \IPS\Member::load( $details['member'] );
if ( !$member->member_id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
$form = new \IPS\Helpers\Form( 'link_accounts', 'login' );
if ( isset( \IPS\Request::i()->ref ) )
/* And then handler to link with */
$handler = \IPS\Login\Handler::load( $details['handler'] );
/* Init reauthentication */
$login = new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login&do=link', 'front', 'login' )->setQueryString( 'ref', isset( \IPS\Request::i()->ref ) ? \IPS\Request::i()->ref : NULL ), \IPS\Login::LOGIN_REAUTHENTICATE );
$login->reauthenticateAs = $member;
$error = NULL;
/* If successful (or if there's no way to reauthenticate which would only happen if a login handler has been deleted)) complete the link... */
try
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
$form->addDummy( 'email_address', htmlspecialchars( isset( $details['email'] ) ? $details['email'] : $member->email, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'validateFor' => $member ) ) );
if ( $values = $form->values() )
{
try
{
$class = 'IPS\Login\\' . ucfirst( $details['handler'] );
$class::link( $member, $details['details'] );
if ( $success = $login->authenticate() or ( !count( $login->usernamePasswordMethods() ) and !count( $login->buttonMethods() ) ) )
{
$handler->completeLink( $member, $details['details'] );
unset( $_SESSION['linkAccounts'] );
$destination = NULL;
$destination = \IPS\Http\Url::internal( '' );
if ( isset( \IPS\Request::i()->ref ) )
{
try
@@ -240,18 +207,27 @@ class _login extends \IPS\Dispatcher\Controller
}
catch ( \Exception $e ) { }
}
$this->_doLogin( $member, FALSE, TRUE, $destination, FALSE, $details['handler'] );
$success = new \IPS\Login\Success( $member, $handler );
if ( $success->mfa() )
{
$_SESSION['processing2FA'] = array( 'memberId' => $success->member->member_id, 'anonymous' => $success->anonymous, 'remember' => $success->rememberMe, 'destination' => (string) $destination, 'handler' => $success->handler->id );
\IPS\Output::i()->redirect( $destination->setQueryString( '_mfaLogin', 1 ) );
}
$success->process();
\IPS\Output::i()->redirect( $destination->setQueryString( '_fromLogin', 1 ) );
}
catch ( \IPS\Login\Exception $e )
{
$form->error = $e->getMessage();
}
}
catch ( \IPS\Login\Exception $e )
{
$error = $e->getMessage();
}
/* Otherwise show the reauthenticate form */
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('login');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->mergeSocialAccount( $details['handler'], $member, $form );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->mergeSocialAccount( $handler, $member, $login, $error );
}
/**
@@ -309,16 +285,6 @@ class _login extends \IPS\Dispatcher\Controller
setcookie( session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] );
session_destroy();
/* Login handler callback */
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
try
{
$handler->logoutAccount( $member, $redirectUrl );
}
catch( \BadMethodCallException $e ) {}
}
/* Member sync callback */
$member->memberSync( 'onLogout', array( $redirectUrl ) );
@@ -345,7 +311,7 @@ class _login extends \IPS\Dispatcher\Controller
/* Not logged in as admin? */
if ( $admin->member_id != \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( array( 'ref' => base64_encode( \IPS\Request::i()->url() ), '_err' => 'login_as_user_login' ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( array( 'ref' => base64_encode( \IPS\Request::i()->url() ), '_err' => 'login_as_user_login' ) ) );
}
/* Do it */
@@ -22,6 +22,26 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _lostpass extends \IPS\Dispatcher\Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
{
if ( \IPS\Settings::i()->allow_forgot_password == 'disabled' )
{
\IPS\Output::i()->error( 'page_doesnt_exist', '2S151/2', 404, '' );
}
if ( \IPS\Settings::i()->allow_forgot_password == 'redirect' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Settings::i()->allow_forgot_password_target ) );
}
return parent::execute();
}
/**
* Manage
*
@@ -32,11 +52,7 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form( "lostpass", 'request_password' );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'bypassProfanity' => TRUE ), function( $val ){
/* Check email exists */
$member = \IPS\Member::load( $val, 'email' );
if( !$member->member_id )
if( !\IPS\Login::emailIsInUse( $val ) )
{
throw new \LogicException( 'lost_pass_no_email' );
}
@@ -47,62 +63,107 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Handle the reset */
if ( $values = $form->values() )
{
/* Load the member */
/* If using "normal" method and we have an account, and at least one login handler we can process a password change for, we're good */
$member = \IPS\Member::load( $values['email_address'], 'email' );
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
if ( $member->member_id and \IPS\Settings::i()->allow_forgot_password == 'normal' )
{
$existing = \IPS\Db::i()->select( array( 'vid', 'email_sent' ), 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) )->first();
$vid = $existing['vid'];
/* If we sent a lost password email within the last 15 minutes, don't send another one otherwise someone could be a nuisence */
if ( $existing['email_sent'] and $existing['email_sent'] > ( time() - 900 ) )
foreach ( \IPS\Login::methods() as $method )
{
$sendEmail = FALSE;
if ( $method->canChangePassword( $member ) )
{
return $this->_sendForgotPasswordEmail( $member );
}
}
else
{
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $vid ) );
}
}
catch ( \UnderflowException $e )
{
$vid = md5( $member->members_pass_hash . \IPS\Login::generateRandomString() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'lost_pass' => 1,
'ip_address' => $member->ip_address,
'email_sent' => time(),
) );
}
/* Send email */
if ( $sendEmail )
/* If not, send them to the handler if we can */
foreach( \IPS\Login::methods() as $method )
{
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
$message = "lost_pass_confirm";
if( $method->emailIsInUse( $values['email_address'] ) === TRUE )
{
if ( $url = $method->forgotPasswordUrl() )
{
\IPS\Output::i()->redirect( $url );
}
}
}
/* If we have no way to reset the password, can we allow creating a local password as a last attempt? */
if ( $member->member_id )
{
foreach( \IPS\Login::methods() as $method )
{
if ( $method instanceof \IPS\Login\Handler\Standard )
{
return $this->_sendForgotPasswordEmail( $member );
}
}
}
/* Otherwise, sorry, we can't do this */
\IPS\Output::i()->error( 'lost_pass_not_possible', '1S151/3', 403, '' );
}
/* Show form */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPass( $form );
}
/**
* Send forgot password email
*
* @param \IPS\Member $member The member
* @return void
*/
protected function _sendForgotPasswordEmail( \IPS\Member $member )
{
/* If we have an existing validation record, we can just reuse it */
$sendEmail = TRUE;
try
{
$existing = \IPS\Db::i()->select( array( 'vid', 'email_sent' ), 'core_validating', array( 'member_id=? AND lost_pass=1', $member->member_id ) )->first();
$vid = $existing['vid'];
/* If we sent a lost password email within the last 15 minutes, don't send another one otherwise someone could be a nuisence */
if ( $existing['email_sent'] and $existing['email_sent'] > ( time() - 900 ) )
{
$sendEmail = FALSE;
}
else
{
$message = "lost_pass_too_soon";
\IPS\Db::i()->update( 'core_validating', array( 'email_sent' => time() ), array( 'vid=?', $vid ) );
}
/* Show confirmation page with further instructions */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm( $message );
}
catch ( \UnderflowException $e )
{
$vid = md5( $member->members_pass_hash . \IPS\Login::generateRandomString() );
\IPS\Db::i()->insert( 'core_validating', array(
'vid' => $vid,
'member_id' => $member->member_id,
'entry_date' => time(),
'lost_pass' => 1,
'ip_address' => $member->ip_address,
'email_sent' => time(),
) );
}
/* Send email */
if ( $sendEmail )
{
\IPS\Email::buildFromTemplate( 'core', 'lost_password_init', array( $member, $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
$message = "lost_pass_confirm";
}
else
{
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPass( $form );
$message = "lost_pass_too_soon";
}
/* Show confirmation page with further instructions */
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm( $message );
}
/**
@@ -135,21 +196,17 @@ class _lostpass extends \IPS\Dispatcher\Controller
/* Reset the failed logins storage - we don't need to save because the login handler will do that for us later */
$member->failed_logins = array();
/* Now reset the member's password */
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
/* Now reset the member's password. If no handlers accept the change, create a local password */
if ( !$member->changePassword( $values['password'], 'lost' ) )
{
/* We cannot update our password in some login handlers, that's ok */
try
{
$handler->changePassword( $member, $values['password'] );
}
catch( \BadMethodCallException $e ){}
$member->setLocalPassword( $values['password'] );
$member->save();
}
/* 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'] ), '' );
\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 ) );
@@ -93,6 +93,8 @@ class _metatags extends \IPS\Dispatcher\Controller
*/
protected function end()
{
\IPS\Session::i()->csrfCheck();
$_SESSION['live_meta_tags'] = FALSE;
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( \IPS\Request::i()->url ) );
@@ -113,6 +113,12 @@ class _notifications extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* Log if admin mail setting is changed */
if ( \IPS\Member::loggedIn()->allow_admin_mails !== $values['allow_admin_mails'] )
{
\IPS\Member::loggedIn()->logHistory( 'core', 'admin_mails', array( 'enabled' => $values['allow_admin_mails'] ) );
}
\IPS\Member::loggedIn()->allow_admin_mails = $values['allow_admin_mails'];
\IPS\Member::loggedIn()->auto_track = json_encode( array(
'content' => ( is_array( $values['auto_track'] ) AND in_array( 'content', $values['auto_track'] ) ) ? 1 : 0,
@@ -168,12 +174,12 @@ class _notifications extends \IPS\Dispatcher\Controller
{
foreach ( $ext->classes as $classname )
{
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname::$containerNodeClass;
break;
@@ -182,7 +188,7 @@ class _notifications extends \IPS\Dispatcher\Controller
{
foreach( $classname::$containerFollowClasses as $followClass )
{
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $followClass;
break;
@@ -216,6 +222,11 @@ class _notifications extends \IPS\Dispatcher\Controller
$class = 'IPS\\Member';
}
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\Member\Club';
}
if ( !$class )
{
\IPS\Output::i()->error( 'node_error', '2C154/3', 404, '' );
@@ -223,7 +234,6 @@ class _notifications extends \IPS\Dispatcher\Controller
/* Get thing */
$thing = NULL;
$indexId = NULL;
try
{
if ( in_array( 'IPS\Node\Model', class_parents( $class ) ) )
@@ -242,17 +252,19 @@ class _notifications extends \IPS\Dispatcher\Controller
}
catch ( \Exception $e ) { }
}
else if ( $class != "IPS\Member" )
elseif ( $class == 'IPS\Member\Club' )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'follow_thing', FALSE, array( 'sprintf' => array( $thing->_title ) ) );
\IPS\Output::i()->breadcrumb = array(
array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs') ),
array( $thing->url(), $thing->name )
);
}
elseif ( $class != "IPS\Member" )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'follow_thing', FALSE, array( 'sprintf' => array( $thing->mapped('title') ) ) );
/* Work out the index ID */
try
{
$indexId = \IPS\Content\Search\Index::i()->getIndexId( $thing );
}
catch ( \UnderflowException $e ) { }
/* Set navigation */
$container = NULL;
@@ -300,7 +312,7 @@ class _notifications extends \IPS\Dispatcher\Controller
{
$type = 'follower_content';
}
elseif ( in_array( 'IPS\Content\Item', class_parents( $class ) ) )
elseif ( $class == 'IPS\Member\Club' or in_array( 'IPS\Content\Item', class_parents( $class ) ) )
{
$type = 'new_comment';
}
@@ -348,8 +360,11 @@ class _notifications extends \IPS\Dispatcher\Controller
if ( $class != "IPS\Member" )
{
$options['daily'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_daily');
$options['weekly'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_weekly');
if ( $class != "IPS\Member\Club" )
{
$options['daily'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_daily');
$options['weekly'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_weekly');
}
$options['none'] = \IPS\Member::loggedIn()->language()->addToStack('follow_type_no_notification');
}
@@ -361,7 +376,7 @@ class _notifications extends \IPS\Dispatcher\Controller
) ) );
}
else
{
{
foreach ( $options as $k => $v )
{
$form->hiddenValues[ $k ] = $v;
@@ -401,7 +416,6 @@ class _notifications extends \IPS\Dispatcher\Controller
'follow_notify_freq' => ( $class == "IPS\Member" ) ? 'immediate' : $values['follow_type'],
'follow_notify_sent' => 0,
'follow_visible' => 1,
'follow_index_id' => $indexId,
);
if ( $current )
{
@@ -412,6 +426,33 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Db::i()->insert( 'core_follow', $save );
}
/* Also follow all nodes if following club */
if( $class == "IPS\Member\Club" )
{
foreach ( $thing->nodes() as $node )
{
$itemClass = $node['node_class']::$contentItemClass;
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
$save = array(
'follow_id' => md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . \IPS\Member::loggedIn()->member_id ),
'follow_app' => $followApp,
'follow_area' => $followArea,
'follow_rel_id' => $node['node_id'],
'follow_member_id' => \IPS\Member::loggedIn()->member_id,
'follow_is_anon' => !$values['follow_public'],
'follow_added' => time(),
'follow_notify_do' => ( isset( $values['follow_type'] ) AND $values['follow_type'] == 'none' ) ? 0 : 1,
'follow_notify_meta' => '',
'follow_notify_freq' => $values['follow_type'],
'follow_notify_sent' => 0,
'follow_visible' => 1,
);
\IPS\Db::i()->insert( 'core_follow', $save, TRUE );
}
}
/* Send notification if following member */
if( $class == "IPS\Member" )
{
@@ -463,40 +504,46 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', \IPS\Request::i()->id, \IPS\Member::loggedIn()->member_id ) );
/* Get class */
$class = NULL;
foreach ( \IPS\Application::load( \IPS\Request::i()->follow_app )->extensions( 'core', 'ContentRouter' ) as $ext )
/* Get class */
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'member' )
{
foreach ( $ext->classes as $classname )
$class = 'IPS\\Member';
}
elseif( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\\Member\Club';
}
else
{
$class = NULL;
foreach ( \IPS\Application::load( \IPS\Request::i()->follow_app )->extensions( 'core', 'ContentRouter' ) as $ext )
{
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
foreach ( $ext->classes as $classname )
{
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname::$containerNodeClass;
break;
}
if( isset( $classname::$containerFollowClasses ) )
{
foreach( $classname::$containerFollowClasses as $followClass )
if ( $classname == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area ) )
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $classname::$containerNodeClass;
break;
}
if( isset( $classname::$containerFollowClasses ) )
{
foreach( $classname::$containerFollowClasses as $followClass )
{
$class = $followClass;
break;
if( $followClass == 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area ) )
{
$class = $followClass;
break;
}
}
}
}
}
}
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'member' )
{
$class = 'IPS\\Member';
}
/* Get thing */
$thing = NULL;
@@ -515,6 +562,19 @@ class _notifications extends \IPS\Dispatcher\Controller
catch ( \OutOfRangeException $e )
{
}
/* Unfollow club areas */
if( $class == "IPS\Member\Club" )
{
foreach ( $thing->nodes() as $node )
{
$itemClass = $node['node_class']::$contentItemClass;
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . \IPS\Member::loggedIn()->member_id ), \IPS\Member::loggedIn()->member_id ) );
}
}
if ( \IPS\Request::i()->isAjax() )
{
@@ -542,9 +602,13 @@ class _notifications extends \IPS\Dispatcher\Controller
{
$class = 'IPS\\Member';
}
else if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\\Member\Club';
}
else
{
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area );
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
}
if ( !class_exists( $class ) )
@@ -566,6 +630,13 @@ class _notifications extends \IPS\Dispatcher\Controller
$anonymous = $classname::containerFollowers( $thing, $classname::FOLLOW_ANONYMOUS )->count( TRUE );
$title = $thing->_title;
}
else if ( $class == "IPS\Member\Club" )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
$anonymous = $thing->followers( $class::FOLLOW_ANONYMOUS )->count( TRUE );
$title = $thing->_title;
}
else if ( $class != "IPS\Member" )
{
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
@@ -617,9 +688,13 @@ class _notifications extends \IPS\Dispatcher\Controller
{
$class = 'IPS\\Member';
}
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'club' )
{
$class = 'IPS\\Member\Club';
}
else
{
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . ucfirst( \IPS\Request::i()->follow_area );
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
}
if ( !class_exists( $class ) )
{
@@ -693,6 +768,23 @@ class _notifications extends \IPS\Dispatcher\Controller
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', \IPS\Request::i()->follow_app, \IPS\Request::i()->follow_area, \IPS\Request::i()->follow_id ) );
if( \IPS\Request::i()->follow_area == 'club' )
{
try
{
$club = \IPS\Member\Club::load( \IPS\Request::i()->follow_id );
foreach ( $club->nodes() as $node )
{
$itemClass = $node['node_class']::$contentItemClass;
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', $followApp, $followArea, $node['node_id'] ) );
}
}
catch ( \OutOfRangeException $e ) { }
}
\IPS\Output::i()->redirect( ( !empty( $_SERVER['HTTP_REFERER'] ) ) ? \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal( '' ), 'followers_removed' );
}
}
@@ -31,7 +31,7 @@ class _privacy extends \IPS\Dispatcher\Controller
{
if ( \IPS\Settings::i()->privacy_type == "none" )
{
\IPS\Output::i()->error( 'node_error', '', 404 ); /* @todo Error code */
\IPS\Output::i()->error( 'node_error', '2C381/1', 404, 'privacy_set_to_none_acp' );
}
/* Set Session Location */
@@ -34,11 +34,19 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Settings::i()->base_url );
}
if( !\IPS\Settings::i()->allow_reg and \IPS\Request::i()->do !== 'complete'
if( \IPS\Request::i()->do !== 'complete'
and \IPS\Request::i()->do !== 'changeEmail' and \IPS\Request::i()->do !== 'validate'
and \IPS\Request::i()->do !== 'validating' and \IPS\Request::i()->do !== 'reconfirm' )
and \IPS\Request::i()->do !== 'validating' and \IPS\Request::i()->do !== 'reconfirm'
and \IPS\Request::i()->do !== 'finish' )
{
\IPS\Output::i()->error( 'reg_disabled', '2S129/5', 403, '' );
if ( \IPS\Login::registrationType() == 'redirect' )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Settings::i()->allow_reg_target ) );
}
elseif ( \IPS\Login::registrationType() == 'disabled' )
{
\IPS\Output::i()->error( 'reg_disabled', '2S129/5', 403, '' );
}
}
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
@@ -62,20 +70,20 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Output::i()->allowDefaultWidgets = FALSE;
/* Quick registration does not work with COPPA */
if ( \IPS\Settings::i()->quick_register )
if ( \IPS\Login::registrationType() == 'normal' )
{
$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' ) )
if( \IPS\Request::i()->isAjax() )
{
\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 ) ) );
\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' ), \IPS\Login::LOGIN_REGISTRATION_FORM ) );
}
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 ) ) );
\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' ), \IPS\Login::LOGIN_REGISTRATION_FORM ) ), new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) ) );
}
return;
@@ -137,7 +145,7 @@ class _register extends \IPS\Dispatcher\Controller
{
$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 ) ) );
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' ), \IPS\Login::LOGIN_REGISTRATION_FORM ) );
};
/* Output */
@@ -209,18 +217,36 @@ class _register extends \IPS\Dispatcher\Controller
/* Log them in */
\IPS\Session::i()->setMember( $member );
\IPS\Member\Device::loadOrCreate( $member, FALSE )->updateAfterAuthentication( TRUE, '' );
\IPS\Member\Device::loadOrCreate( $member, FALSE )->updateAfterAuthentication( TRUE, NULL );
$redirectUrl = \IPS\Login::getRegistrationDestination( $member );
if ( isset( \IPS\Request::i()->ref ) and $ref = @base64_decode( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( $ref );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) or $ref->base !== 'front' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
$ref = \IPS\Http\Url::internal('');
}
}
else
{
$ref = \IPS\Http\Url::internal('');
}
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'redirect' => (string) $redirectUrl ) );
\IPS\Output::i()->json( array( 'redirect' => (string) $ref ) );
}
else
{
\IPS\Output::i()->redirect( $redirectUrl );
\IPS\Output::i()->redirect( $ref );
}
}
}
@@ -241,7 +267,7 @@ class _register extends \IPS\Dispatcher\Controller
$haveRequired = FALSE;
foreach( $steps AS $id => $step )
{
if ( $step->required )
if ( $step->required AND !$step->completed( \IPS\Member::loggedIn() ) )
{
$haveRequired = TRUE;
break;
@@ -253,8 +279,7 @@ class _register extends \IPS\Dispatcher\Controller
/* 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 )
@@ -265,6 +290,8 @@ class _register extends \IPS\Dispatcher\Controller
}
}
$wizardSteps = \IPS\Member\ProfileStep::setOrder( $wizardSteps );
$wizardSteps = array_merge( $wizardSteps, array( 'profile_done' => function( $data ) {
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'saved' );
} ) );
@@ -288,11 +315,11 @@ class _register extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form( 'form', 'register_button', NULL, array( 'data-controller' => 'core.front.system.register') );
$form->add( new \IPS\Helpers\Form\Text( 'username', NULL, TRUE, array( 'accountUsername' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'accountEmail' => TRUE, 'maxLength' => 150, 'bypassProfanity' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter, 'checkStrength' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password' ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'showMeter' => \IPS\Settings::i()->password_strength_meter, 'checkStrength' => TRUE, 'bypassProfanity' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Password( 'password_confirm', NULL, TRUE, array( 'confirm' => 'password', 'bypassProfanity' => TRUE ) ) );
/* Profile fields */
if ( ! \IPS\Settings::i()->quick_register )
if ( \IPS\Login::registrationType() == 'full' )
{
foreach ( \IPS\core\ProfileFields\Field::fields( array(), \IPS\core\ProfileFields\Field::REG ) as $group => $fields )
{
@@ -330,7 +357,15 @@ class _register extends \IPS\Dispatcher\Controller
if( $qanda )
{
$question = \IPS\Db::i()->select( '*', 'core_question_and_answer', array( 'qa_id=?', $qanda ) )->first();
try
{
$question = \IPS\Db::i()->select( '*', 'core_question_and_answer', array( 'qa_id=?', $qanda ) )->first();
}
catch( \UnderflowException $e )
{
throw new \DomainException( 'q_and_a_incorrect' );
}
$answers = json_decode( $question['qa_answers'] );
if( $answers )
@@ -380,14 +415,14 @@ class _register extends \IPS\Dispatcher\Controller
$form->addSeparator();
}
$form->add( new \IPS\Helpers\Form\Checkbox( 'reg_admin_mails', TRUE, FALSE ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'reg_admin_mails', \IPS\Settings::i()->updates_consent_default == 'enabled' ? TRUE : FALSE, FALSE ) );
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] = sprintf( \IPS\Member::loggedIn()->language()->get("reg_agreed_terms"), \IPS\Http\Url::internal( 'app=core&module=system&controller=terms', 'front', 'terms' ) );
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] = sprintf( \IPS\Member::loggedIn()->language()->get("reg_agreed_terms"), \IPS\Http\Url::internal( 'app=core&module=system&controller=terms', 'front', 'terms', array(), \IPS\Http\Url::PROTOCOL_RELATIVE ) );
/* Build the appropriate links for registration terms & privacy policy */
if ( \IPS\Settings::i()->privacy_type == "internal" )
{
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] .= sprintf( \IPS\Member::loggedIn()->language()->get("reg_privacy_link"), \IPS\Http\Url::internal( 'app=core&module=system&controller=privacy', 'front', 'privacy' ), 'data-ipsDialog data-ipsDialog-size="wide" data-ipsDialog-title="' . \IPS\Member::loggedIn()->language()->get("privacy") . '"' );
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] .= sprintf( \IPS\Member::loggedIn()->language()->get("reg_privacy_link"), \IPS\Http\Url::internal( 'app=core&module=system&controller=privacy', 'front', 'privacy', array(), \IPS\Http\Url::PROTOCOL_RELATIVE ), 'data-ipsDialog data-ipsDialog-size="wide" data-ipsDialog-title="' . \IPS\Member::loggedIn()->language()->get("privacy") . '"' );
}
else if ( \IPS\Settings::i()->privacy_type == "external" )
{
@@ -478,33 +513,40 @@ class _register extends \IPS\Dispatcher\Controller
$member = new \IPS\Member;
$member->name = $values['username'];
$member->email = $values['email_address'];
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $values['password'] );
$member->setLocalPassword( $values['password'] );
$member->allow_admin_mails = $values['reg_admin_mails'];
$member->member_group_id = \IPS\Settings::i()->member_group;
$member->members_bitoptions['view_sigs'] = TRUE;
$member->last_visit = time();
/* Query spam service */
$spamCode = NULL;
$spamAction = NULL;
if( \IPS\Settings::i()->spam_service_enabled )
{
if( $member->spamService() == 4 )
$spamAction = $member->spamService( 'register', NULL, $spamCode );
if( $spamAction == 4 )
{
\IPS\Output::i()->error( 'spam_denied_account', '2S129/1', 403, '' );
}
}
/* 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 )
if ( \IPS\Settings::i()->quick_register )
{
$extension = $step->extension;
$extension::formatFormValues( $values, $member, $form );
/* 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();
$member->logHistory( 'core', 'account', array( 'type' => 'register', 'spamCode' => $spamCode, 'spamAction' => $spamAction ), FALSE );
/* Security Questions */
if ( \IPS\Settings::i()->security_questions_enabled and in_array( \IPS\Settings::i()->security_questions_prompt, array( 'register', 'optional' ) ) )
@@ -550,7 +592,18 @@ class _register extends \IPS\Dispatcher\Controller
{
\IPS\Db::i()->replace( 'core_pfields_content', array_merge( array( 'member_id' => $member->member_id ), $profileFields ) );
}
/* Log that we gave consent for admin emails */
$member->logHistory( 'core', 'admin_mails', array( 'enabled' => (boolean) $member->allow_admin_mails ) );
/* Log that we gave consent for terms and privacy */
if ( \IPS\Settings::i()->privacy_type != 'none' )
{
$member->logHistory( 'core', 'terms_acceptance', array( 'type' => 'privacy' ) );
}
$member->logHistory( 'core', 'terms_acceptance', array( 'type' => 'terms' ) );
/* Handle validation */
$member->postRegistration();
@@ -593,7 +646,13 @@ class _register extends \IPS\Dispatcher\Controller
}
/* They're not validated but in what way? */
if( $validating['user_verified'] )
if ( $validating['reg_cancelled'] )
{
/* They are cancelled and will be deleted, haha, etc */
\IPS\Output::i()->error( 'reg_is_cancelled', '2C223/9', 403, '' );
}
else if ( $validating['user_verified'] )
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->notAdminValidated();
}
@@ -690,7 +749,7 @@ class _register extends \IPS\Dispatcher\Controller
/* Check we are an incomplete member */
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 ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ) );
}
elseif ( \IPS\Member::loggedIn()->real_name and \IPS\Member::loggedIn()->email )
{
@@ -711,6 +770,17 @@ class _register extends \IPS\Dispatcher\Controller
{
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'accountEmail' => TRUE ) ) );
}
if ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] )
{
\IPS\Member::loggedIn()->language()->words[ "reg_agreed_terms" ] = sprintf( \IPS\Member::loggedIn()->language()->get("reg_agreed_terms"), \IPS\Http\Url::internal( 'app=core&module=system&controller=terms', 'front', 'terms' ) );
$form->add( new \IPS\Helpers\Form\Checkbox( 'reg_agreed_terms', NULL, TRUE, array(), function( $val )
{
if ( !$val )
{
throw new \InvalidArgumentException('reg_not_agreed_terms');
}
} ) );
}
$form->addButton( 'cancel', 'link', \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=cancel', 'front', 'register' )->csrf() );
/* Handle the submission */
@@ -720,13 +790,16 @@ class _register extends \IPS\Dispatcher\Controller
{
\IPS\Member::loggedIn()->name = $values['username'];
}
$spamCode = NULL;
$spamAction = NULL;
if( isset( $values['email_address'] ) )
{
\IPS\Member::loggedIn()->email = $values['email_address'];
if( \IPS\Settings::i()->spam_service_enabled )
{
if( \IPS\Member::loggedIn()->spamService() == 4 )
$spamAction = \IPS\Member::loggedIn()->spamService( 'register', NULL, $spamCode );
if( $spamAction == 4 )
{
$action = \IPS\Settings::i()->spam_service_action_4;
@@ -740,9 +813,11 @@ class _register extends \IPS\Dispatcher\Controller
}
}
}
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] = FALSE;
/* Save */
\IPS\Member::loggedIn()->save();
\IPS\Member::loggedIn()->logHistory( 'core', 'account', array( 'type' => 'complete' ), FALSE );
/* Handle validation */
\IPS\Member::loggedIn()->postRegistration( ( isset( $values['email_address'] ) ) ? FALSE : TRUE );
@@ -751,7 +826,26 @@ class _register extends \IPS\Dispatcher\Controller
\IPS\Session::i()->setType( \IPS\Session\Front::LOGIN_TYPE_MEMBER );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Login::getRegistrationDestination( \IPS\Member::loggedIn() ) );
if ( isset( \IPS\Request::i()->ref ) and $ref = @base64_decode( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( $ref );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) or $ref->base !== 'front' )
{
throw new \Exception;
}
}
catch ( \Exception $e )
{
$ref = \IPS\Http\Url::internal('');
}
}
else
{
$ref = \IPS\Http\Url::internal('');
}
\IPS\Output::i()->redirect( $ref );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_complete_details');
@@ -784,7 +878,7 @@ class _register extends \IPS\Dispatcher\Controller
/* Build the form */
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Email( 'new_email', '', TRUE, array( 'accountEmail' => TRUE ) ) );
$form->add( new \IPS\Helpers\Form\Email( 'new_email', '', TRUE, array( 'accountEmail' => \IPS\Member::loggedIn() ) ) );
$captcha = new \IPS\Helpers\Form\Captcha;
if ( (string) $captcha !== '' )
{
@@ -794,17 +888,33 @@ class _register extends \IPS\Dispatcher\Controller
/* Handle submissions */
if ( $values = $form->values() )
{
/* Check spam defense whitelist */
if( \IPS\Settings::i()->spam_service_enabled AND ( isset( $pending['new_reg'] ) AND $pending['new_reg'] ) AND \IPS\Member::loggedIn()->spamDefenseWhitelist() )
{
/* We specifically say it's 'register' so that actions are still performed on the account */
$newEmailScore = \IPS\Member::loggedIn()->spamService( 'register', $values['new_email'] );
/* Is it a ban response? */
if( $newEmailScore == 4 )
{
\IPS\Output::i()->error( 'spam_denied_account', '2C223/A', 403, '' );
}
}
/* Change the email */
$oldEmail = \IPS\Member::loggedIn()->email;
foreach ( \IPS\Login::handlers( TRUE ) as $handler )
\IPS\Member::loggedIn()->email = $values['new_email'];
\IPS\Member::loggedIn()->save();
foreach ( \IPS\Login::methods() as $method )
{
try
{
$handler->changeEmail( \IPS\Member::loggedIn(), $oldEmail, $values['new_email'] );
$method->changeEmail( \IPS\Member::loggedIn(), $oldEmail, $values['new_email'] );
}
catch( \BadMethodCallException $e ) {}
}
\IPS\Member::loggedIn()->save();
\IPS\Member::loggedIn()->memberSync( 'onEmailChange', array( $values['new_email'], $oldEmail ) );
\IPS\Member::loggedIn()->logHistory( 'core', 'email_change', array( 'old' => $oldEmail, 'new' => $values['new_email'], 'by' => 'manual' ) );
/* Invalidate sessions except this one */
\IPS\Member::loggedIn()->invalidateSessionsAndLogins( \IPS\Session::i()->id );
@@ -879,16 +989,9 @@ class _register extends \IPS\Dispatcher\Controller
/* Member sync callback */
\IPS\Member::loggedIn()->memberSync( 'onLogout', array( \IPS\Http\Url::internal( '' ) ) );
/* Login handler callback */
foreach ( \IPS\Login::handlers( TRUE ) as $k => $handler )
{
try
{
$handler->logoutAccount( \IPS\Member::loggedIn(), \IPS\Http\Url::internal( '' ) );
}
catch( \BadMethodCallException $e ) {}
}
/* Flag user as having cancelled their registration */
\IPS\Db::i()->update( 'core_validating', array( 'reg_cancelled' => time() ), array( 'member_id=? AND new_reg=1', \IPS\Member::loggedIn()->member_id ) );
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ), 'reg_canceled' );
@@ -902,23 +1005,27 @@ class _register extends \IPS\Dispatcher\Controller
protected function reconfirm()
{
/* Generate form */
$form = new \IPS\Helpers\Form;
$form = new \IPS\Helpers\Form( 'reconfirm_checkbox', 'reconfirm_checkbox' );
if ( isset( \IPS\Request::i()->ref ) )
{
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
}
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Checkbox( 'reconfirm_checkbox', NULL, FALSE, array(), function( $val )
{
if ( !$val )
{
throw new \InvalidArgumentException('reg_not_agreed_terms');
}
} ) );
/* Handle submissions */
if ( $values = $form->values() )
{
/* Log that we gave consent */
if ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_privacy'] )
{
\IPS\Member::loggedIn()->logHistory( 'core', 'terms_acceptance', array( 'type' => 'privacy' ) );
}
if ( \IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] )
{
\IPS\Member::loggedIn()->logHistory( 'core', 'terms_acceptance', array( 'type' => 'terms' ) );
}
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_privacy'] = FALSE;
\IPS\Member::loggedIn()->members_bitoptions['must_reaccept_terms'] = FALSE;
\IPS\Member::loggedIn()->save();
File diff suppressed because it is too large. Load diff
@@ -31,10 +31,10 @@ class _twitter extends \IPS\Dispatcher\Controller
{
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' ) ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( 'ref', base64_encode( \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' ) ) ) );
}
$twitter = \IPS\Login::getHandler('Twitter');
$twitter = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth1\Twitter');
$promote = \IPS\core\Promote::getPromoter( 'Twitter' );
$url = \IPS\Http\Url::internal( 'app=core&module=system&controller=twitter' );
@@ -43,8 +43,7 @@ class _twitter extends \IPS\Dispatcher\Controller
/* 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');
$response = $twitter->requestToken( $url->setQueryString( 'csrf', \IPS\Session::i()->csrfKey ) );
\IPS\Output::i()->redirect( "https://api.twitter.com/oauth/authorize?force_login=1&oauth_token={$response['oauth_token']}" );
}
@@ -55,9 +54,7 @@ class _twitter extends \IPS\Dispatcher\Controller
}
/* 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();
$response = $twitter->exchangeToken( \IPS\Request::i()->oauth_verifier, \IPS\Request::i()->oauth_token );
/* Store the settings */
$promote->saveSettings( array(
@@ -65,17 +62,19 @@ class _twitter extends \IPS\Dispatcher\Controller
'owner' => \IPS\Member::loggedIn()->member_id,
'secret' => $response['oauth_token_secret'],
'token' => $response['oauth_token'],
'name' => $user['screen_name']
'name' => $response['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 );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'promote' )->promoteTwitterComplete( $response );
}
catch ( \Exception $e )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
\IPS\Log::log( $e, 'twitter_promote' );
\IPS\Output::i()->error( 'generic_error', '4C375/1', 403, $e->getMessage() );
}
}
}
@@ -49,6 +49,9 @@ class _unsubscribe extends \IPS\Dispatcher\Controller
$member->allow_admin_mails = 0;
$member->save();
/* Log it */
$member->logHistory( 'core', 'admin_mails', array( 'enabled' => FALSE ) );
/* And then show them a confirmation screen */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('unsubscribed');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->unsubscribed();
+12 -6
View File
@@ -81,7 +81,7 @@ class _vse extends \IPS\Dispatcher\Controller
/* VSE CSS */
if ( isset( $css['core']['front']['custom']['vse.css'] ) )
{
$functionName = "css_" . uniqid();
$functionName = "css_" . mt_rand();
\IPS\Theme::makeProcessFunction( \IPS\Theme::fixResourceTags( $css['core']['front']['custom']['vse.css']['css_content'], 'front' ), $functionName, '', FALSE, TRUE );
$vseCss = call_user_func( 'IPS\\Theme\\'. $functionName );
}
@@ -89,7 +89,7 @@ class _vse extends \IPS\Dispatcher\Controller
if ( isset( $css['core']['front']['custom']['custom.css'] ) )
{
/* Custom CSS */
$functionName = "css_" . uniqid();
$functionName = "css_" . mt_rand();
\IPS\Theme::makeProcessFunction( \IPS\Theme::fixResourceTags( $css['core']['front']['custom']['custom.css']['css_content'], 'front' ), $functionName, '', FALSE, TRUE );
$customCss = call_user_func( 'IPS\\Theme\\'. $functionName );
}
@@ -133,10 +133,16 @@ class _vse extends \IPS\Dispatcher\Controller
$options['options'] = $options;
break;
}
$field = new $class( "core_theme_setting_title_{$data['sc_id']}", $value, false, $options );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( $data['sc_title'], FALSE, array( 'escape' => true ) );
$form->add( $field );
if ( class_exists( $class ) )
{
$field = new $class( "core_theme_setting_title_{$data['sc_id']}", $value, false, $options );
$field->label = \IPS\Member::loggedIn()->language()->addToStack( $data['sc_title'], FALSE, array( 'escape' => true ) );
$form->add( $field );
}
else
{
\IPS\Log::log( 'VSE tried to load ' . $class . ' for theme setting ' . $key, 'vse_error' );
}
}
}
@@ -135,7 +135,7 @@ class _warnings extends \IPS\Content\Controller
{
\IPS\Output::i()->error( 'no_module_permission', '2C184/6', 403, '' );
}
/* Build the form */
$form = \IPS\core\Warnings\Warning::create();
$form->class = 'ipsForm_vertical';
@@ -165,7 +165,7 @@ class _warnings extends \IPS\Content\Controller
}
/**
* Axknowledge Warning
* Acknowledge Warning
*
* @return void
*/
@@ -262,7 +262,13 @@ class _warnings extends \IPS\Content\Controller
* @return void
*/
protected function reasonAjax()
{
{
/* Check permission */
if ( ! ( \IPS\Settings::i()->warn_on AND \IPS\Member::loggedIn()->modPermission('mod_see_warn') ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C135/9', 403, '' );
}
$remove = array(
'date' => NULL,
'time' => NULL,
@@ -351,6 +357,13 @@ class _warnings extends \IPS\Content\Controller
);
$member = \IPS\Member::load( \IPS\Request::i()->member );
/* Check permission */
if ( !( \IPS\Settings::i()->warn_on AND ( \IPS\Member::loggedIn()->modPermission('mod_see_warn') or ( \IPS\Settings::i()->warn_show_own and \IPS\Member::loggedIn()->member_id == $member->member_id ) ) ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2C135/9', 403, '' );
}
try
{
$action = \IPS\Db::i()->select( '*', 'core_members_warn_actions', array( 'wa_points<=?', ( $member->warn_level + \IPS\Request::i()->points ) ), 'wa_points DESC', 1 )->first();
@@ -68,7 +68,7 @@ class _widgets extends \IPS\Dispatcher\Controller
}
}
$block = \IPS\Widget::load( $appOrPlugin, $widget['key'], uniqid(), array(), $widget['restrict'], null );
$block = \IPS\Widget::load( $appOrPlugin, $widget['key'], mt_rand(), array(), $widget['restrict'], null );
$block->allowReuse = (boolean) $widget['allow_reuse'];
$block->menuStyle = $widget['menu_style'];
@@ -131,12 +131,20 @@ class _widgets extends \IPS\Dispatcher\Controller
}
}
}
catch ( \OutOfRangeException $e ) { }
catch ( \UnderflowException $e ) { }
}
if ( !isset( $widget ) )
{
$widget = \IPS\Widget::load( ( $key[0] == 'plugin' ) ? \IPS\Plugin::load( $key[1] ) : \IPS\Application::load( $key[1] ), $key[2], $key[3], array(), null, \IPS\Request::i()->orientation );
try
{
$widget = \IPS\Widget::load( ( $key[0] == 'plugin' ) ? \IPS\Plugin::load( $key[1] ) : \IPS\Application::load( $key[1] ), $key[2], $key[3], array(), null, \IPS\Request::i()->orientation );
}
catch( \OutOfRangeException $e )
{
$widget = '';
}
}
\IPS\Output::i()->sendOutput( (string) $widget );
@@ -217,6 +225,7 @@ class _widgets extends \IPS\Dispatcher\Controller
$blocks[ $k ]['configuration'] = $values;
\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\Widget::deleteCaches( $block['key'], ( isset( $block['app'] ) ) ? $block['app'] : NULL, ( isset( $block['plugin'] ) ) ? $block['plugin'] : NULL );
\IPS\Output::i()->json( 'OK' );
}
\IPS\Output::i()->output = $widget->configuration()->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'widgets', 'core' ) ), 'formTemplate' ), $widget );