Version 4.6.0
This commit is contained in:
1 parent
f79dcf067a
commit
517a5e1f70
2036 files changed
+110041
-26162
No files matched your search
@@ -60,6 +60,24 @@ class _directory extends \IPS\Dispatcher\Controller
|
||||
protected function manage()
|
||||
{
|
||||
$baseUrl = \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' );
|
||||
|
||||
/* 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\Session::i()->csrfCheck();
|
||||
\IPS\Request::i()->setCookie( 'clubs_view', \IPS\Request::i()->view, \IPS\DateTime::create()->add( new \DateInterval('P1Y' ) ) );
|
||||
$view = \IPS\Request::i()->view;
|
||||
|
||||
\IPS\Output::i()->redirect( $baseUrl );
|
||||
}
|
||||
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'];
|
||||
}
|
||||
}
|
||||
|
||||
/* All Clubs: Sort */
|
||||
$sortOption = \IPS\Settings::i()->clubs_default_sort;
|
||||
@@ -74,7 +92,7 @@ class _directory extends \IPS\Dispatcher\Controller
|
||||
$filters = array();
|
||||
$mineOnly = FALSE;
|
||||
$extraWhere = NULL;
|
||||
if ( isset( \IPS\Request::i()->filter ) and \IPS\Request::i()->filter === 'mine' )
|
||||
if ( isset( \IPS\Request::i()->filter ) and \IPS\Request::i()->filter === 'mine' AND \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$mineOnly = TRUE;
|
||||
$baseUrl = $baseUrl->setQueryString( 'filter', 'mine' );
|
||||
@@ -216,22 +234,7 @@ 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\Session::i()->csrfCheck();
|
||||
\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, $view );
|
||||
}
|
||||
@@ -391,6 +394,11 @@ class _directory extends \IPS\Dispatcher\Controller
|
||||
$club->save();
|
||||
}
|
||||
|
||||
if( $club->approved )
|
||||
{
|
||||
\IPS\Member::loggedIn()->achievementAction( 'core', 'NewClub', $club );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $club->url() );
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class _page extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '12345', 404 );
|
||||
\IPS\Output::i()->error( 'node_error', '2S410/4', 404, '' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sidebar['contextual'] = '';
|
||||
|
||||
@@ -527,8 +527,10 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Fetch them */
|
||||
$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 );
|
||||
|
||||
|
||||
$pagination = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->pagination( $baseUrl, ceil( $this->club->members( $statuses, NULL, $orderByClause, 4 ) / $perPage ), $activePage, $perPage );
|
||||
|
||||
|
||||
/* Display */
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -1112,9 +1114,17 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
/* If we're not a member of this club yet, send us back to the join form */
|
||||
if( $this->club->memberStatus( \IPS\Member::loggedIn() ) === NULL AND $referrer = \IPS\Request::i()->referrer() )
|
||||
if( $this->club->memberStatus( \IPS\Member::loggedIn() ) === NULL )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $referrer->setQueryString( 'rulesAcknowledged', 1 ), 'accepted' );
|
||||
if( $referrer = \IPS\Request::i()->referrer() )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $referrer->setQueryString( 'rulesAcknowledged', 1 ), 'accepted' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'rulesAcknowledged', 1 ), 'accepted' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->club->acknowledgeRules( \IPS\Member::loggedIn() );
|
||||
@@ -1150,10 +1160,16 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
|
||||
}
|
||||
|
||||
/* Are there rules that need to be acknowledged which we haven't acknowledged yet? */
|
||||
if( $this->club->rules_required AND !\IPS\Request::i()->rulesAcknowledged )
|
||||
if( $this->club->rules_required AND !$this->club->rulesAcknowledged() AND !\IPS\Request::i()->rulesAcknowledged )
|
||||
{
|
||||
$ref = \IPS\Request::i()->url()->addRef( \IPS\Request::i()->referrer() );
|
||||
\IPS\Output::i()->redirect( $this->club->url()->setQueryString( 'do', 'rules' )->addRef( $ref ) );
|
||||
$rulesUrl = $this->club->url()->setQueryString( 'do', 'rules' );
|
||||
|
||||
if( $referrer = \IPS\Request::i()->referrer() )
|
||||
{
|
||||
$rulesUrl = $rulesUrl->addRef( \IPS\Request::i()->url()->addRef( $referrer ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $rulesUrl );
|
||||
}
|
||||
|
||||
/* CSRF Check */
|
||||
@@ -1484,6 +1500,8 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
|
||||
$this->club->approved = TRUE;
|
||||
$this->club->save();
|
||||
|
||||
$this->club->owner->achievementAction( 'core', 'NewClub', $this->club );
|
||||
|
||||
\IPS\Output::i()->redirect( $this->club->url() );
|
||||
}
|
||||
|
||||
@@ -1515,7 +1533,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
$node = $class::load( \IPS\Request::i()->node );
|
||||
$node = $class::load( (int) \IPS\Request::i()->node );
|
||||
$club = $node->club();
|
||||
if ( !$club or $club->id !== $this->club->id )
|
||||
{
|
||||
@@ -1566,9 +1584,14 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Load */
|
||||
$class = \IPS\Request::i()->type;
|
||||
|
||||
if( !$class instanceof \IPS\Node\Model )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
try
|
||||
{
|
||||
$node = $class::load( \IPS\Request::i()->node );
|
||||
$node = $class::load( (int) \IPS\Request::i()->node );
|
||||
$club = $node->club();
|
||||
if ( !$club or $club->id !== $this->club->id )
|
||||
{
|
||||
|
||||
@@ -168,6 +168,7 @@ class _popular extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
);
|
||||
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( "app=core&module=discover&controller=popular&tab=history", 'front', 'leaderboard_history' );
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $table ), 200, 'text/html' );
|
||||
|
||||
@@ -385,15 +385,20 @@ class _streams extends \IPS\Dispatcher\Controller
|
||||
$view = 'expanded';
|
||||
$streamID = ( \IPS\Request::i()->id ) ? \IPS\Request::i()->id : 'all';
|
||||
|
||||
if ( isset( \IPS\Request::i()->cookie['stream_view_' . $streamID] ) )
|
||||
{
|
||||
$view = \IPS\Request::i()->cookie['stream_view_' . $streamID];
|
||||
}
|
||||
elseif( isset( \IPS\Request::i()->view ) AND \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) )
|
||||
if( isset( \IPS\Request::i()->view ) AND \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) )
|
||||
{
|
||||
$view = \IPS\Request::i()->view;
|
||||
|
||||
\IPS\Request::i()->setCookie( 'stream_view_' . $streamID, \IPS\Request::i()->view, \IPS\DateTime::create()->add( new \DateInterval( 'P1Y' ) ) );
|
||||
|
||||
if( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $stream->url() );
|
||||
}
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->cookie['stream_view_' . $streamID] ) )
|
||||
{
|
||||
$view = \IPS\Request::i()->cookie['stream_view_' . $streamID];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -516,7 +521,7 @@ class _streams extends \IPS\Dispatcher\Controller
|
||||
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->class = 'ipsForm_vertical';
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'stream_title', $stream->title ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'stream_title', $stream->title, NULL, array( 'maxLength' => 255 ) ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex, follow';
|
||||
}
|
||||
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string)$this->member->url();
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) $this->member->url();
|
||||
|
||||
\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' ) );
|
||||
@@ -114,7 +114,7 @@ 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 && !isset( \IPS\Request::i()->getUploader ) )
|
||||
if ( \IPS\Request::i()->status && \IPS\Request::i()->isAjax() && \IPS\Request::i()->commentPage && $canAccessStatuses && !isset( \IPS\Request::i()->getUploader ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -378,6 +378,9 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* Get followers */
|
||||
$followers = $this->member->followers( ( \IPS\Member::loggedIn()->isAdmin() OR \IPS\Member::loggedIn()->member_id === $this->member->member_id ) ? \IPS\Member::FOLLOW_PUBLIC + \IPS\Member::FOLLOW_ANONYMOUS : \IPS\Member::FOLLOW_PUBLIC, array( 'immediate', 'daily', 'weekly', 'none' ), NULL, array( 0, 12 ) );
|
||||
|
||||
/* Get solutions */
|
||||
$solutions = \IPS\Db::i()->select( 'COUNT(*)', 'core_solved_index', array( 'member_id=?', $this->member->member_id ) )->first();
|
||||
|
||||
/* Update online location */
|
||||
$module = \IPS\Application\Module::get( 'core', 'members', 'front' )->permissions();
|
||||
@@ -398,15 +401,15 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
'name' => $this->member->name,
|
||||
'primaryImageOfPage' => array(
|
||||
'@type' => "ImageObject",
|
||||
'contentUrl' => (string) $this->member->get_photo(),
|
||||
'contentUrl' => (string) $this->member->get_photo( TRUE, TRUE ),
|
||||
'representativeOfPage' => true,
|
||||
'thumbnail' => array(
|
||||
'@type' => "ImageObject",
|
||||
'contentUrl' => (string) $this->member->get_photo( TRUE ),
|
||||
'contentUrl' => (string) $this->member->get_photo( TRUE, TRUE ),
|
||||
)
|
||||
),
|
||||
'thumbnailUrl' => (string) $this->member->get_photo( TRUE ),
|
||||
'image' => (string) $this->member->get_photo(),
|
||||
'thumbnailUrl' => (string) $this->member->get_photo( TRUE, TRUE ),
|
||||
'image' => (string) $this->member->get_photo( FALSE, TRUE ),
|
||||
'relatedLink' => (string) \IPS\Http\Url::internal( "app=core&module=members&controller=profile&do=content&id={$this->member->member_id}", "front", "profile_content", array( $this->member->members_seo_name ) ),
|
||||
'dateCreated' => $this->member->joined->format( \IPS\DateTime::ISO8601 ),
|
||||
'interactionStatistic' => array(
|
||||
@@ -425,7 +428,7 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
|
||||
/* 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 );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->profile( $this->member, $mainContent, $visitors, $sidebarFields, $followers, $addWarningUrl, $solutions );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -620,6 +623,33 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userContent( $this->member, $types, $currentAppModule, $currentType, (string) $output );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show badges
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function badges()
|
||||
{
|
||||
if( !$this->member->canHaveAchievements() || !\IPS\core\Achievements\Badge::show() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2C138/S', 403, '' );
|
||||
}
|
||||
|
||||
$percentage = NULL;
|
||||
if ( $this->member->achievements_points )
|
||||
{
|
||||
$percentage = \IPS\Db::i()->select( "CEIL( 100 * COUNT( IF( achievements_points > " . ( $this->member->achievements_points - 1 ) . ", 1, NULL ) ) / COUNT(*) ) as percentage", 'core_members', ['achievements_points > 0'] )->first();
|
||||
|
||||
if ( $percentage > 51 )
|
||||
{
|
||||
$percentage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'members_badges', FALSE, array( 'sprintf' => array( $this->member->name ) ) );;
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userBadgeOverview( $this->member, $percentage );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Reputation
|
||||
@@ -992,20 +1022,14 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
/* The basics */
|
||||
$form->addTab( 'profile_edit_basic_tab', 'user');
|
||||
|
||||
$canChangeTitle = ( \IPS\Settings::i()->post_titlechange != -1 and ( isset( \IPS\Settings::i()->post_titlechange ) and $this->member->member_posts >= \IPS\Settings::i()->post_titlechange ) );
|
||||
$canChangeBirthday = ( \IPS\Settings::i()->profile_birthday_type !== 'none' );
|
||||
$canEnableDisableStatuses = ( \IPS\Settings::i()->profile_comments and $this->member->canAccessModule( \IPS\Application\Module::get( 'core', 'status' ) ) AND !$this->member->members_bitoptions['bw_no_status_update'] );
|
||||
|
||||
if( $canChangeTitle or $canChangeBirthday or $canEnableDisableStatuses )
|
||||
if( $canChangeBirthday or $canEnableDisableStatuses )
|
||||
{
|
||||
$form->addHeader( 'profile_edit_basic_header' );
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->post_titlechange != -1 and ( isset( \IPS\Settings::i()->post_titlechange ) and $this->member->member_posts >= \IPS\Settings::i()->post_titlechange ) )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'member_title', $this->member->member_title, FALSE, array( 'maxLength' => 64 ) ) );
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->profile_birthday_type !== 'none' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Custom( 'bday', array( 'year' => $this->member->bday_year, 'month' => $this->member->bday_month, 'day' => $this->member->bday_day ), FALSE, array( 'getHtml' => function( $element )
|
||||
@@ -1107,11 +1131,6 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
*/
|
||||
protected function _saveMember( $form, array $values )
|
||||
{
|
||||
if( ( \IPS\Settings::i()->post_titlechange == -1 or ( isset( \IPS\Settings::i()->post_titlechange ) and $this->member->member_posts >= \IPS\Settings::i()->post_titlechange ) ) AND isset( $values['member_title'] ) )
|
||||
{
|
||||
$this->member->member_title = $values['member_title'];
|
||||
}
|
||||
|
||||
if( isset( $values['bday'] ) )
|
||||
{
|
||||
if( $values['bday'] and ( ( $values['bday']['day'] and !$values['bday']['month'] ) or ( $values['bday']['month'] and !$values['bday']['day'] ) ) )
|
||||
@@ -1909,4 +1928,262 @@ class _profile extends \IPS\Helpers\CoverPhoto\Controller
|
||||
\IPS\Request::i()->action = 'delete';
|
||||
return $this->moderate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Solutions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function solutions()
|
||||
{
|
||||
/* Get the different types */
|
||||
$types = array();
|
||||
$hasCallback = array();
|
||||
foreach ( \IPS\Content::routedClasses( TRUE, FALSE, TRUE ) as $class )
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'profile.css', $class::$application ) );
|
||||
|
||||
if ( \IPS\IPS::classUsesTrait( $class, 'IPS\Content\Solvable' ) )
|
||||
{
|
||||
$types[ mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ) ] = $class::$commentClass;
|
||||
}
|
||||
}
|
||||
|
||||
/* What type are we looking at? */
|
||||
$currentType = NULL;
|
||||
if ( isset( \IPS\Request::i()->type ) AND array_key_exists( \IPS\Request::i()->type, $types ) )
|
||||
{
|
||||
$currentType = \IPS\Request::i()->type;
|
||||
}
|
||||
|
||||
if ( $currentType === NULL )
|
||||
{
|
||||
foreach ( $types as $key => $type )
|
||||
{
|
||||
$currentType = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$currentClass = $types[ $currentType ];
|
||||
|
||||
/* Build Output */
|
||||
$url = \IPS\Http\Url::internal( "app=core&module=members&controller=profile&id={$this->member->member_id}&do=reputation&type={$currentType}", 'front', 'profile_reputation', array( $this->member->members_seo_name ) );
|
||||
|
||||
$table = new \IPS\Helpers\Table\Content( $currentClass, $url, NULL, NULL, \IPS\Content\Hideable::FILTER_AUTOMATIC, 'read', FALSE );
|
||||
$table->joinContainer = TRUE;
|
||||
$table->sortOptions = array( 'solved_date' );
|
||||
$table->sortBy = 'solved_date';
|
||||
$table->joins = array(
|
||||
array(
|
||||
'select' => "core_solved_index.id AS solved_id, core_solved_index.solved_date",
|
||||
'from' => 'core_solved_index',
|
||||
'where' => array( "core_solved_index.comment_id=" . $currentClass::$databaseTable . "." . $currentClass::$databasePrefix . $currentClass::$databaseColumnId . " AND core_solved_index.member_id=? AND core_solved_index.comment_class=?", $this->member->member_id, $currentClass ),
|
||||
'type' => 'INNER'
|
||||
)
|
||||
);
|
||||
|
||||
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'profile', 'core' ), 'userSolutionsTable' );
|
||||
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'profile', 'core' ), 'userSolutionsRows' );
|
||||
$table->showAdvancedSearch = FALSE;
|
||||
|
||||
/* Display */
|
||||
if ( \IPS\Request::i()->isAjax() && \IPS\Request::i()->change_section )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( (string) $table );
|
||||
}
|
||||
else
|
||||
{
|
||||
\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_solutions', FALSE, array('sprintf' => $this->member->name ) ), $table->page ) ) ) : \IPS\Member::loggedIn()->language()->addToStack( 'member_solutions', FALSE, array('sprintf' => $this->member->name ) );
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'profile' )->userSolutions( $this->member, $types, $currentType, (string) $table, $this->member->solutionCount() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recognize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function recognize()
|
||||
{
|
||||
$class = \IPS\Request::i()->content_class;
|
||||
$id = \IPS\Request::i()->content_id;
|
||||
|
||||
/* Does this content exist? */
|
||||
try
|
||||
{
|
||||
$content = $class::loadAndCheckPerms( $id );
|
||||
|
||||
/* Can we view this item? */
|
||||
if ( ! $content->canView() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/O', 403, '' );
|
||||
}
|
||||
|
||||
/* Make sure there's no shenanigans */
|
||||
if ( $this->member->member_id != $content->author()->member_id )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/P', 403, '' );
|
||||
}
|
||||
|
||||
/* Can we recognize this ? */
|
||||
if ( ! $content->canRecognize() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/Q', 403, '' );
|
||||
}
|
||||
|
||||
/* Now build the form */
|
||||
$form = new \IPS\Helpers\Form( 'badge_form', 'save' );
|
||||
$form->class = 'ipsForm_vertical ipsForm_fullWidth';
|
||||
|
||||
/* What has been awarded so far today? */
|
||||
$message = NULL;
|
||||
if ( $this->member->todaysRecognizePoints() and $this->member->todaysRecognizeBadges() )
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack('recognize_points_so_far_both', NULL, [
|
||||
'sprintf' => [
|
||||
$this->member->name,
|
||||
\IPS\Member::loggedIn()->language()->addToStack('recognize_points_pluralize', NULL, [ 'sprintf' => [ $this->member->todaysRecognizePoints() ], 'pluralize' => [ $this->member->todaysRecognizePoints() ] ]),
|
||||
\IPS\Member::loggedIn()->language()->addToStack('recognize_badges_pluralize', NULL, [ 'sprintf' => [ $this->member->todaysRecognizeBadges() ], 'pluralize' => [ $this->member->todaysRecognizeBadges() ] ]),
|
||||
] ] );
|
||||
}
|
||||
else if ( $this->member->todaysRecognizePoints() )
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack('recognize_points_so_far_single', NULL, [
|
||||
'sprintf' => [
|
||||
$this->member->name,
|
||||
\IPS\Member::loggedIn()->language()->addToStack('recognize_points_pluralize', NULL, [ 'sprintf' => [ $this->member->todaysRecognizePoints() ], 'pluralize' => [ $this->member->todaysRecognizePoints() ] ])
|
||||
] ] );
|
||||
}
|
||||
else if ( $this->member->todaysRecognizeBadges() )
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack('recognize_points_so_far_single', NULL, [
|
||||
'sprintf' => [
|
||||
$this->member->name,
|
||||
\IPS\Member::loggedIn()->language()->addToStack('recognize_points_pluralize', NULL, [ 'sprintf' => [ $this->member->todaysRecognizeBadges() ], 'pluralize' => [ $this->member->todaysRecognizeBadges() ] ])
|
||||
] ] );
|
||||
}
|
||||
|
||||
$maxPoints = NULL;
|
||||
$disabled = FALSE;
|
||||
if ( \IPS\Settings::i()->achievements_recognize_max_per_user_day != -1 )
|
||||
{
|
||||
$maxPoints = \IPS\Settings::i()->achievements_recognize_max_per_user_day - $this->member->todaysRecognizePoints();
|
||||
if ( $maxPoints > 0 )
|
||||
{
|
||||
$message .= \IPS\Member::loggedIn()->language()->addToStack( 'recognize_points_so_far_limit', NULL, ['sprintf' => [$this->member->name, $maxPoints]] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$message .= \IPS\Member::loggedIn()->language()->addToStack( 'recognize_points_so_far_limit_none', NULL, ['sprintf' => [$this->member->name]] );
|
||||
$disabled = TRUE;
|
||||
}
|
||||
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_recognize_content_no_point_limit') )
|
||||
{
|
||||
$message .= \IPS\Member::loggedIn()->language()->addToStack('recognize_points_so_far_limit_but_none');
|
||||
$maxPoints = NULL;
|
||||
$disabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $message )
|
||||
{
|
||||
$form->addMessage( $message, 'ipsMessage ipsMessage_info' );
|
||||
}
|
||||
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_recognize_content') == '*' OR \in_array( 'badges', \IPS\Member::loggedIn()->modPermission('can_recognize_content_options') ) )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Node( 'recognize_badge', NULL, FALSE, [
|
||||
'class' => '\IPS\core\Achievements\Badge',
|
||||
'permissionCheck' => function ( $node ) {
|
||||
return $node->manually_awarded;
|
||||
},
|
||||
'url' => $content->author()->url()->setQueryString( array('do' => 'recognize', 'content_class' => $class, 'content_id' => $id) )
|
||||
] ) );
|
||||
}
|
||||
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_recognize_content') == '*' OR \in_array( 'points', \IPS\Member::loggedIn()->modPermission('can_recognize_content_options') ) )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'recognize_points', 0, FALSE, [ 'disabled' => $disabled, 'min' => 0, 'max' => $maxPoints ] ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'recognize_message', NULL, FALSE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'recognize_public', TRUE, FALSE ) );
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['recognize_message_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'recognize_message__desc', NULL, [ 'sprintf' => [ $content->author()->name ] ] );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if ( ! $values['recognize_badge'] and ! $values['recognize_points'] )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack('recognize_form_empty');
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\core\Achievements\Recognize::add( $content, $this->member, $values['recognize_points'], $values['recognize_badge'], $values['recognize_message'], \IPS\Member::loggedIn(), $values['recognize_public'] );
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\Member::loggedIn()->language()->addToStack( 'recognize_submit_success' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $content->url(), 'recognize_submit_success' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('recognize_author', NULL, [ 'sprintf' => [ $content->author()->name ] ] );
|
||||
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/R', 403, '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recognize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function unrecognize()
|
||||
{
|
||||
$class = \IPS\Request::i()->content_class;
|
||||
$id = \IPS\Request::i()->content_id;
|
||||
|
||||
/* Does this content exist? */
|
||||
try
|
||||
{
|
||||
$content = $class::loadAndCheckPerms( $id );
|
||||
|
||||
/* Can we view this item? */
|
||||
if ( ! $content->canView() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/S', 403, '' );
|
||||
}
|
||||
|
||||
/* Can we recognize this ? */
|
||||
if ( ! $content->canRemoveRecognize() )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/T', 403, '' );
|
||||
}
|
||||
|
||||
$content->removeRecognize();
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C138/Ug', 403, '' );
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\Member::loggedIn()->language()->addToStack( 'recognize_removed_success' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( $content->url(), 'recognize_removed_success' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,7 +468,15 @@ class _messenger extends \IPS\Content\Controller
|
||||
$form->class = 'ipsForm_vertical';
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('compose_new');
|
||||
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('messaging')->submitForm( \IPS\Member::loggedIn()->language()->addToStack('compose_new'), $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -95,6 +95,7 @@ class _online extends \IPS\Dispatcher\Controller
|
||||
$table->sortDirection = $table->sortDirection ?: 'desc';
|
||||
|
||||
/* Display */
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( 'app=core&module=online&controller=online', 'front', 'online' );
|
||||
\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, $table->count );
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ class _promote extends \IPS\Dispatcher\Controller
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
$object = $class::load( $id );
|
||||
$object = $class::load( (int) $id );
|
||||
}
|
||||
catch ( \Exception $ex )
|
||||
{
|
||||
@@ -563,9 +563,11 @@ class _promote extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$isNew = FALSE;
|
||||
if ( ! $promote )
|
||||
{
|
||||
$isNew = TRUE;
|
||||
$promote = new \IPS\core\Promote;
|
||||
$promote->class = $class;
|
||||
$promote->class_id = $id;
|
||||
@@ -584,8 +586,23 @@ class _promote extends \IPS\Dispatcher\Controller
|
||||
$promote->failed = 0; # Reset the failed flag if we're re-promoting
|
||||
$promote->sent = 0;
|
||||
$promote->form_data = $processedForms;
|
||||
|
||||
if ( is_subclass_of( $class, 'IPS\Content' ) )
|
||||
{
|
||||
$promote->author_id = $object->author()->member_id;
|
||||
}
|
||||
|
||||
$promote->save();
|
||||
|
||||
if ( $isNew )
|
||||
{
|
||||
/* Points */
|
||||
$promote->author()->achievementAction( 'core', 'ContentPromotion', [
|
||||
'content' => $promote->object(),
|
||||
'promotype' => 'promote'
|
||||
] );
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->promote_id ) )
|
||||
{
|
||||
/* Redirect back to the list */
|
||||
|
||||
@@ -22,13 +22,36 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _search extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Amount of time to cache search result in browser/CDN
|
||||
*/
|
||||
protected $_cacheTimeout = 30 * 60;
|
||||
|
||||
/**
|
||||
* Check if this was a cached result we should just return a 304 against
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _checkCached()
|
||||
{
|
||||
/* Check whether a 304 Not modified response is appropriate */
|
||||
if( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) AND ( new \IPS\DateTime( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )->getTimestamp() > ( time() - $this->_cacheTimeout ) )
|
||||
{
|
||||
header('HTTP/1.1 304 Not Modified' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
{
|
||||
/* Make sure this isn't a cached result we should just honor */
|
||||
$this->_checkCached();
|
||||
|
||||
/* Init stuff for the output */
|
||||
\IPS\Output::i()->sidebar['enabled'] = FALSE;
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/streams.css' ) );
|
||||
@@ -392,7 +415,7 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
$item = $class::loadAndCheckPerms( \IPS\Request::i()->item );
|
||||
$item = $class::loadAndCheckPerms( (int) \IPS\Request::i()->item );
|
||||
$query->filterByContent( array( \IPS\Content\Search\ContentFilter::init( $class )->onlyInItems( array( \IPS\Request::i()->item ) ) ) );
|
||||
$baseUrl = $baseUrl->setQueryString( 'item', \intval( \IPS\Request::i()->item ) );
|
||||
$titleConditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'search_blurb_in', FALSE, array( 'sprintf' => array( $item->mapped('title') ) ) );
|
||||
@@ -725,13 +748,26 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
/* Search tracking, only if there's a term for a non-member search and we're on the first page */
|
||||
if( \IPS\Request::i()->q AND $page == 1 )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_statistics', array(
|
||||
'type' => 'search',
|
||||
'time' => time(),
|
||||
'value_4' => \IPS\Request::i()->q,
|
||||
'value_2' => $count,
|
||||
'extra_data' => md5( \IPS\Member::loggedIn()->email . \IPS\Member::loggedIn()->joined ) // Intentionally anonymized
|
||||
) );
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_statistics', array(
|
||||
'type' => 'search',
|
||||
'time' => time(),
|
||||
'value_4' => mb_substr( \IPS\Request::i()->q, 0, 255 ), // Some search queries can be unnecessarily long
|
||||
'value_2' => $count,
|
||||
'extra_data' => md5( \IPS\Member::loggedIn()->email . \IPS\Member::loggedIn()->joined ) // Intentionally anonymized
|
||||
) );
|
||||
}
|
||||
catch( \IPS\Db\Exception $e ) {}
|
||||
}
|
||||
|
||||
/* Enable caching for the search results request */
|
||||
if ( !\IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$httpHeaders = array( 'Expires' => \IPS\DateTime::create()->add( new \DateInterval( 'PT3M' ) )->rfc1123(),
|
||||
'Cache-Control' => "max-age=" . $this->_cacheTimeout . ", s-maxage=" . $this->_cacheTimeout . ", public, stale-if-error, stale-while-revalidate" );
|
||||
|
||||
\IPS\Output::i()->httpHeaders += $httpHeaders;
|
||||
}
|
||||
|
||||
/* Display results */
|
||||
@@ -747,11 +783,6 @@ class _search extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$httpHeaders = array( 'Expires' => \IPS\DateTime::create()->add( new \DateInterval( 'PT3M' ) )->rfc1123() ,
|
||||
'Cache-Control' => "max-age=" . 30 * 60 . ", private" );
|
||||
|
||||
\IPS\Output::i()->httpHeaders += $httpHeaders;
|
||||
|
||||
\IPS\Output::i()->title = $title;
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'search' )->search( $this->_splitTermsForDisplay(), $title, $results, $pagination, $baseUrl, $types, $this->_form()->customTemplate( array( \IPS\Theme::i()->getTemplate( 'search' ), 'filters' ), $baseUrl, $count ), $count );
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class _directory extends \IPS\Dispatcher\Controller
|
||||
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'leader_custom_name', ( \IPS\Member::loggedIn()->language()->checkKeyExists("core_staff_directory_name_{$user->id}") ) ? \IPS\Member::loggedIn()->language()->get("core_staff_directory_name_{$user->id}") : \IPS\Member::loggedIn()->name, FALSE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'leader_custom_title', ( \IPS\Member::loggedIn()->language()->checkKeyExists("core_staff_directory_title_{$user->id}") ) ? \IPS\Member::loggedIn()->language()->get("core_staff_directory_title_{$user->id}") : \IPS\Member::loggedIn()->member_title, FALSE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'leader_custom_title', ( \IPS\Member::loggedIn()->language()->checkKeyExists("core_staff_directory_title_{$user->id}") ) ? \IPS\Member::loggedIn()->language()->get("core_staff_directory_title_{$user->id}") : '', FALSE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'leader_custom_bio', \IPS\Member::loggedIn()->language()->addToStack("core_staff_directory_bio_{$user->id}"), FALSE, array(
|
||||
'app' => 'core',
|
||||
'key' => 'Staffdirectory',
|
||||
|
||||
@@ -35,29 +35,39 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
|
||||
$where = array( "name LIKE CONCAT(?, '%')" );
|
||||
$binds = array( $input );
|
||||
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' )
|
||||
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' OR ( \IPS\Member::loggedIn()->modPermission('can_see_emails') AND \IPS\Request::i()->type == 'mod' ) )
|
||||
{
|
||||
$where[] = "email LIKE CONCAT(?, '%')";
|
||||
$binds[] = $input;
|
||||
|
||||
}
|
||||
|
||||
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' )
|
||||
{
|
||||
if ( \is_numeric( \IPS\Request::i()->input ) )
|
||||
{
|
||||
$where[] = "member_id=?";
|
||||
$binds[] = \intval( \IPS\Request::i()->input );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Build the array item for this member after constructing a record */
|
||||
/* The value should be just the name so that it's inserted into the input properly, but for display, we wrap it in the group *fix */
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_members', array_merge( array( implode( ' OR ', $where ) ), $binds ), 'LENGTH(name) ASC', array( 0, 20 ) ) as $row )
|
||||
{
|
||||
$member = \IPS\Member::constructFromData( $row );
|
||||
|
||||
|
||||
$extra = \IPS\Dispatcher::i()->controllerLocation == 'admin' ? htmlspecialchars( $member->email, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) : $member->groupName;
|
||||
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_see_emails') AND \IPS\Request::i()->type == 'mod' )
|
||||
{
|
||||
$extra = htmlspecialchars( $member->email, ENT_DISALLOWED | ENT_QUOTES, 'UTF-8', FALSE ) . '<br>' . $member->groupName;
|
||||
}
|
||||
|
||||
$results[] = array(
|
||||
'id' => $member->member_id,
|
||||
'value' => $member->name,
|
||||
'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,
|
||||
'extra' => $extra,
|
||||
'photo' => (string) $member->photo,
|
||||
);
|
||||
}
|
||||
@@ -256,77 +266,6 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->json( $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns boolean in json indicating whether the supplied email already exists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function emailExists()
|
||||
{
|
||||
$result = array( 'result' => 'ok' );
|
||||
|
||||
/* The value comes urlencoded so we need to decode so length is correct (and not using a percent-encoded value) */
|
||||
$email = urldecode( \IPS\Request::i()->input );
|
||||
|
||||
/* Check is valid */
|
||||
if ( !$email )
|
||||
{
|
||||
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_required') );
|
||||
}
|
||||
elseif ( filter_var( $email, FILTER_VALIDATE_EMAIL ) === FALSE )
|
||||
{
|
||||
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_bad_value') );
|
||||
}
|
||||
|
||||
/* Check if it exists */
|
||||
else if ( $error = \IPS\Login::emailIsInUse( $email ) )
|
||||
{
|
||||
if ( \IPS\Member::loggedIn()->isAdmin() )
|
||||
{
|
||||
$result = array( 'result' => 'fail', 'message' => $error );
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('member_email_exists') );
|
||||
}
|
||||
}
|
||||
|
||||
/* Check it's not banned */
|
||||
if ( $result == array( 'result' => 'ok' ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( 'ban_content', 'core_banfilters', array("ban_type=?", 'email') ) as $bannedEmail )
|
||||
{
|
||||
if( preg_match( '/^' . str_replace( '\*', '.*', preg_quote( $bannedEmail, '/' ) ) . '$/i', $email ) )
|
||||
{
|
||||
$result = array( 'result' => 'fail', 'message' => \IPS\Member::loggedIn()->language()->addToStack('form_email_banned') );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check it's an allowed domain */
|
||||
if ( \IPS\Settings::i()->allowed_reg_email !== '' AND $allowedEmailDomains = explode( ',', \IPS\Settings::i()->allowed_reg_email ) )
|
||||
{
|
||||
$matched = FALSE;
|
||||
foreach ( $allowedEmailDomains AS $domain )
|
||||
{
|
||||
if( \mb_stripos( $email, "@" . $domain ) !== FALSE )
|
||||
{
|
||||
$matched = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( \count( $allowedEmailDomains ) AND !$matched )
|
||||
{
|
||||
$result = array( 'result' => 'fail', 'message' => $email );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
\IPS\Output::i()->json( $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get state/region list for country
|
||||
*
|
||||
@@ -396,6 +335,7 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'block_topContributors' );
|
||||
\IPS\Output::i()->output = $output;
|
||||
}
|
||||
@@ -410,6 +350,11 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/* How many? */
|
||||
$limit = \intval( ( isset( \IPS\Request::i()->limit ) and \IPS\Request::i()->limit <= 25 ) ? \IPS\Request::i()->limit : 5 );
|
||||
|
||||
if( $limit < 0 )
|
||||
{
|
||||
$limit = 5;
|
||||
}
|
||||
|
||||
/* What timeframe? */
|
||||
$where = array( array( 'member_id > 0' ) );
|
||||
@@ -454,6 +399,7 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'block_mostSolved' );
|
||||
\IPS\Output::i()->output = $output;
|
||||
}
|
||||
@@ -472,6 +418,7 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
|
||||
$preview = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->navBar( TRUE );
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'system/menumanager.css', 'core', 'admin' ) );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'applications', 'core', 'admin' )->menuPreviewWrapper( $preview ) );
|
||||
}
|
||||
@@ -608,7 +555,8 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$mysqlTimezone = "GMT" . ( ( $matches[2] == 0 ) ? '' : ( ( $matches[1] ?: '+' ) . \intval( $matches[2] ) ) );
|
||||
}
|
||||
|
||||
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->chartTimezoneInfo( $mysqlTimezone );
|
||||
}
|
||||
|
||||
@@ -626,7 +574,16 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
\IPS\core\AdminNotification::dismissNotification( \IPS\Request::i()->id );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( array( 'status' => 'OK' ) );
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'status' => 'OK' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$ref = \IPS\Request::i()->referrer();
|
||||
|
||||
\IPS\Output::i()->redirect( $ref ?? \IPS\Http\Url::internal( '' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -650,7 +607,7 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
|
||||
try
|
||||
{
|
||||
$container = $containerClass::load( \IPS\Request::i()->container );
|
||||
$container = $containerClass::load( (int) \IPS\Request::i()->container );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
@@ -695,4 +652,19 @@ class _ajax extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Output::i()->json( $results );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current CSRF token
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCsrfKey(): ?string
|
||||
{
|
||||
if ( ! \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Output::i()->json( [ 'key' => \IPS\Session::i()->csrfKey ] );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ class _announcement extends \IPS\Content\Controller
|
||||
}
|
||||
|
||||
/* Make sure this is a local URL */
|
||||
if( !$url->isInternal )
|
||||
if( !( $url instanceof \IPS\Http\Url\Internal ) )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'status' => 'not_local' ) );
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class _attachments extends \IPS\Dispatcher\Controller
|
||||
|
||||
/* Build Table */
|
||||
$table = new \IPS\core\Attachments\Table( 'core_attachments', \IPS\Http\Url::internal( 'app=core&module=system&controller=attachments', 'front', 'attachments' ), array( array( 'attach_member_id=?', \IPS\Member::loggedIn()->member_id ) ) );
|
||||
$table->include = array( 'attach_id', 'attach_location', 'attach_date', 'attach_file', 'attach_filesize', 'attach_is_image', 'attach_content', 'attach_hits' );
|
||||
$table->include = array( 'attach_id', 'attach_location', 'attach_date', 'attach_file', 'attach_filesize', 'attach_is_image', 'attach_content', 'attach_hits', 'attach_security_key' );
|
||||
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate('myAttachments'), 'rows' );
|
||||
$table->joins = array();
|
||||
|
||||
|
||||
@@ -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( mt_rand() ), \IPS\Request::i()->lang ?: '' );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->code( htmlentities( \IPS\Request::i()->val, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8' ), \IPS\Request::i()->editorId, md5( mt_rand() ), \IPS\Request::i()->lang ?: '' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,11 +62,20 @@ class _editor extends \IPS\Dispatcher\Controller
|
||||
protected function image()
|
||||
{
|
||||
$maxImageDims = \IPS\Settings::i()->attachment_image_size ? explode( 'x', \IPS\Settings::i()->attachment_image_size ) : array( 1000, 750 );
|
||||
$maxWidth = ( \IPS\Request::i()->actualWidth < $maxImageDims[0] ) ? \IPS\Request::i()->actualWidth : $maxImageDims[0];
|
||||
$maxHeight = ( \IPS\Request::i()->actualHeight < $maxImageDims[1] ) ? \IPS\Request::i()->actualHeight : $maxImageDims[1];
|
||||
$ratioH = round( \IPS\Request::i()->height / \IPS\Request::i()->width, 2 );
|
||||
$ratioW = round( \IPS\Request::i()->width / \IPS\Request::i()->height, 2 );
|
||||
|
||||
if( \intval( $maxImageDims[0] ) === 0 && \intval( $maxImageDims[1] ) === 0 )
|
||||
{
|
||||
$maxWidth = \IPS\Request::i()->actualWidth;
|
||||
$maxHeight = \IPS\Request::i()->actualHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
$maxWidth = ( \IPS\Request::i()->actualWidth < $maxImageDims[0] ) ? \IPS\Request::i()->actualWidth : $maxImageDims[0];
|
||||
$maxHeight = ( \IPS\Request::i()->actualHeight < $maxImageDims[1] ) ? \IPS\Request::i()->actualHeight : $maxImageDims[1];
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->width > $maxWidth )
|
||||
{
|
||||
\IPS\Request::i()->width = $maxWidth;
|
||||
@@ -115,13 +124,9 @@ class _editor extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
if( \IPS\Request::i()->image )
|
||||
{
|
||||
\IPS\Text\Parser::isAllowedImageUrl( $url );
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->image and \IPS\Request::i()->width and \IPS\Request::i()->height )
|
||||
{
|
||||
\IPS\Text\Parser::isAllowedImageUrl( $url );
|
||||
$embed = \IPS\Text\Parser::imageEmbed( $url, \intval( \IPS\Request::i()->width ), \intval( \IPS\Request::i()->height ) );
|
||||
}
|
||||
else
|
||||
@@ -176,7 +181,7 @@ class _editor extends \IPS\Dispatcher\Controller
|
||||
\IPS\Log::debug( $url . "\n" . $result['errorMessage'], 'embed_failure' );
|
||||
}
|
||||
|
||||
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $result, \IPS\DateTime::create()->add( new\DateInterval( 'PT10S' ) ), TRUE );
|
||||
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $result, \IPS\DateTime::create()->add( new \DateInterval( 'PT10S' ) ), TRUE );
|
||||
|
||||
\IPS\Output::i()->json( $result );
|
||||
}
|
||||
@@ -426,6 +431,11 @@ class _editor extends \IPS\Dispatcher\Controller
|
||||
'title' => $row['title']
|
||||
);
|
||||
}
|
||||
|
||||
if ( empty( $results['images'] ) )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'error' => \IPS\Theme::i()->getTemplate( 'system', 'core' )->noResults() ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( $results );
|
||||
}
|
||||
|
||||
@@ -34,18 +34,13 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
/* Did we just log in? */
|
||||
if ( \IPS\Member::loggedIn()->member_id and isset( \IPS\Request::i()->_fromLogin ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
|
||||
}
|
||||
|
||||
/* Init login class */
|
||||
$login = new \IPS\Login( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' ) );
|
||||
|
||||
/* What's our referrer? */
|
||||
$postBeforeRegister = NULL;
|
||||
$ref = \IPS\Request::i()->ref;
|
||||
$ref = \IPS\Request::i()->referrer( FALSE, FALSE );
|
||||
|
||||
if ( !$ref and isset( \IPS\Request::i()->cookie['post_before_register'] ) )
|
||||
{
|
||||
try
|
||||
@@ -111,12 +106,18 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
|
||||
/* Are we already logged in? */
|
||||
if ( \IPS\Member::loggedIn()->member_id AND ( !\IPS\Request::i()->_err OR \IPS\Request::i()->_err != 'login_as_user_login' ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('') );
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->login( $login, base64_encode( $ref ), $error );
|
||||
|
||||
/* Don't cache for a short while to ensure sessions work */
|
||||
\IPS\Request::i()->setCookie( 'noCache', 1 );
|
||||
@@ -290,7 +291,7 @@ class _login extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
protected function loginas()
|
||||
{
|
||||
if ( !\IPS\Request::i()->key or \IPS\Data\Store::i()->admin_login_as_user != \IPS\Request::i()->key )
|
||||
if ( !\IPS\Request::i()->key or !\IPS\Login::compareHashes( (string) \IPS\Data\Store::i()->admin_login_as_user, (string) \IPS\Request::i()->key ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'invalid_login_as_user_key', '3S167/1', 403, '' );
|
||||
}
|
||||
|
||||
@@ -56,18 +56,29 @@ 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' => \IPS\Helpers\Form\Text::BYPASS_PROFANITY_ALL ), function( $val ){
|
||||
if( !\IPS\Login::emailIsInUse( $val ) )
|
||||
{
|
||||
throw new \LogicException( 'lost_pass_no_email' );
|
||||
}
|
||||
}) );
|
||||
$form->add( new \IPS\Helpers\Form\Email( 'email_address', NULL, TRUE, array( 'bypassProfanity' => \IPS\Helpers\Form\Text::BYPASS_PROFANITY_ALL ) ) );
|
||||
|
||||
$captcha = new \IPS\Helpers\Form\Captcha;
|
||||
|
||||
if ( (string) $captcha !== '' )
|
||||
{
|
||||
$form->add( $captcha );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('lost_password');
|
||||
|
||||
/* Handle the reset */
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if( !\IPS\Login::emailIsInUse( $values['email_address'] ) )
|
||||
{
|
||||
/* We intentionally show the same message as if the request was successful to avoid leaking information about membership */
|
||||
\IPS\Output::i()->sidebar['enabled'] = FALSE;
|
||||
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'system' )->lostPassConfirm( 'lost_pass_confirm' );
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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 ( $member->member_id and \IPS\Settings::i()->allow_forgot_password == 'normal' )
|
||||
|
||||
@@ -42,19 +42,21 @@ class _marketplace extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Db::i()->update( 'core_marketplace_tokens', array( 'token' => \IPS\Request::i()->access_token, 'expires_at' => time() + \IPS\Request::i()->expires_in ), array( 'id=?', \IPS\Request::i()->member ) );
|
||||
|
||||
echo 'OK';
|
||||
exit;
|
||||
$response = 'OK';
|
||||
$responseCode = 200;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
echo 'BAD_HASH';
|
||||
exit;
|
||||
$response = 'BAD_HASH';
|
||||
$responseCode = 403;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo 'NO_MEMBER';
|
||||
exit;
|
||||
$response = 'NO_MEMBER';
|
||||
$responseCode = 404;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( $response, $responseCode, 'text/plain' );
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,84 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('notifications');
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Output::i()->title );
|
||||
\IPS\Output::i()->output = (string) $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe a user's device to push notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function subscribeToPush()
|
||||
{
|
||||
$this->_checkLoggedIn();
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
if ( isset( \IPS\Request::i()->subscription ) AND $subscription = json_decode( \IPS\Request::i()->subscription, TRUE ) )
|
||||
{
|
||||
$device = \IPS\Member\Device::loadOrCreate( \IPS\Member::loggedIn(), FALSE );
|
||||
/* If a subscription already exists, then just return */
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->select( '*', 'core_notifications_pwa_keys', array( "`member`=? AND p256dh=? AND auth=?", \IPS\Member::loggedIn()->member_id, $subscription['keys']['p256dh'], $subscription['keys']['auth'] ) )->first();
|
||||
|
||||
/* Make sure encoding and device is up to date, though since it's needed for encryption transfer. */
|
||||
\IPS\Db::i()->update( 'core_notifications_pwa_keys', array(
|
||||
'encoding' => \IPS\Request::i()->encoding,
|
||||
'device' => $device->device_key
|
||||
), array( "`member`=? AND p256dh=? AND auth=?", \IPS\Member::loggedIn()->member_id, $subscription['keys']['p256dh'], $subscription['keys']['auth'] ) );
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_notifications_pwa_keys', array(
|
||||
'member' => \IPS\Member::loggedIn()->member_id,
|
||||
'endpoint' => $subscription['endpoint'],
|
||||
'p256dh' => $subscription['keys']['p256dh'],
|
||||
'auth' => $subscription['keys']['auth'],
|
||||
'encoding' => \IPS\Request::i()->encoding,
|
||||
'device' => $device->device_key
|
||||
) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( 'OK' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->error( 'invalid_push_subscription', '2C154/H', 403, '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a subscription with the provided key exists for the logged-in user
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function verifySubscription()
|
||||
{
|
||||
$this->_checkLoggedIn();
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
if ( isset( \IPS\Request::i()->key ) )
|
||||
{
|
||||
/* See if a subscription already exists */
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->select( '*', 'core_notifications_pwa_keys', array( "`member`=? AND p256dh=?", \IPS\Member::loggedIn()->member_id, \IPS\Request::i()->key ) )->first();
|
||||
\IPS\Output::i()->json( 'OK' );
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
// Just let it return the error below
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->error( 'invalid_push_subscription', '2C154/I', 403, '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Options: Dispatcher
|
||||
*
|
||||
@@ -127,8 +199,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
if ( $form === TRUE )
|
||||
{
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Member::loggedIn()->notificationsConfiguration = NULL;
|
||||
{
|
||||
$categories = \IPS\Notification::membersOptionCategories( \IPS\Member::loggedIn(), array( $extensionKey => $extension ) );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate('system')->notificationSettingsIndexRowDetails( $extensionKey, $categories[ $extensionKey ] ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
|
||||
}
|
||||
@@ -153,30 +224,6 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable Sounds
|
||||
*
|
||||
* @param array $extensions The extensions
|
||||
* @return void
|
||||
*/
|
||||
protected function sounds()
|
||||
{
|
||||
$this->_checkLoggedIn();
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
\IPS\Member::loggedIn()->members_bitoptions['disable_notification_sounds'] = ( \IPS\Request::i()->enable ? false : true );
|
||||
\IPS\Member::loggedIn()->save();
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->json( 'ok' );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=notifications&do=options', 'front', 'notifications_options' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop receiving all notifications to a particular method
|
||||
*
|
||||
@@ -219,6 +266,11 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
$extension::disableExtra( \IPS\Member::loggedIn(), \IPS\Request::i()->type );
|
||||
}
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->type === 'push' )
|
||||
{
|
||||
\IPS\Member::loggedIn()->clearPwaAuths();
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -239,9 +291,18 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$this->_checkLoggedIn();
|
||||
|
||||
try
|
||||
{
|
||||
$application = \IPS\Application::load( \IPS\Request::i()->follow_app );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'error_no_app', '3C154/F', 404, '' );
|
||||
}
|
||||
|
||||
/* Get class */
|
||||
$class = NULL;
|
||||
foreach ( \IPS\Application::load( \IPS\Request::i()->follow_app )->extensions( 'core', 'ContentRouter' ) as $ext )
|
||||
foreach ( $application->extensions( 'core', 'ContentRouter' ) as $ext )
|
||||
{
|
||||
foreach ( $ext->classes as $classname )
|
||||
{
|
||||
@@ -309,7 +370,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'follow_thing', FALSE, array( 'sprintf' => array( $thing->_title ) ) );
|
||||
|
||||
/* Set navigation */
|
||||
@@ -325,7 +386,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
elseif ( $class == 'IPS\Member\Club' )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::loadAndCheckPerms( (int) \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') ),
|
||||
@@ -333,8 +394,13 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
elseif ( $class != "IPS\Member" )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
{
|
||||
if( !is_subclass_of( $class, "\IPS\Content\Followable" ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$thing = $class::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'follow_thing', FALSE, array( 'sprintf' => array( $thing->mapped('title') ) ) );
|
||||
|
||||
/* Set navigation */
|
||||
@@ -355,7 +421,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$thing = $class::load( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::load( (int) \IPS\Request::i()->follow_id );
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('follow_thing', FALSE, array( 'sprintf' => array( $thing->name ) ) );
|
||||
|
||||
@@ -535,10 +601,28 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
/* Send notification if following member */
|
||||
if( $class == "IPS\Member" )
|
||||
{
|
||||
/* Give points */
|
||||
$receiver = \IPS\Member::load( \IPS\Request::i()->follow_rel_id );
|
||||
$receiver->achievementAction( 'core', 'FollowMember', [
|
||||
'giver' => \IPS\Member::loggedIn()
|
||||
] );
|
||||
|
||||
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'member_follow', \IPS\Member::loggedIn(), array( \IPS\Member::loggedIn() ) );
|
||||
$notification->recipients->attach( $thing );
|
||||
$notification->send();
|
||||
}
|
||||
else if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
|
||||
{
|
||||
\IPS\Member::loggedIn()->achievementAction( 'core', 'FollowNode', $class::load( \IPS\Request::i()->follow_id ) );
|
||||
}
|
||||
else if ( \in_array( 'IPS\Content\Item', class_parents( $class ) ) )
|
||||
{
|
||||
$item = $class::load( \IPS\Request::i()->follow_id );
|
||||
\IPS\Member::loggedIn()->achievementAction( 'core', 'FollowContentItem', [
|
||||
'item' => $item,
|
||||
'author' => $item->author()
|
||||
] );
|
||||
}
|
||||
|
||||
/* Boink */
|
||||
if ( \IPS\Request::i()->isAjax() )
|
||||
@@ -597,7 +681,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
|
||||
try
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( $follow['follow_rel_id'] );
|
||||
$thing = $class::loadAndCheckPerms( (int) $follow['follow_rel_id'] );
|
||||
|
||||
foreach ( $thing->nodes() as $node )
|
||||
{
|
||||
@@ -651,7 +735,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
|
||||
}
|
||||
|
||||
if ( !class_exists( $class ) )
|
||||
if ( !class_exists( $class ) or !array_key_exists( \IPS\Request::i()->follow_app, \IPS\Application::applications() ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C154/5', 404, '' );
|
||||
}
|
||||
@@ -665,7 +749,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$classname = $class::$contentItemClass;
|
||||
$containerClass = $class;
|
||||
$thing = $containerClass::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $containerClass::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
$followers = $classname::containerFollowers( $thing, $classname::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
|
||||
$followersCount = $classname::containerFollowerCount( $thing );
|
||||
$anonymous = $classname::containerFollowerCount( $thing, $classname::FOLLOW_ANONYMOUS );
|
||||
@@ -673,7 +757,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else if ( $class == "IPS\Member\Club" )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
|
||||
$followersCount = $thing->followersCount();
|
||||
$anonymous = $thing->followersCount( $class::FOLLOW_ANONYMOUS );
|
||||
@@ -681,7 +765,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else if ( $class != "IPS\Member" )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
|
||||
$followersCount = $thing->followersCount();
|
||||
$anonymous = $thing->followersCount( $class::FOLLOW_ANONYMOUS );
|
||||
@@ -689,7 +773,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$thing = $class::load( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::load( (int) \IPS\Request::i()->follow_id );
|
||||
$followers = $thing->followers( $class::FOLLOW_PUBLIC, array( 'none', 'immediate', 'daily', 'weekly' ), NULL, array( ( $thisPage - 1 ) * $perPage, $perPage ), 'name' );
|
||||
$followersCount = $thing->followersCount();
|
||||
$anonymous = $thing->followersCount( $class::FOLLOW_ANONYMOUS );
|
||||
@@ -735,7 +819,7 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
* @return void
|
||||
*/
|
||||
protected function unfollowFromEmail()
|
||||
{
|
||||
{
|
||||
/* Logged in? */
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
@@ -764,6 +848,11 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
throw new \Exception;
|
||||
}
|
||||
|
||||
if( !array_key_exists( \IPS\Request::i()->follow_app, \IPS\Application::applications() ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
|
||||
/* Get class */
|
||||
if( \IPS\Request::i()->follow_app == 'core' and \IPS\Request::i()->follow_area == 'member' )
|
||||
{
|
||||
@@ -776,6 +865,11 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
else
|
||||
{
|
||||
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
|
||||
|
||||
if( !is_subclass_of( $class, "\IPS\Content\Followable" ) )
|
||||
{
|
||||
throw new \Exception;
|
||||
}
|
||||
}
|
||||
if ( !class_exists( $class ) )
|
||||
{
|
||||
@@ -789,22 +883,22 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$classname = $class::$contentItemClass;
|
||||
$containerClass = $class;
|
||||
$thing = $containerClass::load( \IPS\Request::i()->follow_id );
|
||||
$thing = $containerClass::load( (int) \IPS\Request::i()->follow_id );
|
||||
$title = $thing->_title;
|
||||
}
|
||||
else if ( $class == "IPS\Member\Club" )
|
||||
{
|
||||
$thing = $class::load( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::load( (int) \IPS\Request::i()->follow_id );
|
||||
$title = $thing->_title;
|
||||
}
|
||||
else if ( $class != "IPS\Member" )
|
||||
{
|
||||
$thing = $class::load( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::load( (int) \IPS\Request::i()->follow_id );
|
||||
$title = $thing->mapped('title');
|
||||
}
|
||||
else
|
||||
{
|
||||
$thing = $class::load( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::load( (int) \IPS\Request::i()->follow_id );
|
||||
$title = $thing->name;
|
||||
}
|
||||
|
||||
@@ -890,7 +984,8 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$class = 'IPS\\' . \IPS\Request::i()->follow_app . '\\' . mb_ucfirst( \IPS\Request::i()->follow_area );
|
||||
}
|
||||
if ( !class_exists( $class ) )
|
||||
|
||||
if ( !class_exists( $class ) or !array_key_exists( \IPS\Request::i()->follow_app, \IPS\Application::applications() ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C154/5', 404, '' );
|
||||
}
|
||||
@@ -903,17 +998,22 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$classname = $class::$contentItemClass;
|
||||
$containerClass = $class;
|
||||
$thing = $containerClass::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $containerClass::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
$count = $classname::containerFollowerCount( $thing );
|
||||
}
|
||||
else if ( $class != "IPS\Member" )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( \IPS\Request::i()->follow_id );
|
||||
$thing = $class::loadAndCheckPerms( (int) \IPS\Request::i()->follow_id );
|
||||
$count = $thing->followersCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
$thing = $class::load( \IPS\Request::i()->follow_id );
|
||||
if( !is_subclass_of( $class, "\IPS\Content\Followable" ) AND $class != "IPS\Member" )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C154/J', 404, '' );
|
||||
}
|
||||
|
||||
$thing = $class::load( (int) \IPS\Request::i()->follow_id );
|
||||
$count = $thing->followersCount();
|
||||
}
|
||||
}
|
||||
@@ -983,4 +1083,39 @@ class _notifications extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Request::i()->referrer() ?: \IPS\Http\Url::internal( '' ), 'followers_removed' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve notification data and return it to the service worker
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function fetchNotification()
|
||||
{
|
||||
/* Got the ID? */
|
||||
if( !\IPS\Request::i()->id )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'error' => 'missing_id' ), 404 );
|
||||
}
|
||||
|
||||
/* Got the notification? */
|
||||
try
|
||||
{
|
||||
$notification = \IPS\Db::i()->select( '*', 'core_notifications_pwa_queue', array( 'id=?', \IPS\Request::i()->id ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'error' => 'not_found' ), 404 );
|
||||
}
|
||||
|
||||
/* Is this our notification? */
|
||||
$data = json_decode( $notification['notification_data'], true );
|
||||
|
||||
if( !isset( $data['member'] ) OR $data['member'] != \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'error' => 'no_permission' ), 403 );
|
||||
}
|
||||
|
||||
/* Send the data */
|
||||
\IPS\Output::i()->json( $data );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Offline page output
|
||||
* @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 Feb 2021
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Offline page Controller
|
||||
*/
|
||||
class _offline extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* View Notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->offline(), 200, 'text/html' );
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,8 @@ class _pixabay extends \IPS\Dispatcher\Controller
|
||||
'key' => \IPS\Settings::i()->pixabay_apikey,
|
||||
'image_type' => 'photo',
|
||||
'per_page' => 20,
|
||||
'page' => ( $offset ) ? ceil( $offset / 20 ) + 1 : 1
|
||||
'page' => ( $offset ) ? ceil( $offset / 20 ) + 1 : 1,
|
||||
'safesearch' => ( \IPS\Settings::i()->pixabay_safesearch ) ? 'true' : 'false',
|
||||
);
|
||||
|
||||
$parameters['q'] = urlencode( $query );
|
||||
@@ -79,6 +80,7 @@ class _pixabay extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->json( array('error' => $request['message'] ) );
|
||||
}
|
||||
|
||||
|
||||
$results = array( 'pagination' => array( 'total_count' => $request['total'] ) );
|
||||
foreach ( $request['hits'] as $row )
|
||||
{
|
||||
@@ -89,6 +91,11 @@ class _pixabay extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
|
||||
if ( empty( $results['images'] ) )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'error' => \IPS\Theme::i()->getTemplate( 'system', 'core' )->noResults() ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( $results );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,18 @@ class _privacy extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->error( 'node_error', '2C381/1', 404, 'privacy_set_to_none_acp' );
|
||||
}
|
||||
|
||||
if ( \IPS\Settings::i()->privacy_type == "external" )
|
||||
{
|
||||
if ( $url = \IPS\Settings::i()->privacy_link )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::external( $url ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2C381/1', 404, 'privacy_link_not_set_acp' );
|
||||
}
|
||||
}
|
||||
|
||||
$subprocessors = array();
|
||||
/* Work out the main subprocessors that the user has no direct choice over */
|
||||
if ( \IPS\Settings::i()->privacy_show_processors )
|
||||
|
||||
@@ -39,7 +39,7 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->redirect( \IPS\Settings::i()->base_url );
|
||||
}
|
||||
|
||||
if( \IPS\Request::i()->do !== 'complete'
|
||||
if( \IPS\Request::i()->do !== 'complete' and \IPS\Request::i()->do !== 'setPassword'
|
||||
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 !== 'finish' and \IPS\Request::i()->do !== 'cancel' )
|
||||
@@ -60,6 +60,7 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimalNoHome';
|
||||
}
|
||||
\IPS\Output::i()->sidebar['enabled'] = FALSE;
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( 'app=core&module=system&controller=register', 'front', 'register' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,7 +525,7 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
* @param \IPS\Helpers\Form $form The form object
|
||||
* @return \IPS\Member
|
||||
*/
|
||||
public static function _createMember( $values, $profileFields, $postBeforeRegister = NULL, &$form )
|
||||
public static function _createMember( $values, $profileFields, $postBeforeRegister, &$form )
|
||||
{
|
||||
/* Create */
|
||||
$member = new \IPS\Member;
|
||||
@@ -1003,7 +1004,7 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
}
|
||||
\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 */
|
||||
@@ -1037,6 +1038,10 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
|
||||
\IPS\Email::buildFromTemplate( 'core', $pending['email_chg'] ? 'email_change' : 'registration_validate', array( \IPS\Member::loggedIn(), $vid ), \IPS\Email::TYPE_TRANSACTIONAL )->send( \IPS\Member::loggedIn() );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Member::loggedIn()->memberSync( 'onEmailChange', array( $values['new_email'], $oldEmail ) );
|
||||
}
|
||||
|
||||
/* Redirect */
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( '' ) );
|
||||
@@ -1087,10 +1092,7 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
|
||||
/* Generate form */
|
||||
$form = new \IPS\Helpers\Form( 'reconfirm_checkbox', 'reconfirm_checkbox' );
|
||||
if ( isset( \IPS\Request::i()->ref ) )
|
||||
{
|
||||
$form->hiddenValues['ref'] = \IPS\Request::i()->ref;
|
||||
}
|
||||
$form->hiddenValues['ref'] = base64_encode( \IPS\Request::i()->referrer( FALSE, FALSE, 'front' ) ?? \IPS\Http\Url::baseUrl() );
|
||||
$form->class = 'ipsForm_vertical';
|
||||
|
||||
/* Handle submissions */
|
||||
@@ -1250,7 +1252,7 @@ class _register extends \IPS\Dispatcher\Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPassword(): void
|
||||
public function setPassword()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Service worker output
|
||||
* @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 Feb 2021
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service worker controller
|
||||
*/
|
||||
class _serviceworker extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* View Notifications
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
$cachedUrls = array();
|
||||
$cachedUrls[] = (string) \IPS\Http\Url::internal("app=core&module=system&controller=offline", "front", "user_offline");
|
||||
|
||||
$notificationIcon = NULL;
|
||||
|
||||
/* Get an icon to use in notifications */
|
||||
$homeScreenIcons = json_decode( \IPS\Settings::i()->icons_homescreen, TRUE ) ?? array();
|
||||
|
||||
if( \count( $homeScreenIcons ) )
|
||||
{
|
||||
foreach( $homeScreenIcons as $name => $image )
|
||||
{
|
||||
if( isset( $image['width'] ) and $image['width'] == 192 )
|
||||
{
|
||||
$notificationIcon = \IPS\File::get( 'core_Icons', $image['url'] )->url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* VARIABLES TO PASS THROUGH TO JS */
|
||||
$DEBUG = ( ( \IPS\IN_DEV and \IPS\DEV_DEBUG_JS ) or \IPS\DEBUG_JS ) ? 'true' : 'false'; // Weird casting is intentional.
|
||||
$SW_CACHE_BUST = \IPS\SW_CACHE_BUST ? 'true' : 'false'; // Weird casting is intentional.
|
||||
$HTTP_CACHE_DURATION = \IPS\CACHE_PAGE_TIMEOUT;
|
||||
$BASE_URL = \IPS\Settings::i()->base_url;
|
||||
$CACHED_ASSETS = json_encode( $cachedUrls, JSON_UNESCAPED_SLASHES );
|
||||
$OFFLINE_URL = (string) \IPS\Http\Url::internal("app=core&module=system&controller=offline", "front", "user_offline");
|
||||
$CACHE_VERSION = \IPS\Theme::i()->cssCacheBustKey();
|
||||
$NOTIFICATION_ICON = $notificationIcon ? "\"{$notificationIcon}\"" : 'null'; // Weird casting is intentional. 'null' will become literal null in JS file.
|
||||
$DEFAULT_NOTIFICATION_TITLE = \IPS\Member::loggedIn()->language()->addToStack('default_notification_title');
|
||||
$DEFAULT_NOTIFICATION_BODY = \IPS\Member::loggedIn()->language()->addToStack('default_notification_body');
|
||||
|
||||
$output = <<<JAVASCRIPT
|
||||
"use strict";
|
||||
const DEBUG = {$DEBUG};
|
||||
const SW_CACHE_BUST = {$SW_CACHE_BUST};
|
||||
const BASE_URL = "{$BASE_URL}";
|
||||
const CACHED_ASSETS = {$CACHED_ASSETS};
|
||||
const CACHE_NAME = 'invision-community-{$CACHE_VERSION}';
|
||||
const HTTP_CACHE_DURATION = {$HTTP_CACHE_DURATION};
|
||||
const HTTP_CACHE_BUFFER = 60;
|
||||
const OFFLINE_URL = "{$OFFLINE_URL}";
|
||||
const NOTIFICATION_ICON = {$NOTIFICATION_ICON};
|
||||
const DEFAULT_NOTIFICATION_TITLE = "{$DEFAULT_NOTIFICATION_TITLE}";
|
||||
const DEFAULT_NOTIFICATION_BODY = "{$DEFAULT_NOTIFICATION_BODY}";
|
||||
|
||||
JAVASCRIPT;
|
||||
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $output );
|
||||
$output .= file_get_contents( \IPS\ROOT_PATH . '/applications/core/interface/js/serviceWorker.js' );
|
||||
$cacheHeaders = \IPS\IN_DEV !== true ? \IPS\Output::getCacheHeaders(time(), 86400) : array();
|
||||
\IPS\Output::i()->sendOutput($output, 200, 'text/javascript', $cacheHeaders);
|
||||
}
|
||||
}
|
||||
@@ -350,6 +350,22 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2C122/T', 403, '' );
|
||||
}
|
||||
|
||||
$canChangePassword = FALSE;
|
||||
|
||||
foreach ( \IPS\Login::methods() as $method )
|
||||
{
|
||||
if ( $method->canChangePassword( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
$canChangePassword = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !$canChangePassword )
|
||||
{
|
||||
\IPS\Output::i()->error( 'no_module_permission', '3C122/W', 403, '' );
|
||||
}
|
||||
|
||||
if( \IPS\Member::loggedIn()->isAdmin() )
|
||||
{
|
||||
@@ -538,7 +554,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
}
|
||||
|
||||
$oauthApps = \IPS\Db::i()->select( 'COUNT(DISTINCT client_id)', 'core_oauth_server_access_tokens', array( 'member_id=? AND oauth_enabled=1 AND oauth_ucp=1', \IPS\Member::loggedIn()->member_id ) )
|
||||
$oauthApps = \IPS\Db::i()->select( 'COUNT(DISTINCT client_id)', 'core_oauth_server_access_tokens', array( "member_id=? AND oauth_enabled=1 AND oauth_ucp=1 AND status='active'", \IPS\Member::loggedIn()->member_id ) )
|
||||
->join( 'core_oauth_clients', 'oauth_client_id=client_id' )
|
||||
->first();
|
||||
|
||||
@@ -563,7 +579,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
$device->login_key = NULL;
|
||||
$device->save();
|
||||
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'member_id=? AND device_key=?', $device->member_id, $device->device_key ) );
|
||||
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'member_id=? AND device_key=?', $device->member_id, $device->device_key ) );
|
||||
|
||||
\IPS\Member::loggedIn()->logHistory( 'core', 'login', array( 'type' => 'logout', 'device' => $device->device_key ) );
|
||||
|
||||
@@ -585,20 +601,27 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
if ( !isset( $_SESSION['passwordValidatedForMfa'] ) )
|
||||
{
|
||||
$login = new \IPS\Login( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ), \IPS\Login::LOGIN_REAUTHENTICATE );
|
||||
$error = NULL;
|
||||
try
|
||||
$usernamePasswordMethods = $login->usernamePasswordMethods();
|
||||
$buttonMethods = $login->buttonMethods();
|
||||
|
||||
/* Only prompt for re-authentication if it is possible */
|
||||
if( $usernamePasswordMethods OR $buttonMethods )
|
||||
{
|
||||
if ( $success = $login->authenticate() )
|
||||
$error = NULL;
|
||||
try
|
||||
{
|
||||
$_SESSION['passwordValidatedForMfa'] = TRUE;
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
|
||||
if ( $success = $login->authenticate() )
|
||||
{
|
||||
$_SESSION['passwordValidatedForMfa'] = TRUE;
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&area=mfa', 'front', 'settings_mfa' ) );
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Login\Exception $e )
|
||||
{
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
return \IPS\Theme::i()->getTemplate( 'system' )->settingsMfaPassword( $login, $error );
|
||||
}
|
||||
catch ( \IPS\Login\Exception $e )
|
||||
{
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
return \IPS\Theme::i()->getTemplate( 'system' )->settingsMfaPassword( $login, $error );
|
||||
}
|
||||
|
||||
/* Get our handlers and the output, even if it's just for a backdrop */
|
||||
@@ -742,7 +765,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
$this->_performRedirect( \IPS\Http\Url::internal('') );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_complete_details');
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('reg_complete_2fa_title');
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( '2fa.css', 'core', 'global' ) );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->mfaSetup( $handlers, \IPS\Member::loggedIn(), \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&do=initialMfa', 'front', 'settings' )->addRef( $this->_performRedirect( \IPS\Http\Url::internal(''), '', TRUE ) ) );
|
||||
}
|
||||
@@ -1128,7 +1151,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
|
||||
/* Number of Images */
|
||||
if ( \is_numeric( $sigLimits[1] ) and $signature->getElementsByTagName('img')->length > 0 )
|
||||
if ( \is_numeric( $sigLimits[1] ) )
|
||||
{
|
||||
$imageCount = 0;
|
||||
foreach ( $signature->getElementsByTagName('img') as $img )
|
||||
@@ -1138,6 +1161,15 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
$imageCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for background-image URLs too */
|
||||
$xpath = new \DOMXpath( $signature );
|
||||
|
||||
foreach ( $xpath->query("//*[contains(@style, 'url') and contains(@style, 'background')]") as $styleUrl )
|
||||
{
|
||||
$imageCount++;
|
||||
}
|
||||
|
||||
if( $imageCount > $sigLimits[1] )
|
||||
{
|
||||
$errors[] = \IPS\Member::loggedIn()->language()->addToStack('sig_num_images_exceeded');
|
||||
@@ -1479,6 +1511,10 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_oauth_server_access_tokens', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), 'issued DESC' ) as $accessToken )
|
||||
{
|
||||
if ( $accessToken['status'] == 'revoked' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
$client = \IPS\Api\OAuthClient::load( $accessToken['client_id'] );
|
||||
@@ -1538,7 +1574,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
try
|
||||
{
|
||||
$client = \IPS\Api\OAuthClient::load( \IPS\Request::i()->client_id );
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'client_id=? AND member_id=?', $client->client_id, \IPS\Member::loggedIn()->member_id ) );
|
||||
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'client_id=? AND member_id=?', $client->client_id, \IPS\Member::loggedIn()->member_id ) );
|
||||
\IPS\Member::loggedIn()->logHistory( 'core', 'oauth', array( 'type' => 'revoked_access_token', 'client' => $client->client_id ) );
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
@@ -280,6 +280,8 @@ class _warnings extends \IPS\Content\Controller
|
||||
'remove' => $remove,
|
||||
'remove_override' => TRUE,
|
||||
'notes' => NULL,
|
||||
'cheev_point_reduction' => 0,
|
||||
'cheev_override' => TRUE
|
||||
) );
|
||||
}
|
||||
|
||||
@@ -313,6 +315,8 @@ class _warnings extends \IPS\Content\Controller
|
||||
'remove' => $remove,
|
||||
'remove_override' => $reason->remove_override,
|
||||
'notes' => $reason->notes,
|
||||
'cheev_point_reduction' => $reason->cheev_point_reduction,
|
||||
'cheev_override' => $reason->cheev_override
|
||||
) );
|
||||
}
|
||||
|
||||
@@ -324,6 +328,8 @@ class _warnings extends \IPS\Content\Controller
|
||||
'remove' => $remove,
|
||||
'remove_override' => FALSE,
|
||||
'notes' => NULL,
|
||||
'cheev_point_reduction' => 0,
|
||||
'cheev_override' => FALSE
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user