Version 4.3.0

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

No files matched your search

@@ -117,7 +117,6 @@ class _forums extends \IPS\Node\Controller
return parent::permissions();
}
protected function form()
{
parent::form();
@@ -43,7 +43,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
$activeTab = \IPS\Request::i()->tab ?: 'settings';
$activeTabContents = call_user_func( array( $this, 'manage' . ucfirst( $activeTab ) ) );
$activeTabContents = call_user_func( array( $this, 'manage' . mb_ucfirst( $activeTab ) ) );
if( \IPS\Request::i()->isAjax() and !isset( \IPS\Request::i()->ajaxValidate ) )
{
@@ -437,12 +437,19 @@ class _settings extends \IPS\Dispatcher\Controller
}
/* Do we need to unarchive some? */
$whereClause = \IPS\Db::i()->compileWhereClause( \IPS\Application::load('forums')->archiveWhere( $rules ) );
$_whereClause = array( 'topic_archive_status=? AND !( ' . $whereClause['clause'] . ')' );
$_whereClause[] = \IPS\forums\Topic::ARCHIVE_DONE;
foreach ( $whereClause['binds'] as $bind )
if( $values['archive_on'] )
{
$_whereClause[] = $bind;
$whereClause = \IPS\Db::i()->compileWhereClause( \IPS\Application::load('forums')->archiveWhere( $rules ) );
$_whereClause = array( 'topic_archive_status=? AND !( ' . $whereClause['clause'] . ')' );
$_whereClause[] = \IPS\forums\Topic::ARCHIVE_DONE;
foreach ( $whereClause['binds'] as $bind )
{
$_whereClause[] = $bind;
}
}
else
{
$_whereClause = array( 'topic_archive_status NOT IN(' . \IPS\forums\Topic::ARCHIVE_NOT . ',' . \IPS\forums\Topic::ARCHIVE_EXCLUDE . ')' );
}
/* Make sure the unarchive task is enabled - it will disable itself if there is no work to do */
@@ -461,7 +468,7 @@ class _settings extends \IPS\Dispatcher\Controller
/* Log and redirect */
\IPS\Session::i()->log( 'acplogs__archive_settings' );
if ( \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics', $values['archive_on'] ? $_whereClause : array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_DONE ) )->first() )
if ( \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics', $_whereClause )->first() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=forums&module=forums&controller=settings&do=unarchive' ) );
}
@@ -590,10 +597,19 @@ class _settings extends \IPS\Dispatcher\Controller
} ) );
$form->addHeader('topic_settings');
$popularNowMaximum = 14400000;
$form->add( new \IPS\Helpers\Form\Custom( 'forums_popular_now', json_decode( \IPS\Settings::i()->forums_popular_now, TRUE ), FALSE, array(
'getHtml' => function( $obj )
'getHtml' => function( $obj ) use ( $popularNowMaximum )
{
return \IPS\Theme::i()->getTemplate('settings')->popularNow( $obj->name, $obj->value );
return \IPS\Theme::i()->getTemplate('settings')->popularNow( $obj->name, $obj->value, $popularNowMaximum );
},
/* If popular now time is greater than 10,000 days */
'validate' => function( $obj ) use ( $popularNowMaximum )
{
if( $obj->value['minutes'] > $popularNowMaximum )
{
throw new \LengthException( \IPS\Member::loggedIn()->language()->addToStack('form_number_max', FALSE, array( 'sprintf' => array( $popularNowMaximum ) ) ) );
}
}
) ) );
$form->add( new \IPS\Helpers\Form\Number( 'forums_posts_per_page', \IPS\Settings::i()->forums_posts_per_page , TRUE, array( 'min' => 2, 'max' => 250 ) ) );
@@ -31,20 +31,63 @@ class _posts extends \IPS\Dispatcher\Controller
protected function manage()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'posts_manage' );
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=forums&module=stats&controller=posts" ), 'forums_posts', 'post_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
) );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( 'stats_new_posts' ), 'number', 'COUNT(*)', FALSE );
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_posts_title' );
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'menu__forums_stats_posts' );
\IPS\Output::i()->output = (string) $chart;
$tabs = array( 'total' => 'stats_posts_tab_total', 'byforum' => 'stats_posts_tab_byforum' );
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'total';
if ( $activeTab === 'total' )
{
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=forums&module=stats&controller=posts" ), 'forums_posts', 'post_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
) );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( 'stats_new_posts' ), 'number', 'COUNT(*)', FALSE );
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_posts_title' );
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
}
else
{
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=forums&module=stats&controller=posts&tab=" . $activeTab ), 'forums_posts', 'post_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4,
'chartArea' => array( 'width' => '70%', 'left' => '5%' ),
'height' => 400,
'trendlines' => array( 0 => array( 'type' => 'exponential', 'color' => '#000', 'lineWidth' => 2, 'opacity' => 0.3 ) )
),
'ColumnChart',
'monthly',
array( 'start' => ( new \IPS\DateTime )->sub( new \DateInterval('P90D') ), 'end' => new \IPS\DateTime ),
array(),
'byforum'
);
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_posts_title_byforum' );
$chart->availableTypes = array( 'ColumnChart' );
$chart->groupBy = 'forum_id';
$chart->joins = array( array( 'forums_topics', 'forums_topics.tid=forums_posts.topic_id' ) );
foreach( \IPS\Db::i()->select( '*', 'forums_forums', array( 'posts>?', 0 ) ) as $forum )
{
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( 'forums_forum_' . $forum['id'] ), 'number', 'COUNT(*)', TRUE, $forum['id'] );
}
}
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = (string) $chart;
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__forums_stats_posts');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, (string) $chart, \IPS\Http\Url::internal( "app=forums&module=stats&controller=posts" ) );
}
}
}
@@ -31,20 +31,65 @@ class _topics extends \IPS\Dispatcher\Controller
protected function manage()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'topics_manage' );
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=forums&module=stats&controller=topics" ), 'forums_topics', 'start_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
) );
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( 'stats_new_topics' ), 'number', 'COUNT(*)', FALSE );
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_topics_title' );
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'menu__forums_stats_topics' );
\IPS\Output::i()->output = (string) $chart;
$tabs = array( 'total' => 'stats_topics_tab_total', 'byforum' => 'stats_topics_tab_byforum' );
$activeTab = ( isset( \IPS\Request::i()->tab ) and array_key_exists( \IPS\Request::i()->tab, $tabs ) ) ? \IPS\Request::i()->tab : 'total';
if ( $activeTab === 'total' )
{
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=forums&module=stats&controller=topics" ), 'forums_topics', 'start_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'colors' => array( '#10967e' ),
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4
),
'AreaChart'
);
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( 'stats_new_topics' ), 'number', 'COUNT(*)', FALSE );
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_topics_title' );
$chart->availableTypes = array( 'AreaChart', 'ColumnChart', 'BarChart' );
}
else
{
$chart = new \IPS\Helpers\Chart\Database( \IPS\Http\Url::internal( "app=forums&module=stats&controller=topics&tab=" . $activeTab ), 'forums_topics', 'start_date', '', array(
'isStacked' => FALSE,
'backgroundColor' => '#ffffff',
'hAxis' => array( 'gridlines' => array( 'color' => '#f5f5f5' ) ),
'lineWidth' => 1,
'areaOpacity' => 0.4,
'chartArea' => array( 'width' => '70%', 'left' => '5%' ),
'height' => 400,
'trendlines' => array( 0 => array( 'type' => 'exponential', 'color' => '#000', 'lineWidth' => 2, 'opacity' => 0.3 ) )
),
'ColumnChart',
'monthly',
array( 'start' => ( new \IPS\DateTime )->sub( new \DateInterval('P90D') ), 'end' => new \IPS\DateTime ),
array(),
'byforum'
);
$chart->title = \IPS\Member::loggedIn()->language()->addToStack( 'stats_topics_title_byforum' );
$chart->availableTypes = array( 'ColumnChart' );
$chart->groupBy = 'forum_id';
foreach( \IPS\Db::i()->select( '*', 'forums_forums', array( 'topics>?', 0 ) ) as $forum )
{
$chart->addSeries( \IPS\Member::loggedIn()->language()->addToStack( 'forums_forum_' . $forum['id'] ), 'number', 'COUNT(*)', TRUE, $forum['id'] );
}
}
if ( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output = (string) $chart;
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__forums_stats_topics');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $tabs, $activeTab, (string) $chart, \IPS\Http\Url::internal( "app=forums&module=stats&controller=topics" ) );
}
}
}
@@ -29,7 +29,7 @@ class _forums extends \IPS\Dispatcher\Controller
* @return void
*/
protected function manage()
{
{
$forum = NULL;
try
{
@@ -61,7 +61,7 @@ class _forums extends \IPS\Dispatcher\Controller
/* Password protected */
if ( $form = $forum->passwordForm() )
{
\IPS\Output::i()->title = $forum->_stripTagsTitle;
\IPS\Output::i()->title = $forum->_title;
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' ), 'forumPasswordPopup' ), $forum );
return;
}
@@ -320,11 +320,11 @@ class _forums extends \IPS\Dispatcher\Controller
$rssUrl = \IPS\Http\Url::internal( "app=forums&module=forums&controller=forums&id={$forum->_id}&rss=1", 'front', 'forums_rss', array( $forum->name_seo ) );
if ( $forum->forums_bitoptions['bw_enable_answers'] )
{
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_questions', FALSE, array( 'sprintf' => array( $forum->_stripTagsTitle ) ) );
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_questions', FALSE, array( 'escape' => true, 'sprintf' => array( $forum->_title ) ) );
}
else
{
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_topics', FALSE, array( 'sprintf' => array( $forum->_stripTagsTitle ) ) );
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_topics', FALSE, array( 'escape' => true, 'sprintf' => array( $forum->_title ) ) );
}
\IPS\Output::i()->rssFeeds[ $rssTitle ] = $rssUrl;
@@ -411,6 +411,28 @@ class _forums extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forums' )->forumDisplay( $forum, $forumOutput );
}
/**
* Show Club Forums
*
* @return void
*/
public function clubs()
{
if ( !\IPS\Settings::i()->club_nodes_in_apps )
{
\IPS\Output::i()->error( 'node_error', '2F176/4', 404, '' );
}
if ( \IPS\forums\Forum::isSimpleView() )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=forums&module=forums&controller=index&forumId=clubs', 'front', 'forums' ), '', 302 );
}
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack('club_node_forums') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('club_node_forums');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forums' )->clubForums();
}
/**
* Add Topic
@@ -454,7 +476,7 @@ class _forums extends \IPS\Dispatcher\Controller
$formTemplate = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'submit', 'forums' ) ), 'createTopicForm' ), $forum, $hasModOptions, NULL );
if ( \IPS\forums\Topic::moderateNewItems( \IPS\Member::loggedIn() ) )
if ( \IPS\forums\Topic::moderateNewItems( \IPS\Member::loggedIn(), $forum ) )
{
$formTemplate = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->modQueueMessage( \IPS\Member::loggedIn()->warnings( 5, NULL, 'mq' ), \IPS\Member::loggedIn()->mod_posts ) . $formTemplate;
}
@@ -568,7 +590,8 @@ class _forums extends \IPS\Dispatcher\Controller
}
return NULL;
}
},
'clubs' => \IPS\Settings::i()->club_nodes_in_apps
) ) );
if ( $values = $form->values() )
@@ -95,7 +95,14 @@ class _index extends \IPS\Dispatcher\Controller
/* Prepare output */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_core.js', 'core', 'global' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'forums' );
if ( \IPS\forums\Forum::isSimpleView() )
{
\IPS\Output::i()->title = ( isset( \IPS\Request::i()->page ) AND \IPS\Request::i()->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'forums' ), \IPS\Request::i()->page ) ) ) : \IPS\Member::loggedIn()->language()->addToStack( 'forums' );
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'forums' );
}
\IPS\Output::i()->linkTags['canonical'] = (string) \IPS\Http\Url::internal( 'app=forums&module=forums&controller=index', 'front', 'forums' );
\IPS\Output::i()->metaTags['og:title'] = \IPS\Settings::i()->board_name;
\IPS\Output::i()->metaTags['og:type'] = 'website';
@@ -108,9 +115,12 @@ class _index extends \IPS\Dispatcher\Controller
/* Display */
if ( \IPS\forums\Forum::isSimpleView() )
{
$where = array( 'container' => array( array( 'forums_forums.password IS NULL AND forums_forums.can_view_others=1 AND forums_forums.club_id IS NULL' ) ) );
$where = array( 'container' => array( array( 'forums_forums.password IS NULL' ) ) );
if ( !\IPS\Settings::i()->club_nodes_in_apps )
{
$where['container'][] = array( 'forums_forums.club_id IS NULL' );
}
$forumIds = array();
$parentIds = array();
$map = array();
$ids = array();
@@ -130,50 +140,32 @@ class _index extends \IPS\Dispatcher\Controller
{
try
{
/* Panic not, they are all loaded into memory at this point */
$forum = \IPS\forums\Forum::load( $id );
if ( $forum->hasChildren() )
if ( $id == 'clubs' )
{
/* This is a root category, so fetch all children */
$this->getParentIds( $forum, $parentIds );
$forumIds[] = $forum->id;
$parentIds['clubs'] = 'clubs';
foreach ( \IPS\forums\Forum::clubNodes() as $child )
{
$forumIds[ $child->id ] = $child->id;
}
}
else
{
{
/* Panic not, they are all loaded into memory at this point */
$forum = \IPS\forums\Forum::load( $id );
$map[ $forum->parent_id ][] = $forum->_id;
$forumIds[] = $forum->id;
}
}
catch( \Exception $ex ) { }
}
/* Now remove all children that are in the same category */
foreach( $map as $parent => $children )
{
if ( in_array( $parent, $parentIds ) )
{
$forumIds = array_diff( $forumIds, $children );
}
}
$or = array();
if ( count( $forumIds ) )
{
$or[] = \IPS\Db::i()->in( 'forums_forums.id', array_filter( $forumIds ) );
}
if ( count( $parentIds ) )
{
$or[] = \IPS\Db::i()->in( 'forums_forums.parent_id', array_filter( $parentIds ) );
}
if ( count( $or ) )
{
$where['container'][] = array( '(' . implode( ' OR ', $or ) . ')' );
$where['container'][] = array( \IPS\Db::i()->in( 'forums_forums.id', array_filter( $forumIds ) ) );
}
}
/* Simplified view */
$table = new \IPS\Helpers\Table\Content( 'IPS\forums\Topic', \IPS\Http\Url::internal( 'app=forums&module=forums&controller=index', 'front', 'forums' ), $where, NULL, NULL, 'read' );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'index' ), 'simplifiedForumTable' );
@@ -189,7 +181,7 @@ class _index extends \IPS\Dispatcher\Controller
if( \IPS\forums\Forum::theOnlyForum() === NULL )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'index' )->simplifiedViewSidebar( $forumIds, $parentIds );
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'index' )->simplifiedViewSidebar( $forumIds );
}
if ( isset( $where['container'] ) )
@@ -204,32 +196,7 @@ class _index extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'index' )->index();
}
}
/**
* Recursively collect parents
*
* @param \IPS\forums\Forum $forum Forum object
* @param array $parentIds ParentIds to use
* @return void
*/
protected function getParentIds( $forum, &$parentIds )
{
if ( $forum->hasChildren() )
{
$parentIds[ $forum->id ] = $forum->id;
foreach( $forum->children() as $child )
{
if ( $child->hasChildren() )
{
$parentIds[ $child->id ] = $child->id;
$this->getParentIds( $child, $parentIds );
}
}
}
}
/**
* Set the viewing method
*
@@ -237,6 +204,8 @@ class _index extends \IPS\Dispatcher\Controller
*/
protected function setMethod()
{
\IPS\Session::i()->csrfCheck();
$method = ( isset( \IPS\Request::i()->method ) ) ? \IPS\Request::i()->method : \IPS\Settings::i()->forums_default_view;
\IPS\Request::i()->setCookie( 'forum_view', $method, ( new \IPS\DateTime )->add( new \DateInterval( 'P1Y' ) ) );
@@ -234,27 +234,11 @@ class _topic extends \IPS\Content\Controller
{
\IPS\Output::i()->error( 'no_posts_returned', '2F173/L', 404, '' );
}
/* On pages 2 and more, it will show the first post on that page, and that is fine as the title has - Page 2 in it meaning its a different page */
$metaDescription = $topic->isQuestion() ? $question->post : $current->post;
/* Did we request a specific post? If so, reset descriptions. */
if( isset( $_SESSION['_findComment'] ) )
{
$commentId = $_SESSION['_findComment'];
unset( $_SESSION['_findComment'] );
$metaDescription = $topic->metaDescription( isset( $_SESSION['_findComment'] ) ? NULL : ( $topic->isQuestion() ? $question->content() : $current->content() ) );
try
{
$comment = \IPS\forums\Topic\Post::loadAndCheckPerms( $commentId );
$metaDescription = $comment->content();
}
catch( \Exception $e ){}
}
$metaDescription = strip_tags( $metaDescription );
\IPS\Output::i()->metaTags['description'] = \IPS\Output::i()->metaTags['og:description'] = mb_strlen( $metaDescription ) > 160 ? ( mb_substr( $metaDescription, 0, 157 ) . '...' ) : $metaDescription;
\IPS\Output::i()->metaTags['description'] = \IPS\Output::i()->metaTags['og:description'] = $metaDescription;
/* Mark read */
if( !$topic->isLastPage() )
@@ -303,19 +287,18 @@ class _topic extends \IPS\Content\Controller
'@type' => $topic->isQuestion() ? 'Question' : 'DiscussionForumPosting',
'url' => (string) $topic->url(),
'discussionUrl' => (string) $topic->url(),
'name' => htmlspecialchars( $topic->mapped('title'), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'headline' => htmlspecialchars( $topic->mapped('title'), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'name' => $topic->mapped('title'),
'headline' => $topic->mapped('title'),
'text' => strip_tags( $topic->isQuestion() ? $question->truncated() : $current->truncated() ),
'dateCreated' => \IPS\DateTime::ts( $topic->start_date )->format( \IPS\DateTime::ISO8601 ),
'datePublished' => \IPS\DateTime::ts( $topic->start_date )->format( \IPS\DateTime::ISO8601 ),
'pageStart' => 1,
'pageEnd' => $topic->commentPageCount(),
/* Image is required, but we don't have "topic images", so we'll use topic starter's profile photo for now */
'image' => \IPS\Member::load( $topic->starter_id )->get_photo(),
'image' => (string) \IPS\Http\Url::external( \IPS\Member::load( $topic->starter_id )->get_photo() )->setScheme( \IPS\Request::i()->isSecure() ? 'https' : 'http' ),
'author' => array(
'@type' => 'Person',
'name' => htmlspecialchars( $topic->starter_name ?: \IPS\Member::load( $topic->starter_id )->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'url' => (string) \IPS\Member::load( $topic->starter_id )->url(),
'name' => $topic->starter_name ?: \IPS\Member::load( $topic->starter_id )->name,
'image' => \IPS\Member::load( $topic->starter_id )->get_photo()
),
'interactionStatistic' => array(
@@ -337,6 +320,22 @@ class _topic extends \IPS\Content\Controller
)
);
/* Are ratings allowed? */
if( !$topic->isArchived() AND $topic->container()->forum_allow_rating AND $topic->averageRating() )
{
\IPS\Output::i()->jsonLd['topic']['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $topic->averageRating(),
'ratingCount' => $topic->numberOfRatings(),
);
}
/* Do we have a real author */
if( $topic->starter_id )
{
\IPS\Output::i()->jsonLd['topic']['author']['url'] = (string) \IPS\Member::load( $topic->starter_id )->url();
}
if( $topic->isQuestion() )
{
\IPS\Output::i()->jsonLd['topic']['answerCount'] = $topic->posts ? $topic->posts - 1 : 0;
@@ -357,11 +356,15 @@ class _topic extends \IPS\Content\Controller
'upvoteCount' => $answer->post_field_int,
'author' => array(
'@type' => 'Person',
'name' => htmlspecialchars( $answer->author_name ?: \IPS\Member::load( $answer->author_id )->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'url' => (string) \IPS\Member::load( $answer->author_id )->url(),
'name' => $answer->author_name ?: \IPS\Member::load( $answer->author_id )->name,
'image' => \IPS\Member::load( $answer->author_id )->get_photo()
),
);
if( $answer->author_id )
{
\IPS\Output::i()->jsonLd['topic']['acceptedAnswer']['author']['url'] = (string) \IPS\Member::load( $answer->author_id )->url();
}
}
catch( \OutOfRangeException $e ){}
}
@@ -370,21 +373,28 @@ class _topic extends \IPS\Content\Controller
{
\IPS\Output::i()->jsonLd['topic']['comment'] = array();
$i = 0;
foreach( $comments as $comment )
{
\IPS\Output::i()->jsonLd['topic']['comment'][] = array(
\IPS\Output::i()->jsonLd['topic']['comment'][ $i ] = array(
'@type' => 'Comment',
'url' => (string) $comment->url(),
'author' => array(
'@type' => 'Person',
'name' => htmlspecialchars( $comment->author_name ?: \IPS\Member::load( $comment->author_id )->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'url' => (string) \IPS\Member::load( $comment->author_id )->url(),
'name' => $comment->author_name ?: \IPS\Member::load( $comment->author_id )->name,
'image' => \IPS\Member::load( $comment->author_id )->get_photo()
),
'dateCreated' => \IPS\DateTime::ts( $comment->post_date )->format( \IPS\DateTime::ISO8601 ),
'text' => strip_tags( $comment->truncated() ),
'mainEntityOfPage' => (string) $topic->url(),
);
if( $comment->author_id )
{
\IPS\Output::i()->jsonLd['topic']['comment'][ $i ]['author']['url'] = (string) \IPS\Member::load( $comment->author_id )->url();
}
$i++;
}
}
@@ -445,9 +455,20 @@ class _topic extends \IPS\Content\Controller
\IPS\Member::loggedIn()->language()->words['topic_mainTab'] = \IPS\Member::loggedIn()->language()->addToStack( 'question_mainTab', FALSE );
}
if ( !$topic->canEdit() and !\IPS\Request::i()->form_submitted ) // We check if the form has been submitted to prevent the user loosing their content
// We check if the form has been submitted to prevent the user loosing their content
if ( isset( \IPS\Request::i()->form_submitted ) )
{
\IPS\Output::i()->error( 'edit_no_perm_err', '2F173/E', 403, '' );
if ( ! $topic->couldEdit() )
{
\IPS\Output::i()->error( 'edit_no_perm_err', '2F173/E', 403, '' );
}
}
else
{
if ( ! $topic->canEdit() )
{
\IPS\Output::i()->error( 'edit_no_perm_err', '2F173/E', 403, '' );
}
}
$formElements = $class::formElements( $topic, $forum );
@@ -864,6 +885,77 @@ class _topic extends \IPS\Content\Controller
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'widgets', 'forums', 'front' )->poll( $topic, $poll );
}
/**
* Find a Comment / Review (do=findComment/findReview)
*
* @param string $commentClass The comment/review class
* @param \IPS\Content\Comment $comment The comment/review
* @param \IPS\Content\Item $item The item
* @return void
*/
public function _find( $commentClass, $comment, $item )
{
/* For normal topics (i.e. not questions), we can handle this normally */
if ( !$item->isQuestion() )
{
return parent::_find( $commentClass, $comment, $item );
}
/* Otherwise we need to get the position ordered by votes... */
if ( $item->isArchived() )
{
$where = array( array( 'archive_topic_id=?', $item->tid ) );
if ( !$item->canViewHiddenComments() )
{
$hiddenWhereClause = "(archive_queued != -2 AND archive_queued != -1 AND archive_queued != 1)";
if ( \IPS\Member::loggedIn()->member_id )
{
$where[] = array( "( {$hiddenWhereClause} OR ( archive_queued=1 AND archive_author_id=" . \IPS\Member::loggedIn()->member_id . '))' );
}
else
{
$where[] = array( $hiddenWhereClause );
}
}
$answers = \IPS\Db::i()->select( 'archive_id, @rownum := @rownum + 1 AS position', 'forums_archive_posts', $where, 'archive_is_first DESC, archive_bwoptions DESC, archive_field_int DESC, archive_content_date' )->join( array( '(SELECT @rownum := 0)', 'r' ), NULL, 'JOIN' );
$commentPosition = \IPS\Db::i()->select( 'position', $answers, array( 'archive_id=?', $comment->id ) )->first() - 1;
}
else
{
$where = array( array( 'topic_id=?', $item->tid ) );
if ( !$item->canViewHiddenComments() )
{
$hiddenWhereClause = "(queued != -2 AND queued != -1 AND queued != 1)";
if ( \IPS\Member::loggedIn()->member_id )
{
$where[] = array( "( {$hiddenWhereClause} OR ( queued=1 AND author_id=" . \IPS\Member::loggedIn()->member_id . '))' );
}
else
{
$where[] = array( $hiddenWhereClause );
}
}
$answers = \IPS\Db::i()->select( 'pid, @rownum := @rownum + 1 AS position', 'forums_posts', $where, 'new_topic DESC, post_bwoptions DESC, post_field_int DESC, post_date' )->join( array( '(SELECT @rownum := 0)', 'r' ), NULL, 'JOIN' );
$commentPosition = \IPS\Db::i()->select( 'position', $answers, array( 'pid=?', $comment->pid ) )->first() - 1;
}
/* Now work out what page that makes it */
$url = $item->url();
$perPage = $item::getCommentsPerPage();
$page = ceil( $commentPosition / $perPage );
if ( $page != 1 )
{
$url = $url->setQueryString( 'page', $page );
}
/* And redirect */
$idField = $commentClass::$databaseColumnId;
\IPS\Output::i()->redirect( $url->setFragment( 'comment-' . $comment->$idField ) );
}
/**
* Edit Comment/Review
@@ -914,7 +1006,8 @@ class _topic extends \IPS\Content\Controller
{
try
{
$comment = \IPS\forums\Topic\Post::load( \IPS\Request::i()->comment );
$commentClass = $class::$commentClass;
$comment = $commentClass::load( \IPS\Request::i()->comment );
$topic = \IPS\forums\Topic::load( $comment->topic_id );
\IPS\Output::i()->redirect( $topic->url()->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->comment ) ), NULL, 301 );
@@ -930,4 +1023,22 @@ class _topic extends \IPS\Content\Controller
\IPS\Output::i()->error( 'node_error', '2F173/I', 404, '' );
}
}
/**
* Form for splitting
*
* @param \IPS\Content\Item $item The item
* @return \IPS\Helpers\Form
*/
protected function _splitForm( \IPS\Content\Item $item )
{
$form = parent::_splitForm( $item );
if ( isset( $form->elements['']['topic_create_state'] ) )
{
unset( $form->elements['']['topic_create_state'] );
}
return $form;
}
}