Version 4.7.0

This commit is contained in:
Neo committed 2025-12-19 16:00:35 -08:00
1 parent 517a5e1f70
commit 8ba7d43898
1933 files changed
+65613 -11332

No files matched your search

@@ -42,7 +42,25 @@ class _forums extends \IPS\Dispatcher\Controller
\IPS\Output::i()->error( 'node_error', '2F176/1', 404, '' );
}
}
protected $childrenIds = [];
protected function getChildrenIds( $forum )
{
$this->childrenIds[] = $forum->_id;
foreach( $forum->children() as $node )
{
$this->childrenIds[] = $node->_id;
foreach( $node->children() as $child )
{
$this->getChildrenIds( $child );
}
}
return $this->childrenIds;
}
/**
* Show Forum
*
@@ -88,37 +106,6 @@ class _forums extends \IPS\Dispatcher\Controller
}
$getReactions = $getFirstComment = $getFollowerCount = (boolean) ( \IPS\forums\Forum::getMemberListView() === 'snippet' );
/* Init table (it won't show anything until after the password check, but it sets navigation and titles) */
$table = new \IPS\Helpers\Table\Content( 'IPS\forums\Topic', $forum->url(), $where, $forum, NULL, 'view', isset( \IPS\Request::i()->rss ) ? FALSE : TRUE, isset( \IPS\Request::i()->rss ) ? FALSE : TRUE, NULL, $getFirstComment, $getFollowerCount, $getReactions );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' ), 'forumTable' );
$table->classes = array( 'cTopicList' );
$table->limit = \IPS\Settings::i()->forums_topics_per_page;
$table->title = \IPS\Member::loggedIn()->language()->addToStack( ( $forum->forums_bitoptions['bw_enable_answers'] ) ? 'count_questions_in_forum' : 'count_topics_in_forum', FALSE, array( 'pluralize' => array( $forum->topics ) ) );
if ( $forum->forums_bitoptions['bw_enable_answers'] )
{
$table->rowsTemplate = array( $this->themeGroup, 'questionRow' );
}
else
{
if ( \IPS\forums\Forum::getMemberListView() == 'snippet' )
{
$table->rowsTemplate = array( $this->themeGroup, 'topicRowSnippet' );
}
else
{
$table->rowsTemplate = array( $this->themeGroup, 'topicRow' );
}
}
$table->hover = TRUE;
$table->sortOptions['num_replies'] = $table->sortOptions['num_comments'];
unset( $table->sortOptions['num_comments'] );
/* If there's only one forum and we're not in a club, we actually don't want the nav */
if ( \IPS\forums\Forum::theOnlyForum() AND !$forum->club() )
{
\IPS\Output::i()->breadcrumb = isset( \IPS\Output::i()->breadcrumb['module'] ) ? array( 'module' => \IPS\Output::i()->breadcrumb['module'] ) : array();
}
/* Redirect? */
if ( $forum->redirect_url )
@@ -127,142 +114,283 @@ class _forums extends \IPS\Dispatcher\Controller
$forum->save();
\IPS\Output::i()->redirect( $forum->redirect_url );
}
/* Display */
if ( $forum->isCombinedView() )
{
$childrenIds = $this->getChildrenIds( $forum );
$where = array();
if ( \IPS\forums\Forum::customPermissionNodes() )
{
$where['container'][] = array( 'forums_forums.password IS NULL' );
}
if ( !\IPS\Settings::i()->club_nodes_in_apps OR !\IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'clubs', 'front' ) ) )
{
$where['container'][] = array( 'forums_forums.club_id IS NULL' );
}
$forumIds = array();
$ids = $childrenIds;
$urlParam = 'forumId' . $forum->_id;
if ( isset( \IPS\Request::i()->$urlParam ) )
{
$ids = explode( ',', \IPS\Request::i()->$urlParam );
}
else if ( isset( \IPS\Request::i()->cookie['forums_flowIdsRoots'] ) and $cookie = json_decode( \IPS\Request::i()->cookie['forums_flowIdsRoots'], TRUE ) )
{
if ( isset( $cookie[ $forum->_id ] ) )
{
if ( \is_array( $cookie[ $forum->_id ] ) )
{
$ids = $cookie[$forum->_id];
}
}
}
/* Inline forum IDs? */
if ( ( \is_array( $ids ) and ! \count( $ids ) ) )
{
/* If we unselect all the filters, then there is nothing to show... */
$where[] = [ "1=2" ];
}
else if ( \count( $ids ) )
{
foreach( $ids as $id )
{
if ( ! \in_array( $id, $childrenIds ) )
{
continue;
}
try
{
/* Panic not, they are all loaded into memory at this point */
$_forum = \IPS\forums\Forum::load( $id );
$forumIds[] = $_forum->id;
}
catch( \Exception $ex ) { }
}
if ( \count( $forumIds ) )
{
$where['container'][] = array( \IPS\Db::i()->in( 'forums_forums.id', array_filter( $forumIds ) ) );
}
}
/* Simplified view */
$table = new \IPS\Helpers\Table\Content( 'IPS\forums\Topic', $forum->url(), $where, $forum, NULL, 'read', TRUE, FALSE, NULL, FALSE, FALSE, FALSE, FALSE );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'index' ), 'simplifiedForumTable' );
$table->classes = array( 'cTopicList' );
$table->limit = \IPS\Settings::i()->forums_topics_per_page;
$table->enableRealtime = true;
if ( \IPS\forums\Forum::getMemberListView() == 'snippet' )
{
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'index' ), 'simplifiedTopicRowSnippet' );
}
else
{
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'index' ), 'simplifiedTopicRow' );
}
$table->honorPinned = \IPS\Settings::i()->forums_fluid_pinned;
$table->hover = TRUE;
$table->sortOptions['num_replies'] = $table->sortOptions['num_comments'];
unset( $table->sortOptions['num_comments'] );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'index' )->simplifiedView( $table );
if( \IPS\forums\Forum::theOnlyForum() === NULL )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'index' )->simplifiedViewForumSidebar( $forum );
}
if ( isset( $where['container'] ) )
{
$allForumIds = iterator_to_array( \IPS\Db::i()->select( 'id', 'forums_forums', $where['container'] ) );
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack('forums_chosen_forums') ] = array( 'type' => 'forums_topic', 'nodes' => implode( ',', $allForumIds ) );
}
}
else
{
/* Init table (it won't show anything until after the password check, but it sets navigation and titles) */
$table = new \IPS\Helpers\Table\Content( 'IPS\forums\Topic', $forum->url(), $where, $forum, NULL, 'view', isset( \IPS\Request::i()->rss ) ? FALSE : TRUE, isset( \IPS\Request::i()->rss ) ? FALSE : TRUE, NULL, $getFirstComment, $getFollowerCount, $getReactions );
$table->tableTemplate = array(\IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' ), 'forumTable');
$table->classes = array('cTopicList');
$table->limit = \IPS\Settings::i()->forums_topics_per_page;
$table->title = \IPS\Member::loggedIn()->language()->addToStack( ( $forum->forums_bitoptions['bw_enable_answers'] ) ? 'count_questions_in_forum' : 'count_topics_in_forum', FALSE, array('pluralize' => array($forum->topics)) );
if ( $forum->forums_bitoptions['bw_enable_answers'] )
{
$table->rowsTemplate = array($this->themeGroup, 'questionRow');
}
else
{
if ( \IPS\forums\Forum::getMemberListView() == 'snippet' )
{
$table->rowsTemplate = array($this->themeGroup, 'topicRowSnippet');
}
else
{
$table->rowsTemplate = array($this->themeGroup, 'topicRow');
}
}
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_forums' ) ] = array( 'type' => 'forums_topic', 'nodes' => $forum->_id );
}
/* If there's only one forum and we're not in a club, we actually don't want the nav */
if ( \IPS\forums\Forum::theOnlyForum() and !$forum->club() )
{
\IPS\Output::i()->breadcrumb = isset( \IPS\Output::i()->breadcrumb['module'] ) ? array('module' => \IPS\Output::i()->breadcrumb['module']) : array();
}
$table->hover = TRUE;
if ( isset( $table->sortOptions['num_comments'] ) )
{
$table->sortOptions['num_replies'] = $table->sortOptions['num_comments'];
unset( $table->sortOptions['num_comments'] );
}
/* Custom Search */
$filterOptions = array(
'all' => 'all_topics',
'open' => 'open_topics',
'popular' => 'popular_now',
'poll' => 'poll',
'locked' => 'locked_topics',
'moved' => 'moved_topics',
'all' => 'all_topics',
'open' => 'open_topics',
'popular' => 'popular_now',
'poll' => 'poll',
'locked' => 'locked_topics',
'moved' => 'moved_topics',
);
$timeFrameOptions = array(
'show_all' => 'show_all',
'today' => 'today',
'last_5_days' => 'last_5_days',
'last_7_days' => 'last_7_days',
'last_10_days' => 'last_10_days',
'last_15_days' => 'last_15_days',
'last_20_days' => 'last_20_days',
'last_25_days' => 'last_25_days',
'last_30_days' => 'last_30_days',
'last_60_days' => 'last_60_days',
'last_90_days' => 'last_90_days',
'show_all' => 'show_all',
'today' => 'today',
'last_5_days' => 'last_5_days',
'last_7_days' => 'last_7_days',
'last_10_days' => 'last_10_days',
'last_15_days' => 'last_15_days',
'last_20_days' => 'last_20_days',
'last_25_days' => 'last_25_days',
'last_30_days' => 'last_30_days',
'last_60_days' => 'last_60_days',
'last_90_days' => 'last_90_days',
);
if ( \IPS\Member::loggedIn()->member_id )
{
$filterOptions['starter'] = $forum->forums_bitoptions['bw_enable_answers'] ? 'questions_i_asked' : 'topics_i_started';
$filterOptions['replied'] = $forum->forums_bitoptions['bw_enable_answers'] ? 'questions_i_posted_in' : 'topics_i_posted_in';
if ( \IPS\Member::loggedIn()->member_id AND \IPS\Member::loggedIn()->last_visit)
if ( \IPS\Member::loggedIn()->member_id and \IPS\Member::loggedIn()->last_visit )
{
$timeFrameOptions['since_last_visit'] = \IPS\Member::loggedIn()->language()->addToStack('since_last_visit', FALSE, array( 'sprintf' => array( \IPS\DateTime::ts( \IPS\Member::loggedIn()->last_visit ) ) ) );
$timeFrameOptions['since_last_visit'] = \IPS\Member::loggedIn()->language()->addToStack( 'since_last_visit', FALSE, array('sprintf' => array(\IPS\DateTime::ts( \IPS\Member::loggedIn()->last_visit ))) );
}
}
if ( $forum->forums_bitoptions['bw_enable_answers'] )
{
$table->filters = array(
'questions_with_best_answers' => 'topic_answered_pid>0',
'questions_without_best_answers' => 'topic_answered_pid=0',
'questions_with_best_answers' => 'topic_answered_pid>0',
'questions_without_best_answers' => 'topic_answered_pid=0',
);
$table->sortOptions['question_rating'] = 'forums_topics.question_rating';
}
else if ( $forum->forums_bitoptions['bw_enable_answers_moderator'] )
else
{
$table->filters = array(
'solved_topics' => 'topic_answered_pid>0',
'unsolved_topics' => 'topic_answered_pid=0',
);
if ( $forum->forums_bitoptions['bw_enable_answers_moderator'] )
{
$table->filters = array(
'solved_topics' => 'topic_answered_pid>0',
'unsolved_topics' => 'topic_answered_pid=0',
);
}
}
/* Are we a moderator? */
if( \IPS\forums\Topic::modPermission( 'unhide', NULL, $forum ) )
if ( \IPS\forums\Topic::modPermission( 'unhide', NULL, $forum ) )
{
$filterOptions['queued_topics'] = 'queued_topics';
$filterOptions['queued_posts'] = 'queued_posts';
$filterOptions['queued_topics'] = 'queued_topics';
$filterOptions['queued_posts'] = 'queued_posts';
$table->filters['filter_hidden_topics'] = 'approved=-1';
$table->filters['filter_hidden_posts_in_topics'] = 'topic_hiddenposts=1';
}
/* Are we filtering by queued topics or posts? */
if( \IPS\Request::i()->filter == 'queued_topics' OR \IPS\Request::i()->filter == 'queued_posts' )
if ( \IPS\Request::i()->filter == 'queued_topics' or \IPS\Request::i()->filter == 'queued_posts' )
{
\IPS\Request::i()->advanced_search_submitted = 1;
\IPS\Request::i()->csrfKey = \IPS\Session::i()->csrfKey;
\IPS\Request::i()->topic_type = \IPS\Request::i()->filter;
}
$table->advancedSearch = array(
'topic_type' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $filterOptions ) ),
'sort_by' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
'last_post' => 'last_post',
'replies' => 'replies',
'views' => 'views',
'topic_title' => 'topic_title',
'last_poster' => 'last_poster',
'topic_started' => 'topic_started',
'topic_starter' => $forum->forums_bitoptions['bw_enable_answers'] ? 'question_asker' : 'topic_starter',
) )
'topic_type' => array(\IPS\Helpers\Table\SEARCH_SELECT, array('options' => $filterOptions)),
'sort_by' => array(\IPS\Helpers\Table\SEARCH_SELECT, array('options' => array(
'last_post' => 'last_post',
'replies' => 'replies',
'views' => 'views',
'topic_title' => 'topic_title',
'last_poster' => 'last_poster',
'topic_started' => 'topic_started',
'topic_starter' => $forum->forums_bitoptions['bw_enable_answers'] ? 'question_asker' : 'topic_starter',
))
),
'sort_direction'=> array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
'asc' => 'asc',
'desc' => 'desc',
) )
'sort_direction' => array(\IPS\Helpers\Table\SEARCH_SELECT, array('options' => array(
'asc' => 'asc',
'desc' => 'desc',
))
),
'time_frame' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $timeFrameOptions ) ),
'time_frame' => array(\IPS\Helpers\Table\SEARCH_SELECT, array('options' => $timeFrameOptions)),
);
$table->advancedSearchCallback = function( $table, $values )
{
$table->advancedSearchCallback = function ( $table, $values ) {
/* Type */
switch ( $values['topic_type'] )
{
case 'open':
$table->where[] = array( 'state=?', 'open' );
$table->where[] = array('state=?', 'open');
break;
case 'popular':
$table->where[] = array( 'popular_time IS NOT NULL AND popular_time>?', time() );
$table->where[] = array('popular_time IS NOT NULL AND popular_time>?', time());
break;
case 'poll':
$table->where[] = array( 'poll_state<>0' );
$table->where[] = array('poll_state<>0');
break;
case 'locked':
$table->where[] = array( 'state=?', 'closed' );
$table->where[] = array('state=?', 'closed');
break;
case 'moved':
$table->where[] = array( 'state=?', 'link' );
$table->where[] = array('state=?', 'link');
break;
case 'starter':
$table->where[] = array( 'starter_id=?', \IPS\Member::loggedIn()->member_id );
$table->where[] = array('starter_id=?', \IPS\Member::loggedIn()->member_id);
break;
case 'replied':
$table->joinComments = TRUE;
$table->where[] = array( 'forums_posts.author_id=?', \IPS\Member::loggedIn()->member_id );
$table->where[] = array('forums_posts.author_id=?', \IPS\Member::loggedIn()->member_id);
break;
case 'answered':
$table->where[] = array( 'topic_answered_pid<>0' );
$table->where[] = array('topic_answered_pid<>0');
break;
case 'unanswered':
$table->where[] = array( 'topic_answered_pid=0' );
$table->where[] = array('topic_answered_pid=0');
break;
case 'queued_topics':
$table->where[] = array( 'approved=0' );
$table->where[] = array('approved=0');
break;
case 'queued_posts':
$table->where[] = array( 'topic_queuedposts>0' );
$table->where[] = array('topic_queuedposts>0');
break;
}
if ( ! isset( $values['sort_by'] ) )
if ( !isset( $values['sort_by'] ) )
{
$values['sort_by'] = 'forums_topics.last_post';
}
/* Sort */
switch ( $values['sort_by'] )
{
@@ -288,10 +416,10 @@ class _forums extends \IPS\Dispatcher\Controller
break;
}
$table->sortDirection = $values['sort_direction'];
/* Cutoff */
$days = NULL;
if ( isset( $values['time_frame'] ) )
{
switch ( $values['time_frame'] )
@@ -327,18 +455,18 @@ class _forums extends \IPS\Dispatcher\Controller
$days = 90;
break;
case 'since_last_visit':
$table->where[] = array( 'forums_topics.last_post>?', \IPS\Member::loggedIn()->last_visit );
$table->where[] = array('forums_topics.last_post>?', \IPS\Member::loggedIn()->last_visit);
break;
}
}
if ( $days !== NULL )
{
$table->where[] = array( 'forums_topics.last_post>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $days . 'D' ) )->getTimestamp() );
$table->where[] = array('forums_topics.last_post>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $days . 'D' ) )->getTimestamp());
}
};
\IPS\Request::i()->sort_direction = \IPS\Request::i()->sort_direction ?: mb_strtolower( $table->sortDirection );
\IPS\Request::i()->sort_direction = \IPS\Request::i()->sort_direction ?: mb_strtolower( $table->sortDirection );
/* Saved actions */
foreach ( \IPS\forums\SavedAction::actions( $forum ) as $action )
{
@@ -353,7 +481,7 @@ class _forums extends \IPS\Dispatcher\Controller
if ( \IPS\Member::loggedIn()->member_id )
{
$key = md5( ( \IPS\Member::loggedIn()->members_pass_hash ?: \IPS\Member::loggedIn()->email ) . \IPS\Member::loggedIn()->members_pass_salt );
$key = \IPS\Member::loggedIn()->getUniqueMemberHash();
$rssUrl = $rssUrl->setQueryString( array( 'member' => \IPS\Member::loggedIn()->member_id , 'key' => $key ) );
}
@@ -377,6 +505,23 @@ class _forums extends \IPS\Dispatcher\Controller
{
\IPS\forums\Forum::populateFollowerCounts( $forum );
}
/* Data Layer Context */
if ( !\IPS\Request::i()->isAjax AND \IPS\Settings::i()->core_datalayer_enabled )
{
foreach ( $forum->getDataLayerProperties() as $key => $value )
{
\IPS\core\DataLayer::i()->addContextProperty( $key, $value );
\IPS\core\DataLayer::i()->addContextProperty( 'sort_direction', \IPS\Request::i()->sort_direction ?: null );
$sortby = \IPS\Request::i()->sort_by ?: null;
if ( $sortby AND !\in_array( $sortby, ['asc', 'desc'] ) )
{
$sortby = null;
}
\IPS\core\DataLayer::i()->addContextProperty( 'sort_by', $sortby );
\IPS\core\DataLayer::i()->addContextProperty( 'page_number', 'page' );
}
}
/* Show Forum */
if ( isset( \IPS\Request::i()->advancedSearchForm ) )
@@ -384,11 +529,10 @@ class _forums extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = (string) $table;
return;
}
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_forums' ) ] = array( 'type' => 'forums_topic', 'nodes' => $forum->_id );
$forumOutput = '';
if ( $forum->forums_bitoptions['bw_enable_answers'] )
if ( ! $forum->isCombinedView() and $forum->forums_bitoptions['bw_enable_answers'] )
{
$featuredTopic = NULL;
@@ -412,14 +556,25 @@ class _forums extends \IPS\Dispatcher\Controller
$newQuestions = \IPS\forums\Topic::getItemsWithPermission( $newQuestionsWhere, 'start_date DESC', 5 );
$forumOutput = \IPS\Theme::i()->getTemplate( 'forums' )->qaForum( (string) $table, $popularQuestions, $newQuestions, $featuredTopic, $forum );
}
else if( $forum->sub_can_post )
else if( $forum->sub_can_post or $forum->isCombinedView() )
{
$forumOutput = (string) $table;
}
$table = $this->postProcessTable( $table );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js('front_forum.js', 'forums' ) );
\IPS\Output::i()->output = $this->themeGroup->forumDisplay( $forum, $forumOutput );
}
/**
* Return the forum table
*
* @return \IPS\Helpers\Table\Content
*/
protected function postProcessTable( $table ) {
return $table;
}
/**
* Show Club Forums
@@ -596,10 +751,39 @@ class _forums extends \IPS\Dispatcher\Controller
{
\IPS\Db::i()->replace( 'forums_view_method', array( 'member_id' => \IPS\Member::loggedIn()->member_id, 'method' => $method, 'type' => 'list' ) );
}
if ( ! \IPS\Request::i()->id )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=forums&module=forums&controller=index', 'front', 'forums' ) );
}
\IPS\Output::i()->redirect( \IPS\forums\Forum::load( \IPS\Request::i()->id )->url() );
}
/**
* Populate the combined fluid view start modal form elements
* @param $nodes
* @param $disabled
* @param $node
* @param int $depth
*/
protected function _selectForumPopulate( &$nodes, &$disabled, $node, $depth = 0 )
{
if ( $node->can('view') )
{
$nodes[ $node->_id ] = str_repeat( '- ', $depth ) . $node->_title;
if ( ! $node->can('add') )
{
$disabled[] = $node->_id;
}
foreach( $node->children() AS $child )
{
$this->_selectForumPopulate( $nodes, $disabled, $child, $depth + 1 );
}
}
}
/**
* Shows the forum selector for creating a topic outside of specific forum
*
@@ -607,31 +791,59 @@ class _forums extends \IPS\Dispatcher\Controller
*/
protected function _selectForum()
{
if( !\IPS\forums\Forum::canOnAny( 'add' ) )
{
\IPS\Output::i()->error( 'no_module_permission', '2F176/5', 403, 'no_module_permission_guest' );
}
$form = new \IPS\Helpers\Form( 'select_forum', 'continue' );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Node( 'forum', NULL, TRUE, array(
'url' => \IPS\Http\Url::internal( 'app=forums&module=forums&controller=forums&do=createMenu' ),
'class' => 'IPS\forums\Forum',
'permissionCheck' => function( $node )
{
if ( $node->can( 'view' ) )
{
if ( $node->can( 'add' ) )
{
return TRUE;
}
return FALSE;
}
return NULL;
},
'clubs' => \IPS\Settings::i()->club_nodes_in_apps
) ) );
if ( isset( \IPS\Request::i()->root ) )
{
$root = \IPS\forums\Forum::load( \IPS\Request::i()->root );
$options = [];
$disabled = [];
$this->_selectForumPopulate( $options, $disabled, $root );
$form->add( new \IPS\Helpers\Form\Select( 'forum', $root->id, TRUE, [
'options' => $options,
'disabled' => $disabled
] ) );
}
else
{
$form->add( new \IPS\Helpers\Form\Node( 'forum', NULL, TRUE, array(
'url' => \IPS\Http\Url::internal( 'app=forums&module=forums&controller=forums&do=createMenu' ),
'class' => 'IPS\forums\Forum',
'permissionCheck' => function ( $node ) {
if ( $node->can( 'view' ) )
{
if ( $node->can( 'add' ) )
{
return TRUE;
}
return FALSE;
}
return NULL;
},
'clubs' => \IPS\Settings::i()->club_nodes_in_apps
) ) );
}
if ( $values = $form->values() )
{
\IPS\Output::i()->redirect( $values['forum']->url()->setQueryString( 'do', 'add' ) );
if ( \is_numeric( $values['forum'] ) )
{
$forum = \IPS\forums\Forum::load( $values['forum'] );
}
else
{
$forum = $values['forum'];
}
\IPS\Output::i()->redirect( $forum->url()->setQueryString( 'do', 'add' ) );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'select_forum' );
@@ -117,7 +117,7 @@ class _index extends \IPS\Dispatcher\Controller
{
$where = array();
if ( \IPS\forums\Forum::hasPasswordForums() )
if ( \IPS\forums\Forum::customPermissionNodes() )
{
$where = array( 'container' => array( array( 'forums_forums.password IS NULL' ) ) );
}
@@ -42,7 +42,7 @@ class _topic extends \IPS\Content\Controller
/**
* View Topic
*
* @return void
* @return \IPS\Content\Item
* @throws \Exception
*/
protected function manage()
@@ -263,7 +263,7 @@ class _topic extends \IPS\Content\Controller
$current = current( $comments );
reset( $comments );
if( !\count( $comments ) AND !$topic->isQuestion() )
if( ( !\count( $comments ) AND !$topic->isQuestion() ) OR ( $topic->isQuestion() AND empty( $question ) ) )
{
\IPS\Output::i()->error( 'no_posts_returned', '2F173/L', 404, '' );
}
@@ -296,6 +296,9 @@ class _topic extends \IPS\Content\Controller
reset( $comments );
}
/* A convenient hook point to do any further set up */
$this->finishManage( $topic );
$votes = array();
$topicVotes = array();
@@ -357,29 +360,43 @@ class _topic extends \IPS\Content\Controller
{
try
{
$answer = \IPS\forums\Topic\Post::load( $topic->topic_answered_pid );
\IPS\Output::i()->jsonLd['topic']['mainEntity']['acceptedAnswer'] = array(
'@type' => 'Answer',
'text' => $answer->truncated( TRUE, NULL ),
'url' => (string) $answer->url(),
'dateCreated' => \IPS\DateTime::ts( $answer->post_date )->format( \IPS\DateTime::ISO8601 ),
'upvoteCount' => $answer->reactionCount(),
'author' => array(
'@type' => 'Person',
'name' => $answer->author_name ?: \IPS\Member::load( $answer->author_id )->name,
'image' => \IPS\Member::load( $answer->author_id )->get_photo( TRUE, TRUE )
),
);
if( $topic->isQuestion() )
$postClass = '\IPS\forums\Topic\Post';
if( $topic->isArchived() )
{
\IPS\Output::i()->jsonLd['topic']['mainEntity']['acceptedAnswer']['upvoteCount'] = $answer->post_field_int;
$postClass = '\IPS\forums\Topic\ArchivedPost';
}
if( $answer->author_id )
$answer = $postClass::load( $topic->topic_answered_pid );
/* Set up our column names */
$authorIdColumn = $answer::$databaseColumnMap['author'];
$dateColumn = $answer::$databaseColumnMap['date'];
if ( $truncatedAnswer = $answer->truncated( TRUE, NULL ) )
{
\IPS\Output::i()->jsonLd['topic']['mainEntity']['acceptedAnswer']['author']['url'] = (string) \IPS\Member::load( $answer->author_id )->url();
\IPS\Output::i()->jsonLd['topic']['mainEntity']['acceptedAnswer'] = array(
'@type' => 'Answer',
'text' => $truncatedAnswer,
'url' => (string) $answer->url(),
'dateCreated' => \IPS\DateTime::ts( $answer->$dateColumn )->format( \IPS\DateTime::ISO8601 ),
'upvoteCount' => ( $topic->isArchived() ) ? $answer->field_int : $answer->post_field_int,
'author' => array(
'@type' => 'Person',
'name' => \IPS\Member::load( $answer->$authorIdColumn )->name,
'image' => \IPS\Member::load( $answer->$authorIdColumn )->get_photo( TRUE, TRUE )
),
);
if( $topic->isQuestion() )
{
\IPS\Output::i()->jsonLd['topic']['mainEntity']['acceptedAnswer']['upvoteCount'] = ( $topic->isArchived() ) ? $answer->field_int : $answer->post_field_int;
}
if( $answer->author_id )
{
\IPS\Output::i()->jsonLd['topic']['mainEntity']['acceptedAnswer']['author']['url'] = (string) \IPS\Member::load( $answer->$authorIdColumn )->url();
}
}
}
catch( \OutOfRangeException $e ){}
@@ -424,14 +441,19 @@ class _topic extends \IPS\Content\Controller
$commentJson = [];
foreach( $comments as $comment )
{
/* Set up our column names */
$idColumn = $comment::$databaseColumnId;
$authorIdColumn = $comment::$databaseColumnMap['author'];
$dateColumn = $comment::$databaseColumnMap['date'];
// Don't include the first post as a "comment"
if( $comment->pid == $topic->topic_firstpost )
if( $comment->$idColumn == $topic->topic_firstpost )
{
continue;
}
// Don't include the answer as the suggested answer
if( $isQuestion and ( $comment->pid === $topic->mapped('solved_comment_id') ) )
if( $isQuestion and ( $comment->$idColumn === $topic->mapped('solved_comment_id') ) )
{
continue;
}
@@ -442,21 +464,30 @@ class _topic extends \IPS\Content\Controller
$commentJson[$i] = array(
'@type' => $isQuestion ? 'Answer' : 'Comment',
'@id' => (string)$url->setFragment( 'comment-' . $comment->pid ),
'url' => (string)$url->setFragment( 'comment-' . $comment->pid ),
'@id' => (string)$url->setFragment( 'comment-' . $comment->$idColumn ),
'url' => (string)$url->setFragment( 'comment-' . $comment->$idColumn ),
'author' => array(
'@type' => 'Person',
'name' => $comment->author_name ?: \IPS\Member::load( $comment->author_id )->name,
'image' => \IPS\Member::load( $comment->author_id )->get_photo( TRUE, TRUE )
'name' => \IPS\Member::load( $comment->$authorIdColumn )->name,
'image' => \IPS\Member::load( $comment->$authorIdColumn )->get_photo( TRUE, TRUE )
),
'dateCreated' => \IPS\DateTime::ts( $comment->post_date )->format( \IPS\DateTime::ISO8601 ),
'upvoteCount' => $comment->reactionCount(),
'dateCreated' => \IPS\DateTime::ts( $comment->$dateColumn )->format( \IPS\DateTime::ISO8601 ),
'text' => $truncatedComment,
);
if ( $comment->author_id )
if ( $comment->$authorIdColumn )
{
$commentJson[$i]['author']['url'] = (string)\IPS\Member::load( $comment->author_id )->url();
$commentJson[$i]['author']['url'] = (string)\IPS\Member::load( $comment->$authorIdColumn )->url();
}
if( $isQuestion )
{
$commentJson[$i]['upvoteCount'] = ( $topic->isArchived() ) ? $comment->field_int : $comment->post_field_int;
}
else
{
$commentJson[$i]['upvoteCount'] = $comment->reactionCount();
}
$i++;
@@ -491,7 +522,7 @@ class _topic extends \IPS\Content\Controller
{
/* We do not want to use the \IPS\CACHE_PRIVATE_TIMEOUT constant here, as we explicitly want to cache archived topics for longer times */
$httpHeaders = array( 'Expires' => \IPS\DateTime::create()->add( new \DateInterval( 'PT12H' ) )->rfc1123() ,
'Cache-Control' => "max-age=" . ( 60 * 60 * 12 ) . ", s-maxage=" . ( 60 * 60 * 12 ) . ", public, stale-if-error, stale-while-revalidate" );
'Cache-Control' => 'no-cache="Set-Cookie", max-age=' . ( 60 * 60 * 12 ) . ", s-maxage=" . ( 60 * 60 * 12 ) . ", public, stale-if-error, stale-while-revalidate" );
\IPS\Output::i()->httpHeaders += $httpHeaders;
}
@@ -507,7 +538,7 @@ class _topic extends \IPS\Content\Controller
'image' => (string) \IPS\Member::load( $topic->starter_id )->get_photo( TRUE, TRUE ),
'author' => array(
'@type' => 'Person',
'name' => $topic->starter_name ?: \IPS\Member::load( $topic->starter_id )->name,
'name' => \IPS\Member::load( $topic->starter_id )->name,
'image' => \IPS\Member::load( $topic->starter_id )->get_photo( TRUE, TRUE )
),
'interactionStatistic' => array(
@@ -532,6 +563,8 @@ class _topic extends \IPS\Content\Controller
/* Show topic */
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'topics.css', 'forums' ) );
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'topics' )->topic( $topic, $comments, $question, $votes, $nextUnread, $pagination, $topicVotes );
return $topic;
}
/**