Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\admin\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _forums extends \IPS\Node\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Node Class
|
||||
*/
|
||||
@@ -117,6 +122,11 @@ class _forums extends \IPS\Node\Controller
|
||||
return parent::permissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to add/edit a forum
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
parent::form();
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Feeds
|
||||
* @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
|
||||
* @subpackage Forums
|
||||
* @since 04 Feb 2014
|
||||
*/
|
||||
|
||||
namespace IPS\forums\modules\admin\forums;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* rss
|
||||
*/
|
||||
class _rss extends \IPS\Node\Controller
|
||||
{
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rss_manage' );
|
||||
parent::execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Node Class
|
||||
*/
|
||||
protected $nodeClass = '\IPS\forums\Feed';
|
||||
|
||||
/**
|
||||
* Get Root Buttons
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function _getRootButtons()
|
||||
{
|
||||
$buttons = parent::_getRootButtons();
|
||||
|
||||
if ( isset( \IPS\Output::i()->sidebar['actions']['add'] ) )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['add']['link'] = \IPS\Output::i()->sidebar['actions']['add']['link']->setQueryString( '_new', TRUE );
|
||||
}
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add/Edit Form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
$nodeClass = $this->nodeClass;
|
||||
if ( !\IPS\Request::i()->id and $nodeClass::canAddRoot() )
|
||||
{
|
||||
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( array(
|
||||
'rss_import_url' => function( $data )
|
||||
{
|
||||
$form = new \IPS\Helpers\Form( 'form', 'continue' );
|
||||
$form->add( new \IPS\Helpers\Form\Url( 'rss_import_url', NULL, TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'rss_import_auth_user' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Password( 'rss_import_auth_pass' ) );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$request = $values['rss_import_url']->request();
|
||||
|
||||
if ( $values['rss_import_auth_user'] or $values['rss_import_auth_pass'] )
|
||||
{
|
||||
$request = $request->login( $values['rss_import_auth_user'], $values['rss_import_auth_pass'] );
|
||||
}
|
||||
|
||||
$response = $request->get();
|
||||
|
||||
if ( $response->httpResponseCode == 401 )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'rss_import_auth' );
|
||||
return $form;
|
||||
}
|
||||
|
||||
$response = $response->decodeXml();
|
||||
if ( !( $response instanceof \IPS\Xml\Rss ) and !( $response instanceof \IPS\Xml\Atom ) )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'rss_import_invalid' );
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
catch ( \IPS\Http\Request\Exception $e )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'form_url_bad' );
|
||||
return $form;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'rss_import_invalid' );
|
||||
return $form;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
return $form;
|
||||
},
|
||||
'rss_import_preview' => function( $data )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->continue ) )
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
$request = \IPS\Http\Url::external( $data['rss_import_url'] )->request();
|
||||
if ( $data['rss_import_auth_user'] or $data['rss_import_auth_pass'] )
|
||||
{
|
||||
$request = $request->login( $data['rss_import_auth_user'], $data['rss_import_auth_pass'] );
|
||||
}
|
||||
return \IPS\Theme::i()->getTemplate( 'feeds' )->importPreview( $request->get()->decodeXml()->articles() );
|
||||
},
|
||||
'rss_import_details' => function ( $data )
|
||||
{
|
||||
$request = \IPS\Http\Url::external( $data['rss_import_url'] )->request();
|
||||
if ( $data['rss_import_auth_user'] or $data['rss_import_auth_pass'] )
|
||||
{
|
||||
$request = $request->login( $data['rss_import_auth_user'], $data['rss_import_auth_pass'] );
|
||||
}
|
||||
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->add( new \IPS\Helpers\Form\Node( 'rss_import_forum_id', NULL, TRUE, array( 'class' => 'IPS\forums\Forum', 'permissionCheck' => function ( $forum )
|
||||
{
|
||||
return $forum->sub_can_post and !$forum->redirect_url;
|
||||
} ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Member( 'rss_import_mid', \IPS\Member::loggedIn(), TRUE, array(), function( $val ){
|
||||
if( !is_array( $val ) )
|
||||
{
|
||||
$val = array( $val );
|
||||
}
|
||||
|
||||
foreach( $val as $member )
|
||||
{
|
||||
if( $member instanceof \IPS\Member )
|
||||
{
|
||||
if( !$member->member_id )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'form_member_bad' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$testMember = \IPS\Member::load( $member );
|
||||
|
||||
if( !$testMember->member_id )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'form_member_bad' );
|
||||
}
|
||||
}
|
||||
}
|
||||
} ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'rss_import_showlink', \IPS\Member::loggedIn()->language()->addToStack('rss_import_showlink_default') ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_topic_open', NULL, FALSE, array( 'options' => array( 1 => 'unlocked', 0 => 'locked' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_topic_hide', NULL, FALSE, array( 'options' => array( 0 => 'unhidden', 1 => 'hidden' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'rss_import_topic_pre', NULL, FALSE, array( 'trim' => FALSE ) ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$import = new \IPS\forums\Feed;
|
||||
$import->enabled = TRUE;
|
||||
$import->title = $request->get()->decodeXml()->title();
|
||||
$import->url = (string) $data['rss_import_url'];
|
||||
$import->forum_id = $values['rss_import_forum_id']->_id;
|
||||
$import->mid = $values['rss_import_mid']->member_id;
|
||||
$import->pergo = 10;
|
||||
$import->time = 30;
|
||||
$import->showlink = $values['rss_import_showlink'];
|
||||
$import->topic_open = $values['rss_import_topic_open'];
|
||||
$import->topic_hide = $values['rss_import_topic_hide'];
|
||||
$import->topic_pre = $values['rss_import_topic_pre'];
|
||||
$import->auth = ( $data['rss_import_auth_user'] or $data['rss_import_auth_pass'] );
|
||||
$import->auth_user = ( $data['rss_import_auth_user'] or $data['rss_import_auth_pass'] ) ? $data['rss_import_auth_user'] : NULL;
|
||||
$import->auth_pass = ( $data['rss_import_auth_user'] or $data['rss_import_auth_pass'] ) ? $data['rss_import_auth_pass'] : NULL;
|
||||
$import->save();
|
||||
try
|
||||
{
|
||||
$import->run();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'rss_run_error', '3F181/3', 500, '' );
|
||||
}
|
||||
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( '`key`=?', 'rssimport' ) );
|
||||
\IPS\Session::i()->log( 'acplog__node_created', array( (string) $import->title => TRUE, (string) $import->title => FALSE ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=forums&module=forums&controller=rss' ) );
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
), \IPS\Http\Url::internal('app=forums&module=forums&controller=rss&do=form') );
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::form();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'rss_run' );
|
||||
|
||||
try
|
||||
{
|
||||
$feed = \IPS\forums\Feed::load( \IPS\Request::i()->id );
|
||||
$feed->run();
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2F181/1', 404, '' );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->error( 'rss_run_error', '3F181/2', 500, '' );
|
||||
}
|
||||
|
||||
\IPS\Session::i()->log( 'acplog__rss_ran', array( $feed->title => FALSE ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=forums&module=forums&controller=rss' ) );
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\admin\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _savedActions extends \IPS\Node\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Node Class
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\admin\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _settings extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Manage Settings
|
||||
*
|
||||
@@ -43,7 +48,8 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
|
||||
$activeTab = \IPS\Request::i()->tab ?: 'settings';
|
||||
$activeTabContents = call_user_func( array( $this, 'manage' . mb_ucfirst( $activeTab ) ) );
|
||||
$methodFunction = 'manage' . mb_ucfirst( $activeTab );
|
||||
$activeTabContents = $this->$methodFunction();
|
||||
|
||||
if( \IPS\Request::i()->isAjax() and !isset( \IPS\Request::i()->ajaxValidate ) )
|
||||
{
|
||||
@@ -64,7 +70,24 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
protected function manageArchiving()
|
||||
{
|
||||
\IPS\Dispatcher::i()->checkAcpPermission( 'archive_manage' );
|
||||
|
||||
|
||||
if ( \IPS\CIC2 )
|
||||
{
|
||||
return \IPS\Cicloud\getForumArchiveForm();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->manageArchivingForm();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Archive settings
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function manageArchivingForm()
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_settings.js', 'forums', 'admin' ) );
|
||||
|
||||
/* Init */
|
||||
@@ -172,7 +195,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
'archive_topic_starter_not',
|
||||
'form_header_archive_topics_where',
|
||||
'form_header_archive_topics_not_where'
|
||||
),
|
||||
)
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'archive_storage_location', \IPS\Settings::i()->archive_remote_sql_host ? 'remote' : 'local', FALSE, array(
|
||||
@@ -187,6 +210,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'archive_sql_port', \IPS\Settings::i()->archive_sql_port ?: ini_get('mysqli.default_port'), FALSE, array(), NULL, NULL, NULL, 'archive_sql_port' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'archive_sql_socket', \IPS\Settings::i()->archive_sql_socket ?: ini_get('mysqli.default_socket'), FALSE, array(), NULL, NULL, NULL, 'archive_sql_socket' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'archive_sql_tbl_prefix', \IPS\Settings::i()->archive_sql_tbl_prefix ?: NULL, FALSE, array(), NULL, NULL, NULL, 'archive_sql_tbl_prefix' ) );
|
||||
|
||||
|
||||
$form->addHeader( 'archive_topics_where' );
|
||||
$form->add( new \IPS\Helpers\Form\Custom( 'archive_last_post', isset( $existingValues['archive_last_post'] ) ? $existingValues['archive_last_post'] : array( '>', 0, 'm', TRUE ), FALSE, array( 'getHtml' => array( $this, '_beforeAfterTimeAgo' ), 'validate' => array( $this, '_validateBeforeAfterTimeAgo' ) ), NULL, NULL, NULL, 'archive_last_post' ) );
|
||||
@@ -221,7 +245,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
$rules = array();
|
||||
foreach ( $values as $k => $v )
|
||||
{
|
||||
if ( in_array( $k, array( 'archive_last_post' ) ) )
|
||||
if ( \in_array( $k, array( 'archive_last_post' ) ) )
|
||||
{
|
||||
if ( ( !isset( $v[3] ) or !$v[3] ) and $v[1] )
|
||||
{
|
||||
@@ -236,7 +260,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif ( in_array( $k, array( 'archive_not_last_post' ) ) )
|
||||
elseif ( \in_array( $k, array( 'archive_not_last_post' ) ) )
|
||||
{
|
||||
if ( ( !isset( $v[3] ) or !$v[3] ) and $v[1] )
|
||||
{
|
||||
@@ -251,7 +275,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif( in_array( $k, array( 'archive_topic_forums' ) ) )
|
||||
elseif( \in_array( $k, array( 'archive_topic_forums' ) ) )
|
||||
{
|
||||
if ( !empty( $v ) )
|
||||
{
|
||||
@@ -266,7 +290,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif( in_array( $k, array( 'archive_topic_not_forums' ) ) )
|
||||
elseif( \in_array( $k, array( 'archive_topic_not_forums' ) ) )
|
||||
{
|
||||
if ( !empty( $v ) )
|
||||
{
|
||||
@@ -281,9 +305,9 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif ( in_array( $k, array( 'archive_topic_pinned', 'archive_topic_featured', 'archive_topic_state', 'archive_topic_approved', 'archive_topic_poll' ) ) )
|
||||
elseif ( \in_array( $k, array( 'archive_topic_pinned', 'archive_topic_featured', 'archive_topic_state', 'archive_topic_approved', 'archive_topic_poll' ) ) )
|
||||
{
|
||||
if ( !empty( $v ) and count( $v ) == 1 )
|
||||
if ( !empty( $v ) and \count( $v ) == 1 )
|
||||
{
|
||||
$rules[] = array(
|
||||
'archive_key' => md5( "forums_{$k}" ),
|
||||
@@ -296,9 +320,9 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif( in_array( $k, array( 'archive_topic_post', 'archive_topic_view', 'archive_topic_rating' ) ) )
|
||||
elseif( \in_array( $k, array( 'archive_topic_post', 'archive_topic_view', 'archive_topic_rating' ) ) )
|
||||
{
|
||||
if ( !isset( $v[2] ) and $v[1] )
|
||||
if ( !isset( $v[2] ) and $v[1] and $v[0] )
|
||||
{
|
||||
$rules[] = array(
|
||||
'archive_key' => md5( "forums_{$k}" ),
|
||||
@@ -311,9 +335,9 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif( in_array( $k, array( 'archive_not_topic_post', 'archive_not_topic_view', 'archive_not_topic_rating' ) ) )
|
||||
elseif( \in_array( $k, array( 'archive_not_topic_post', 'archive_not_topic_view', 'archive_not_topic_rating' ) ) )
|
||||
{
|
||||
if ( !isset( $v[2] ) and $v[1] )
|
||||
if ( !isset( $v[2] ) and $v[1] and $v[0] )
|
||||
{
|
||||
$rules[] = array(
|
||||
'archive_key' => md5( "forums_{$k}" ),
|
||||
@@ -326,9 +350,9 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif( in_array( $k, array( 'archive_topic_starter' ) ) )
|
||||
elseif( \in_array( $k, array( 'archive_topic_starter' ) ) )
|
||||
{
|
||||
if ( is_array( $v ) and count( $v ) )
|
||||
if ( \is_array( $v ) and \count( $v ) )
|
||||
{
|
||||
$ids = array();
|
||||
foreach( $v AS $member )
|
||||
@@ -347,9 +371,9 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
);
|
||||
}
|
||||
}
|
||||
elseif( in_array( $k, array( 'archive_topic_starter_not' ) ) )
|
||||
elseif( \in_array( $k, array( 'archive_topic_starter_not' ) ) )
|
||||
{
|
||||
if ( is_array( $v ) AND count( $v ) )
|
||||
if ( \is_array( $v ) AND \count( $v ) )
|
||||
{
|
||||
$ids = array();
|
||||
foreach( $v AS $member )
|
||||
@@ -431,7 +455,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
$form->saveAsSettings( $settingValues );
|
||||
|
||||
\IPS\Db::i()->delete( 'forums_archive_rules' );
|
||||
if ( count( $rules ) )
|
||||
if ( \count( $rules ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'forums_archive_rules', $rules );
|
||||
}
|
||||
@@ -531,6 +555,8 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
|
||||
if ( isset( \IPS\Request::i()->confirm ) )
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
if ( \IPS\Settings::i()->archive_on )
|
||||
{
|
||||
$whereClause = \IPS\Db::i()->compileWhereClause( \IPS\Application::load('forums')->archiveWhere( \IPS\Db::i()->select( '*', 'forums_archive_rules' ) ) );
|
||||
@@ -552,7 +578,7 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->decision( 'uanrchive_settings_change', array(
|
||||
'restore_unmatched_settings' => \IPS\Http\Url::internal( 'app=forums&module=forums&controller=settings&do=unarchive&confirm=1' ),
|
||||
'restore_unmatched_settings' => \IPS\Http\Url::internal( 'app=forums&module=forums&controller=settings&do=unarchive&confirm=1' )->csrf(),
|
||||
'leave_archived_topics' => \IPS\Http\Url::internal( 'app=forums&module=forums&controller=settings&tab=archiving' ),
|
||||
) );
|
||||
}
|
||||
@@ -590,13 +616,31 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
'fluid' => 'forums_default_view_fluid'
|
||||
)
|
||||
), function( $value ) {
|
||||
if( $value !== '*' AND count( $value ) !== 0 AND count( $value ) < 2 )
|
||||
if( $value !== '*' AND \count( $value ) !== 0 AND \count( $value ) < 2 )
|
||||
{
|
||||
throw new \DomainException( 'forums_default_view_choose_error' );
|
||||
}
|
||||
} ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'forums_topics_per_page', \IPS\Settings::i()->forums_topics_per_page , TRUE, array( 'min' => 5, 'max' => 100 ) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'forums_view_list_method', \IPS\Settings::i()->forums_view_list_method, FALSE, array(
|
||||
'options' => array(
|
||||
'list' => 'forums_topic_list_list',
|
||||
'snippet' => 'forums_topic_list_snippet'
|
||||
),
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'forums_view_list_choose', \IPS\Settings::i()->forums_view_list_choose, FALSE, array(), NULL, NULL, NULL, 'forums_view_list_choose' ) );
|
||||
|
||||
$form->addHeader('question_settings');
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'forums_questions_downvote', \IPS\Settings::i()->forums_questions_downvote ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'forums_answers_downvote', \IPS\Settings::i()->forums_answers_downvote ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'forums_new_questions', \IPS\Settings::i()->forums_new_questions, FALSE, array( 'options' => array( '0' => 'forums_new_questions_best', '1' => 'forums_new_questions_any' ) ) ) );
|
||||
|
||||
$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 ) use ( $popularNowMaximum )
|
||||
@@ -606,18 +650,38 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
/* If popular now time is greater than 10,000 days */
|
||||
'validate' => function( $obj ) use ( $popularNowMaximum )
|
||||
{
|
||||
if( $obj->value['minutes'] > $popularNowMaximum )
|
||||
|
||||
if( isset( $obj->value['minutes'] ) AND $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 ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'forums_topics_per_page', \IPS\Settings::i()->forums_topics_per_page , TRUE, array( 'min' => 5, 'max' => 100 ) ) );
|
||||
$form->addHeader('question_settings');
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'forums_questions_downvote', \IPS\Settings::i()->forums_questions_downvote ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'forums_answers_downvote', \IPS\Settings::i()->forums_answers_downvote ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'forums_new_questions', \IPS\Settings::i()->forums_new_questions, FALSE, array( 'options' => array( '0' => 'forums_new_questions_best', '1' => 'forums_new_questions_any' ) ) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'forums_topics_show_meta', \IPS\Settings::i()->forums_topics_show_meta ? json_decode( \IPS\Settings::i()->forums_topics_show_meta, TRUE ) : array(), FALSE, array(
|
||||
'options' => array(
|
||||
'time' => 'forums_topic_show_meta_time',
|
||||
'moderation' => 'forums_topic_show_meta_moderation'
|
||||
) ) ) );
|
||||
|
||||
$form->addHeader('topic_summary_settings');
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'forums_topic_activity', \IPS\Settings::i()->forums_topic_activity ? json_decode( \IPS\Settings::i()->forums_topic_activity, TRUE ) : NULL, FALSE, array(
|
||||
'options' => array( 'desktop' => 'forums_topic_activity_desktop_on', 'mobile' => 'forums_topic_activity_mobile_on' ),
|
||||
'toggles' => array( 'desktop' => array( 'forums_topic_activity_desktop' ) )
|
||||
) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'forums_topic_activity_desktop', \IPS\Settings::i()->forums_topic_activity_desktop, FALSE, array( 'options' => array( 'sidebar' => 'forums_topic_activity_desktop_sidebar', 'post' => 'forums_topic_activity_desktop_post' ) ), NULL, NULL, NULL, 'forums_topic_activity_desktop' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Number( 'forums_topics_activity_pages_show', \IPS\Settings::i()->forums_topics_activity_pages_show , TRUE, array( 'unlimited' => 0, 'unlimitedLang'=> 'forums_topics_activity_pages_show_unlimited', 'min' => 0, 'max' => 100 ), NULL, \IPS\Member::loggedIn()->language()->addToStack('forums_topics_activity_pages_show_prefix') ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'forums_topic_activity_features', \IPS\Settings::i()->forums_topic_activity_features ? json_decode( \IPS\Settings::i()->forums_topic_activity_features, TRUE ) : array(), FALSE, array(
|
||||
'options' => array(
|
||||
'popularDays' => 'forums_topic_activity_features_popularDays',
|
||||
'topPost' => 'forums_topic_activity_features_topPost',
|
||||
'uploads' => 'forums_topic_activity_features_uploads'
|
||||
) ) ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
@@ -632,7 +696,22 @@ class _settings extends \IPS\Dispatcher\Controller
|
||||
|
||||
if ( isset( $values['forums_default_view_choose'] ) )
|
||||
{
|
||||
$values['forums_default_view_choose'] = ( is_array( $values['forums_default_view_choose'] ) AND !count( $values['forums_default_view_choose'] ) ) ? NULL : json_encode( $values['forums_default_view_choose'] );
|
||||
$values['forums_default_view_choose'] = ( \is_array( $values['forums_default_view_choose'] ) AND !\count( $values['forums_default_view_choose'] ) ) ? NULL : json_encode( $values['forums_default_view_choose'] );
|
||||
}
|
||||
|
||||
if ( isset( $values['forums_topic_activity'] ) )
|
||||
{
|
||||
$values['forums_topic_activity'] = json_encode( $values['forums_topic_activity'] );
|
||||
}
|
||||
|
||||
if ( isset( $values['forums_topic_activity_features'] ) )
|
||||
{
|
||||
$values['forums_topic_activity_features'] = json_encode( $values['forums_topic_activity_features'] );
|
||||
}
|
||||
|
||||
if ( isset( $values['forums_topics_show_meta'] ) )
|
||||
{
|
||||
$values['forums_topics_show_meta'] = json_encode( $values['forums_topics_show_meta'] );
|
||||
}
|
||||
|
||||
$form->saveAsSettings( $values );
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\admin\stats;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _posts extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Manage
|
||||
*
|
||||
@@ -59,7 +64,6 @@ class _posts extends \IPS\Dispatcher\Controller
|
||||
'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',
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\admin\stats;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -23,6 +23,11 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _topics extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Has been CSRF-protected
|
||||
*/
|
||||
public static $csrfProtected = TRUE;
|
||||
|
||||
/**
|
||||
* Manage
|
||||
*
|
||||
@@ -62,7 +67,6 @@ class _topics extends \IPS\Dispatcher\Controller
|
||||
'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',
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\front\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\front\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -23,13 +23,15 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _forums extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
protected $themeGroup = NULL;
|
||||
|
||||
/**
|
||||
* Route
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
{
|
||||
$forum = NULL;
|
||||
try
|
||||
{
|
||||
@@ -49,6 +51,10 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
*/
|
||||
public function _forum( $forum )
|
||||
{
|
||||
$this->themeGroup = \IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' );
|
||||
|
||||
$forum->clubCheckRules();
|
||||
|
||||
/* Is simple mode on? If so, redirect to the index page */
|
||||
if ( \IPS\forums\Forum::isSimpleView( $forum ) )
|
||||
{
|
||||
@@ -77,31 +83,40 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
|
||||
/* Users can see topics posted by other users? */
|
||||
$where = array();
|
||||
if ( !$forum->can_view_others and !\IPS\Member::loggedIn()->modPermission( 'can_read_all_topics' ) )
|
||||
if ( !$forum->memberCanAccessOthersTopics( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
$where[] = array( 'starter_id = ?', \IPS\Member::loggedIn()->member_id );
|
||||
}
|
||||
|
||||
|
||||
$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 );
|
||||
$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( \IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' ), 'questionRow' );
|
||||
$table->rowsTemplate = array( $this->themeGroup, 'questionRow' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' ), 'topicRow' );
|
||||
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 we actually don't want the nav */
|
||||
if ( \IPS\forums\Forum::theOnlyForum() )
|
||||
/* 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();
|
||||
}
|
||||
@@ -158,6 +173,15 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
|
||||
$table->sortOptions['question_rating'] = 'forums_topics.question_rating';
|
||||
}
|
||||
else if ( $forum->forums_bitoptions['bw_enable_answers_moderator'] )
|
||||
{
|
||||
$table->filters = array(
|
||||
'solved_topics' => 'topic_answered_pid>0',
|
||||
'unsolved_topics' => 'topic_answered_pid=0',
|
||||
);
|
||||
|
||||
$table->sortOptions['question_rating'] = 'forums_topics.question_rating';
|
||||
}
|
||||
|
||||
/* Are we a moderator? */
|
||||
if( \IPS\forums\Topic::modPermission( 'unhide', NULL, $forum ) )
|
||||
@@ -318,6 +342,14 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/* Show the link */
|
||||
$rssUrl = \IPS\Http\Url::internal( "app=forums&module=forums&controller=forums&id={$forum->_id}&rss=1", 'front', 'forums_rss', array( $forum->name_seo ) );
|
||||
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$key = md5( ( \IPS\Member::loggedIn()->members_pass_hash ?: \IPS\Member::loggedIn()->email ) . \IPS\Member::loggedIn()->members_pass_salt );
|
||||
|
||||
$rssUrl = $rssUrl->setQueryString( array( 'member' => \IPS\Member::loggedIn()->member_id , 'key' => $key ) );
|
||||
}
|
||||
|
||||
if ( $forum->forums_bitoptions['bw_enable_answers'] )
|
||||
{
|
||||
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_questions', FALSE, array( 'escape' => true, 'sprintf' => array( $forum->_title ) ) );
|
||||
@@ -327,49 +359,17 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_topics', FALSE, array( 'escape' => true, 'sprintf' => array( $forum->_title ) ) );
|
||||
}
|
||||
\IPS\Output::i()->rssFeeds[ $rssTitle ] = $rssUrl;
|
||||
|
||||
/* Or actually show RSS feed */
|
||||
if ( isset( \IPS\Request::i()->rss ) )
|
||||
{
|
||||
/* Set the title, either topics or questions */
|
||||
if ( $forum->forums_bitoptions['bw_enable_answers'] )
|
||||
{
|
||||
$rssTitle = sprintf( \IPS\Member::loggedIn()->language()->get( 'forum_rss_title_questions'), \IPS\Member::loggedIn()->language()->get( "forums_forum_{$forum->id}" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$rssTitle = sprintf( \IPS\Member::loggedIn()->language()->get( 'forum_rss_title_topics'), \IPS\Member::loggedIn()->language()->get( "forums_forum_{$forum->id}" ) );
|
||||
}
|
||||
|
||||
/* Don't include "moved" links in the RSS feed, as there is no content to include ( $topic->content() results in BadMethodCallException) */
|
||||
$table->where[] = array( 'forums_topics.moved_to IS NULL' );
|
||||
|
||||
/* Can we view the content (permission_showtopic may allow us to view the list, but not the content)? */
|
||||
$canViewContent = $forum->can('read');
|
||||
|
||||
/* Build the document */
|
||||
$document = \IPS\Xml\Rss::newDocument( $forum->url(), $rssTitle, $rssTitle );
|
||||
foreach ( $table->getRows( array() ) as $topic )
|
||||
{
|
||||
if ( !$topic->hidden() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$document->addItem( $topic->title, $topic->url(), $canViewContent ? $topic->content() : NULL, \IPS\DateTime::ts( $topic->start_date ), $topic->tid );
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
/* Display - note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
|
||||
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml' );
|
||||
}
|
||||
}
|
||||
|
||||
/* Online User Location */
|
||||
$permissions = $forum->permissions();
|
||||
\IPS\Session::i()->setLocation( $forum->url(), explode( ",", $permissions['perm_view'] ), 'loc_forums_viewing_forum', array( "forums_forum_{$forum->id}" => TRUE ) );
|
||||
|
||||
|
||||
if ( \IPS\forums\Forum::getMemberView() === 'grid' )
|
||||
{
|
||||
\IPS\forums\Forum::populateFollowerCounts( $forum );
|
||||
}
|
||||
|
||||
/* Show Forum */
|
||||
if ( isset( \IPS\Request::i()->advancedSearchForm ) )
|
||||
{
|
||||
@@ -408,8 +408,8 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
$forumOutput = (string) $table;
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forums' )->forumDisplay( $forum, $forumOutput );
|
||||
|
||||
\IPS\Output::i()->output = $this->themeGroup->forumDisplay( $forum, $forumOutput );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,20 +465,24 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
$form = \IPS\forums\Topic::create( $forum );
|
||||
|
||||
$hasModOptions = false;
|
||||
|
||||
|
||||
$canHide = ( \IPS\Member::loggedIn()->group['g_hide_own_posts'] == '1' or \in_array( 'IPS\forums\Topics', explode( ',', \IPS\Member::loggedIn()->group['g_hide_own_posts'] ) ) );
|
||||
if ( \IPS\forums\Topic::modPermission( 'lock', NULL, $forum ) or
|
||||
\IPS\forums\Topic::modPermission( 'pin', NULL, $forum ) or
|
||||
\IPS\forums\Topic::modPermission( 'hide', NULL, $forum ) or
|
||||
$canHide or
|
||||
\IPS\forums\Topic::modPermission( 'feature', NULL, $forum ) )
|
||||
{
|
||||
$hasModOptions = TRUE;
|
||||
}
|
||||
|
||||
$formTemplate = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'submit', 'forums' ) ), 'createTopicForm' ), $forum, $hasModOptions, NULL );
|
||||
$formTemplate = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'submit', 'forums' ), 'createTopicForm' ), $forum, $hasModOptions, NULL );
|
||||
|
||||
if ( \IPS\forums\Topic::moderateNewItems( \IPS\Member::loggedIn(), $forum ) )
|
||||
$guestPostBeforeRegister = ( !\IPS\Member::loggedIn()->member_id ) ? !$forum->can( 'add', \IPS\Member::loggedIn(), FALSE ) : NULL;
|
||||
$modQueued = \IPS\forums\Topic::moderateNewItems( \IPS\Member::loggedIn(), $forum, $guestPostBeforeRegister );
|
||||
if ( $guestPostBeforeRegister or $modQueued )
|
||||
{
|
||||
$formTemplate = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->modQueueMessage( \IPS\Member::loggedIn()->warnings( 5, NULL, 'mq' ), \IPS\Member::loggedIn()->mod_posts ) . $formTemplate;
|
||||
$formTemplate = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->postingInformation( $guestPostBeforeRegister, $modQueued, TRUE ) . $formTemplate;
|
||||
}
|
||||
|
||||
$title = $forum->forums_bitoptions['bw_enable_answers'] ? 'ask_new_question' : 'create_new_topic';
|
||||
@@ -564,6 +568,27 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2F173/3', 403, 'no_module_permission_guest' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the viewing method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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_list_view', $method, ( new \IPS\DateTime )->add( new \DateInterval( 'P1Y' ) ) );
|
||||
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'forums_view_method', array( 'member_id' => \IPS\Member::loggedIn()->member_id, 'method' => $method, 'type' => 'list' ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\forums\Forum::load( \IPS\Request::i()->id )->url() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the forum selector for creating a topic outside of specific forum
|
||||
@@ -603,4 +628,4 @@ class _forums extends \IPS\Dispatcher\Controller
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'select_forum' ) );
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forums' )->forumSelector( $form );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\front\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -116,7 +116,7 @@ class _index extends \IPS\Dispatcher\Controller
|
||||
if ( \IPS\forums\Forum::isSimpleView() )
|
||||
{
|
||||
$where = array( 'container' => array( array( 'forums_forums.password IS NULL' ) ) );
|
||||
if ( !\IPS\Settings::i()->club_nodes_in_apps )
|
||||
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' );
|
||||
}
|
||||
@@ -134,7 +134,7 @@ class _index extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
|
||||
/* Inline forum IDs? */
|
||||
if ( count( $ids ) )
|
||||
if ( \count( $ids ) )
|
||||
{
|
||||
foreach( $ids as $id )
|
||||
{
|
||||
@@ -142,7 +142,7 @@ class _index extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
if ( $id == 'clubs' )
|
||||
{
|
||||
$parentIds['clubs'] = 'clubs';
|
||||
$map['clubs'] = 'clubs';
|
||||
foreach ( \IPS\forums\Forum::clubNodes() as $child )
|
||||
{
|
||||
$forumIds[ $child->id ] = $child->id;
|
||||
@@ -160,7 +160,7 @@ class _index extends \IPS\Dispatcher\Controller
|
||||
catch( \Exception $ex ) { }
|
||||
}
|
||||
|
||||
if ( count( $forumIds ) )
|
||||
if ( \count( $forumIds ) )
|
||||
{
|
||||
$where['container'][] = array( \IPS\Db::i()->in( 'forums_forums.id', array_filter( $forumIds ) ) );
|
||||
}
|
||||
@@ -181,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 );
|
||||
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'index' )->simplifiedViewSidebar( $forumIds, $map );
|
||||
}
|
||||
|
||||
if ( isset( $where['container'] ) )
|
||||
@@ -192,7 +192,12 @@ class _index extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Standard view */
|
||||
/* Merge in follower counts to the immediately visible forums */
|
||||
if ( \IPS\forums\Forum::getMemberView() === 'grid' )
|
||||
{
|
||||
\IPS\forums\Forum::populateFollowerCounts();
|
||||
}
|
||||
|
||||
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'index' )->index();
|
||||
}
|
||||
}
|
||||
@@ -212,7 +217,7 @@ class _index extends \IPS\Dispatcher\Controller
|
||||
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'forums_view_method', array( 'member_id' => \IPS\Member::loggedIn()->member_id, 'method' => $method ) );
|
||||
\IPS\Db::i()->replace( 'forums_view_method', array( 'member_id' => \IPS\Member::loggedIn()->member_id, 'method' => $method, 'type' => 'index' ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=forums&module=forums&controller=index', 'front', 'forums' ) );
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\modules\front\forums;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -42,21 +42,14 @@ class _topic extends \IPS\Content\Controller
|
||||
/**
|
||||
* View Topic
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function manage()
|
||||
{
|
||||
/* Load topic */
|
||||
$topic = parent::manage();
|
||||
\IPS\Member::loggedIn()->language()->words['submit_comment'] = \IPS\Member::loggedIn()->language()->addToStack( 'submit_reply', FALSE );
|
||||
|
||||
/* If there's only one forum we actually don't want the nav */
|
||||
if ( \IPS\forums\Forum::theOnlyForum() or \IPS\forums\Forum::isSimpleView() )
|
||||
{
|
||||
$topicBreadcrumb = array_pop( \IPS\Output::i()->breadcrumb );
|
||||
\IPS\Output::i()->breadcrumb = isset( \IPS\Output::i()->breadcrumb['module'] ) ? array( 'module' => \IPS\Output::i()->breadcrumb['module'] ) : array();
|
||||
\IPS\Output::i()->breadcrumb[] = $topicBreadcrumb;
|
||||
}
|
||||
|
||||
/* If it failed, it might be because we want a password */
|
||||
if ( $topic === NULL )
|
||||
@@ -91,6 +84,16 @@ class _topic extends \IPS\Content\Controller
|
||||
}
|
||||
}
|
||||
|
||||
$topic->container()->clubCheckRules();
|
||||
|
||||
/* If there's only one forum and we're not in a club, we actually don't want the nav */
|
||||
if ( !$topic->container()->club() AND ( \IPS\forums\Forum::theOnlyForum() or \IPS\forums\Forum::isSimpleView() ) )
|
||||
{
|
||||
$topicBreadcrumb = array_pop( \IPS\Output::i()->breadcrumb );
|
||||
\IPS\Output::i()->breadcrumb = isset( \IPS\Output::i()->breadcrumb['module'] ) ? array( 'module' => \IPS\Output::i()->breadcrumb['module'] ) : array();
|
||||
\IPS\Output::i()->breadcrumb[] = $topicBreadcrumb;
|
||||
}
|
||||
|
||||
/* Legacy findpost redirect */
|
||||
if ( \IPS\Request::i()->findpost )
|
||||
{
|
||||
@@ -110,6 +113,18 @@ class _topic extends \IPS\Content\Controller
|
||||
$this->_doViewCheck();
|
||||
}
|
||||
|
||||
/* If the topic is locked and scheduled to unlock already, or vice versa, do that */
|
||||
if( $topic->locked() && $topic->topic_open_time && $topic->topic_open_time < time() )
|
||||
{
|
||||
$topic->state = 'open';
|
||||
$topic->save();
|
||||
}
|
||||
elseif( !$topic->locked() && $topic->topic_close_time && $topic->topic_close_time < time() )
|
||||
{
|
||||
$topic->state = 'closed';
|
||||
$topic->save();
|
||||
}
|
||||
|
||||
/* If this is an AJAX request fetch the comment form now. The HTML will be cached so calling here and then again in the template has no overhead
|
||||
and this is necessary if you entered into a topic with &queued_posts=1, approve the posts, then try to reply. Otherwise, clicking into the
|
||||
editor produces an error when the getUploader=1 call occurs, and submitting a reply results in an error. */
|
||||
@@ -127,33 +142,51 @@ class _topic extends \IPS\Content\Controller
|
||||
{
|
||||
$postClass = '\IPS\forums\Topic\ArchivedPost';
|
||||
}
|
||||
|
||||
$firstPost = $postClass::load( $topic->topic_firstpost );
|
||||
|
||||
$topicOverview = array( 'firstPost' => array( $topic->isQuestion() ? 'question_mainTab' : 'first_post', $firstPost ) );
|
||||
|
||||
if ( $topic->posts > 1 )
|
||||
/* If this topic was moved or merged, load that up in case someone loads the preview after that happens but before they reload the page */
|
||||
$previewTopic = $topic;
|
||||
if ( \in_array( $topic->state, array( 'merged', 'link' ) ) )
|
||||
{
|
||||
$latestPost = $topic->comments( 1, 0, 'date', 'DESC' );
|
||||
$topicOverview['latestPost'] = array( $topic->isQuestion() ? 'latest_answer' : 'latest_post', $latestPost );
|
||||
|
||||
$timeLastRead = $topic->timeLastRead();
|
||||
if ( $timeLastRead instanceof \IPS\DateTime AND $topic->unread() !== 0 )
|
||||
$movedTo = explode( '&', $topic->moved_to );
|
||||
|
||||
try
|
||||
{
|
||||
$firstUnread = $topic->comments( 1, NULL, 'date', 'asc', NULL, NULL, $timeLastRead );
|
||||
$previewTopic = \IPS\forums\Topic::loadAndCheckPerms( $movedTo[0] );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
/* I can't help you */
|
||||
\IPS\Output::i()->error( 'node_error', '2F173/Q', 404, '' );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$firstPost = $postClass::load( $previewTopic->topic_firstpost );
|
||||
|
||||
$topicOverview = array( 'firstPost' => array( $previewTopic->isQuestion() ? 'question_mainTab' : 'first_post', $firstPost ) );
|
||||
|
||||
if ( $previewTopic->posts > 1 )
|
||||
{
|
||||
$latestPost = $previewTopic->comments( 1, 0, 'date', 'DESC' );
|
||||
$topicOverview['latestPost'] = array( $previewTopic->isQuestion() ? 'latest_answer' : 'latest_post', $latestPost );
|
||||
|
||||
$timeLastRead = $previewTopic->timeLastRead();
|
||||
if ( $timeLastRead instanceof \IPS\DateTime AND $previewTopic->unread() !== 0 )
|
||||
{
|
||||
$firstUnread = $previewTopic->comments( 1, NULL, 'date', 'asc', NULL, NULL, $timeLastRead );
|
||||
if( $firstUnread instanceof \IPS\forums\Topic\Post AND $firstUnread->date !== $latestPost->date AND $firstUnread->date !== $firstPost->date )
|
||||
{
|
||||
$topicOverview['firstUnread'] = array( 'first_unread_post_hover', $topic->comments( 1, NULL, 'date', 'asc', NULL, NULL, $timeLastRead ) );
|
||||
$topicOverview['firstUnread'] = array( 'first_unread_post_hover', $previewTopic->comments( 1, NULL, 'date', 'asc', NULL, NULL, $timeLastRead ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $topic->isQuestion() and $topic->topic_answered_pid )
|
||||
if ( $previewTopic->isQuestion() and $previewTopic->topic_answered_pid )
|
||||
{
|
||||
$topicOverview['bestAnswer'] = array( 'best_answer_post', \IPS\forums\Topic\Post::load( $topic->topic_answered_pid ) );
|
||||
$topicOverview['bestAnswer'] = array( 'best_answer_post', \IPS\forums\Topic\Post::load( $previewTopic->topic_answered_pid ) );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'forums' )->topicHover( $topic, $topicOverview ) );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'forums' )->topicHover( $previewTopic, $topicOverview ) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -201,7 +234,7 @@ class _topic extends \IPS\Content\Controller
|
||||
}
|
||||
catch ( \UnderflowException $e ) { }
|
||||
|
||||
$page = ( isset( \IPS\Request::i()->page ) ) ? intval( \IPS\Request::i()->page ) : 1;
|
||||
$page = ( isset( \IPS\Request::i()->page ) ) ? \intval( \IPS\Request::i()->page ) : 1;
|
||||
|
||||
if( $page < 1 )
|
||||
{
|
||||
@@ -230,18 +263,13 @@ class _topic extends \IPS\Content\Controller
|
||||
$current = current( $comments );
|
||||
reset( $comments );
|
||||
|
||||
if( !count( $comments ) AND !$topic->isQuestion() )
|
||||
if( !\count( $comments ) AND !$topic->isQuestion() )
|
||||
{
|
||||
\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->metaDescription( isset( $_SESSION['_findComment'] ) ? NULL : ( $topic->isQuestion() ? $question->content() : $current->content() ) );
|
||||
|
||||
\IPS\Output::i()->metaTags['description'] = \IPS\Output::i()->metaTags['og:description'] = $metaDescription;
|
||||
|
||||
/* Mark read */
|
||||
if( !$topic->isLastPage() )
|
||||
if( !$topic->isLastPage() AND $topic->unread() !== 0 )
|
||||
{
|
||||
$maxTime = 0;
|
||||
|
||||
@@ -250,7 +278,10 @@ class _topic extends \IPS\Content\Controller
|
||||
$maxTime = ( $comment->mapped('date') > $maxTime ) ? $comment->mapped('date') : $maxTime;
|
||||
}
|
||||
|
||||
$topic->markRead( NULL, $maxTime );
|
||||
if( $topic->timeLastRead() === NULL OR $maxTime > $topic->timeLastRead()->getTimestamp() )
|
||||
{
|
||||
$topic->markRead( NULL, $maxTime );
|
||||
}
|
||||
}
|
||||
|
||||
$votes = array();
|
||||
@@ -267,79 +298,63 @@ class _topic extends \IPS\Content\Controller
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words[ 'topic__comment_placeholder' ] = \IPS\Member::loggedIn()->language()->addToStack( 'question__comment_placeholder', FALSE );
|
||||
}
|
||||
|
||||
|
||||
/* Online User Location */
|
||||
\IPS\Session::i()->setLocation( $topic->url(), ( $topic->container()->password or !$topic->container()->can_view_others or $topic->container()->min_posts_view ) ? 0 : $topic->onlineListPermissions(), 'loc_forums_viewing_topic', array( $topic->title => FALSE ) );
|
||||
|
||||
/* Next unread */
|
||||
try
|
||||
{
|
||||
$nextUnread = $topic->nextUnread();
|
||||
$nextUnread = $topic->containerHasUnread();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
$nextUnread = NULL;
|
||||
}
|
||||
|
||||
/* Add Json-LD */
|
||||
\IPS\Output::i()->jsonLd['topic'] = array(
|
||||
'@context' => "http://schema.org",
|
||||
'@type' => $topic->isQuestion() ? 'Question' : 'DiscussionForumPosting',
|
||||
'url' => (string) $topic->url(),
|
||||
'discussionUrl' => (string) $topic->url(),
|
||||
'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' => (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' => $topic->starter_name ?: \IPS\Member::load( $topic->starter_id )->name,
|
||||
'image' => \IPS\Member::load( $topic->starter_id )->get_photo()
|
||||
),
|
||||
'interactionStatistic' => array(
|
||||
array(
|
||||
'@type' => 'InteractionCounter',
|
||||
'interactionType' => "http://schema.org/ViewAction",
|
||||
'userInteractionCount' => $topic->views
|
||||
),
|
||||
array(
|
||||
'@type' => 'InteractionCounter',
|
||||
'interactionType' => "http://schema.org/CommentAction",
|
||||
'userInteractionCount' => $topic->posts
|
||||
),
|
||||
array(
|
||||
'@type' => 'InteractionCounter',
|
||||
'interactionType' => "http://schema.org/FollowAction",
|
||||
'userInteractionCount' => \IPS\forums\Topic::containerFollowerCount( $topic->container() )
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
/* Are ratings allowed? */
|
||||
if( !$topic->isArchived() AND $topic->container()->forum_allow_rating AND $topic->averageRating() )
|
||||
/* Sidebar? */
|
||||
if ( $topic->showSummaryOnDesktop() == 'sidebar' )
|
||||
{
|
||||
\IPS\Output::i()->jsonLd['topic']['aggregateRating'] = array(
|
||||
'@type' => 'AggregateRating',
|
||||
'ratingValue' => $topic->averageRating(),
|
||||
'ratingCount' => $topic->numberOfRatings(),
|
||||
);
|
||||
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'topics' )->activity( $topic, 'sidebar' );
|
||||
}
|
||||
|
||||
/* Add Json-LD */
|
||||
$isQuestion = ( $topic->isQuestion() or $topic->isSolved() );
|
||||
\IPS\Output::i()->jsonLd['topic'] = array(
|
||||
'@context' => "http://schema.org",
|
||||
'@type' => $isQuestion ? 'Question' : 'DiscussionForumPosting',
|
||||
'@id' => (string) $topic->url(),
|
||||
'isPartOf' => array(
|
||||
'@id' => \IPS\Settings::i()->base_url . '#website'
|
||||
),
|
||||
'publisher' => array(
|
||||
'@id' => \IPS\Settings::i()->base_url . '#organization'
|
||||
),
|
||||
'url' => (string) $topic->url(),
|
||||
'discussionUrl' => (string) $topic->url(),
|
||||
'mainEntityOfPage' => array(
|
||||
'@type' => 'WebPage',
|
||||
'@id' => (string) $topic->url()
|
||||
)
|
||||
);
|
||||
|
||||
/* 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();
|
||||
\IPS\Output::i()->jsonLd['topic']['author']['url'] = (string) \IPS\Member::load( $topic->starter_id )->url();
|
||||
|
||||
\IPS\Output::i()->jsonLd['topic']['publisher']['member'] = array(
|
||||
'@type' => "Person",
|
||||
'name' => \IPS\Member::load( $topic->starter_id )->name,
|
||||
'image' => (string) \IPS\Member::load( $topic->starter_id )->get_photo(),
|
||||
'url' => (string) \IPS\Member::load( $topic->starter_id )->url(),
|
||||
);
|
||||
}
|
||||
|
||||
if( $topic->isQuestion() )
|
||||
if( $isQuestion )
|
||||
{
|
||||
\IPS\Output::i()->jsonLd['topic']['answerCount'] = $topic->posts ? $topic->posts - 1 : 0;
|
||||
\IPS\Output::i()->jsonLd['topic']['upvoteCount'] = intval( $topic->question_rating );
|
||||
\IPS\Output::i()->jsonLd['topic']['upvoteCount'] = \intval( $topic->question_rating );
|
||||
|
||||
if( $topic->topic_answered_pid )
|
||||
{
|
||||
@@ -349,9 +364,8 @@ class _topic extends \IPS\Content\Controller
|
||||
|
||||
\IPS\Output::i()->jsonLd['topic']['acceptedAnswer'] = array(
|
||||
'@type' => 'Answer',
|
||||
'text' => strip_tags( $answer->truncated() ),
|
||||
'text' => $answer->truncated( TRUE, NULL ),
|
||||
'url' => (string) $answer->url(),
|
||||
'mainEntityOfPage' => (string) $topic->url(),
|
||||
'dateCreated' => \IPS\DateTime::ts( $answer->post_date )->format( \IPS\DateTime::ISO8601 ),
|
||||
'upvoteCount' => $answer->post_field_int,
|
||||
'author' => array(
|
||||
@@ -376,17 +390,24 @@ class _topic extends \IPS\Content\Controller
|
||||
$i = 0;
|
||||
foreach( $comments as $comment )
|
||||
{
|
||||
// Don't include the first post as a "comment"
|
||||
if( $comment->pid == $topic->topic_firstpost )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = $topic->url()->setPage( 'page', \IPS\Request::i()->page );
|
||||
\IPS\Output::i()->jsonLd['topic']['comment'][ $i ] = array(
|
||||
'@type' => 'Comment',
|
||||
'url' => (string) $comment->url(),
|
||||
'@id' => (string) $url->setFragment( 'comment-' . $comment->pid ),
|
||||
'url' => (string) $url->setFragment( 'comment-' . $comment->pid ),
|
||||
'author' => array(
|
||||
'@type' => 'Person',
|
||||
'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(),
|
||||
'text' => $comment->truncated( TRUE, NULL ),
|
||||
);
|
||||
|
||||
if( $comment->author_id )
|
||||
@@ -398,7 +419,43 @@ class _topic extends \IPS\Content\Controller
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->jsonLd['topic'] = array_merge_recursive( array(
|
||||
'name' => $topic->mapped('title'),
|
||||
'headline' => $topic->mapped('title'),
|
||||
'text' => $topic->isQuestion() ? $question->truncated( TRUE, NULL ) : $current->truncated( TRUE, NULL ),
|
||||
'dateCreated' => \IPS\DateTime::ts( $topic->start_date )->format( \IPS\DateTime::ISO8601 ),
|
||||
'datePublished' => \IPS\DateTime::ts( $topic->start_date )->format( \IPS\DateTime::ISO8601 ),
|
||||
'dateModified' => \IPS\DateTime::ts( $topic->last_post )->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' => (string) \IPS\Member::load( $topic->starter_id )->get_photo(),
|
||||
'author' => array(
|
||||
'@type' => 'Person',
|
||||
'name' => $topic->starter_name ?: \IPS\Member::load( $topic->starter_id )->name,
|
||||
'image' => \IPS\Member::load( $topic->starter_id )->get_photo()
|
||||
),
|
||||
'interactionStatistic' => array(
|
||||
array(
|
||||
'@type' => 'InteractionCounter',
|
||||
'interactionType' => "http://schema.org/ViewAction",
|
||||
'userInteractionCount' => $topic->views
|
||||
),
|
||||
array(
|
||||
'@type' => 'InteractionCounter',
|
||||
'interactionType' => "http://schema.org/CommentAction",
|
||||
'userInteractionCount' => $topic->posts - 1 // We subtract one to account for the "first post"
|
||||
),
|
||||
array(
|
||||
'@type' => 'InteractionCounter',
|
||||
'interactionType' => "http://schema.org/FollowAction",
|
||||
'userInteractionCount' => $topic->followersCount()
|
||||
),
|
||||
)
|
||||
), \IPS\Output::i()->jsonLd['topic'] );
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
|
||||
@@ -474,9 +531,8 @@ class _topic extends \IPS\Content\Controller
|
||||
$formElements = $class::formElements( $topic, $forum );
|
||||
|
||||
$hasModOptions = FALSE;
|
||||
|
||||
/* We used to just check against the ability to lock, however this may not be enough - a moderator could pin, for example, but not lock */
|
||||
foreach( array( 'lock', 'pin', 'hide', 'feature' ) AS $perm )
|
||||
foreach( array( 'lock', 'pin', 'feature' ) AS $perm )
|
||||
{
|
||||
if ( $class::modPermission( $perm, NULL, $forum ) )
|
||||
{
|
||||
@@ -484,19 +540,33 @@ class _topic extends \IPS\Content\Controller
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( $topic->canHide() )
|
||||
{
|
||||
$hasModOptions = TRUE;
|
||||
}
|
||||
|
||||
$form = $topic->buildEditForm();
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
if ( $topic->canEdit() )
|
||||
{
|
||||
{
|
||||
$titleField = $topic::$databaseColumnMap['title'];
|
||||
$oldTitle = $topic->$titleField;
|
||||
|
||||
$topic->processForm( $values );
|
||||
$topic->save();
|
||||
$topic->processAfterEdit( $values );
|
||||
|
||||
/* Moderator log */
|
||||
\IPS\Session::i()->modLog( 'modlog__item_edit', array( $topic::$title => FALSE, $topic->url()->__toString() => FALSE, $topic::$title => TRUE, $topic->mapped( 'title' ) => FALSE ), $topic );
|
||||
$toLog = array( $topic::$title => FALSE, $topic->url()->__toString() => FALSE, $topic::$title => TRUE, $topic->mapped( 'title' ) => FALSE );
|
||||
|
||||
if ( $oldTitle != $topic->$titleField )
|
||||
{
|
||||
$toLog[ $oldTitle ] = false;
|
||||
}
|
||||
|
||||
\IPS\Session::i()->modLog( 'modlog__item_edit', $toLog, $topic );
|
||||
|
||||
\IPS\Output::i()->redirect( $topic->url() );
|
||||
}
|
||||
@@ -506,7 +576,7 @@ class _topic extends \IPS\Content\Controller
|
||||
}
|
||||
}
|
||||
|
||||
$formTemplate = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'submit', 'forums' ) ), 'createTopicForm' ), $forum, $hasModOptions, $topic );
|
||||
$formTemplate = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'submit', 'forums' ), 'createTopicForm' ), $forum, $hasModOptions, $topic );
|
||||
|
||||
$title = $forum->forums_bitoptions['bw_enable_answers'] ? 'edit_question' : 'edit_topic';
|
||||
|
||||
@@ -614,7 +684,7 @@ class _topic extends \IPS\Content\Controller
|
||||
}
|
||||
|
||||
/* Voting up or down? */
|
||||
$rating = intval( \IPS\Request::i()->rating );
|
||||
$rating = \intval( \IPS\Request::i()->rating );
|
||||
if ( $rating !== 1 and $rating !== -1 )
|
||||
{
|
||||
\IPS\Output::i()->error( 'form_bad_value', '2F173/A', 403, '' );
|
||||
@@ -626,13 +696,15 @@ class _topic extends \IPS\Content\Controller
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2F173/9', 403, '' );
|
||||
}
|
||||
|
||||
/* If we have an existing vote, we're just undoing that, otherwise, insert the vote */
|
||||
/* If we have an existing vote, remove it first */
|
||||
$ratings = $question->votes();
|
||||
if ( isset( $ratings[ \IPS\Member::loggedIn()->member_id ] ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'forums_question_ratings', array( 'topic=? AND member=?', $question->tid, \IPS\Member::loggedIn()->member_id ) );
|
||||
\IPS\Db::i()->delete( 'forums_question_ratings', array( 'topic=? AND `member`=?', $question->tid, \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
else
|
||||
|
||||
/* Revoting for the same thing you already voted for should remove your vote - so don't insert if we voted for the same thing we did before */
|
||||
if ( !isset( $ratings[ \IPS\Member::loggedIn()->member_id ] ) OR $ratings[ \IPS\Member::loggedIn()->member_id ] != $rating )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'forums_question_ratings', array(
|
||||
'topic' => $question->tid,
|
||||
@@ -675,19 +747,19 @@ class _topic extends \IPS\Content\Controller
|
||||
\IPS\Output::i()->error( 'no_module_permission', '2F173/5', 403, '' );
|
||||
}
|
||||
|
||||
$rating = intval( \IPS\Request::i()->rating );
|
||||
$rating = \intval( \IPS\Request::i()->rating );
|
||||
if ( $rating !== 1 and $rating !== -1 )
|
||||
{
|
||||
\IPS\Output::i()->error( 'form_bad_value', '2F173/6', 403, '' );
|
||||
}
|
||||
|
||||
/* Have we already rated ? */
|
||||
try
|
||||
{
|
||||
$rating = \IPS\Db::i()->select( '*', 'forums_answer_ratings', array( 'topic=? AND post=? AND member=?', $question->tid, $answer->pid, \IPS\Member::loggedIn()->member_id ) )->first();
|
||||
\IPS\Db::i()->delete( 'forums_answer_ratings', array( 'topic=? AND post=? AND member=?', $question->tid, $answer->pid, \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
$ratings = $question->answerVotes( \IPS\Member::loggedIn() );
|
||||
|
||||
/* If we've already rated the answer, remove that first */
|
||||
\IPS\Db::i()->delete( 'forums_answer_ratings', array( 'topic=? AND post=? AND `member`=?', $question->tid, $answer->pid, \IPS\Member::loggedIn()->member_id ) );
|
||||
|
||||
/* Revoting for the same thing you already voted for should remove your vote - so don't insert if we voted for the same thing we did before */
|
||||
if ( !isset( $ratings[ $answer->pid ] ) OR $ratings[ $answer->pid ] != $rating )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'forums_answer_ratings', array(
|
||||
'post' => $answer->pid,
|
||||
@@ -723,12 +795,13 @@ class _topic extends \IPS\Content\Controller
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( \IPS\Request::i()->answer );
|
||||
|
||||
if ( !$topic->canSetBestAnswer() )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( \IPS\Request::i()->answer );
|
||||
if ( $post->item() != $topic )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
@@ -738,31 +811,23 @@ class _topic extends \IPS\Content\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2F173/7', 404, '' );
|
||||
}
|
||||
|
||||
if ( $topic->topic_answered_pid )
|
||||
|
||||
$topic->toggleSolveComment( $post->pid, TRUE );
|
||||
|
||||
if( $post->author()->member_id != \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
try
|
||||
{
|
||||
$oldBestAnswer = \IPS\forums\Topic\Post::load( $topic->topic_answered_pid );
|
||||
$oldBestAnswer->post_bwoptions['best_answer'] = FALSE;
|
||||
$oldBestAnswer->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'best_answer', $topic, array( $post ), array( $post->author()->member_id ) );
|
||||
$notification->recipients->attach( $post->author() );
|
||||
$notification->send();
|
||||
}
|
||||
|
||||
$post->post_bwoptions['best_answer'] = TRUE;
|
||||
$post->save();
|
||||
|
||||
$topic->topic_answered_pid = $post->pid;
|
||||
$topic->save();
|
||||
|
||||
/* Log */
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_set_best_answer') )
|
||||
{
|
||||
\IPS\Session::i()->modLog( 'modlog__best_answer_set', array( $post->pid => FALSE ), $topic );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( $topic->url() );
|
||||
\IPS\Output::i()->redirect( $post->url() );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -777,6 +842,8 @@ class _topic extends \IPS\Content\Controller
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( \IPS\Request::i()->answer );
|
||||
|
||||
if ( !$topic->canSetBestAnswer() )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
@@ -786,14 +853,17 @@ class _topic extends \IPS\Content\Controller
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2F173/G', 404, '' );
|
||||
}
|
||||
|
||||
|
||||
if ( $post->item() != $topic )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
if ( $topic->topic_answered_pid )
|
||||
{
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::load( $topic->topic_answered_pid );
|
||||
$post->post_bwoptions['best_answer'] = FALSE;
|
||||
$post->save();
|
||||
$topic->toggleSolveComment( $post->pid, FALSE );
|
||||
|
||||
if ( \IPS\Member::loggedIn()->modPermission('can_set_best_answer') )
|
||||
{
|
||||
@@ -803,10 +873,7 @@ class _topic extends \IPS\Content\Controller
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
$topic->topic_answered_pid = FALSE;
|
||||
$topic->save();
|
||||
|
||||
\IPS\Output::i()->redirect( $topic->url() );
|
||||
\IPS\Output::i()->redirect( $post->url() );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -885,7 +952,47 @@ class _topic extends \IPS\Content\Controller
|
||||
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'widgets', 'forums', 'front' )->poll( $topic, $poll );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show a single comment requested by ajax
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxShowComment()
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( ! \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( \IPS\Request::i()->id );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2F173/N', 403, '' );
|
||||
}
|
||||
|
||||
$comment = \IPS\forums\Topic\Post::load( \IPS\Request::i()->showComment );
|
||||
|
||||
if ( ! $comment->canView() )
|
||||
{
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( \IPS\Theme::i()->getTemplate( 'global', 'core' )->commentContainer( $topic, $comment ), 200, 'text/html' ) );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a Comment / Review (do=findComment/findReview)
|
||||
*
|
||||
@@ -949,7 +1056,7 @@ class _topic extends \IPS\Content\Controller
|
||||
$page = ceil( $commentPosition / $perPage );
|
||||
if ( $page != 1 )
|
||||
{
|
||||
$url = $url->setQueryString( 'page', $page );
|
||||
$url = $url->setPage( 'page', $page );
|
||||
}
|
||||
|
||||
/* And redirect */
|
||||
@@ -1042,4 +1149,20 @@ class _topic extends \IPS\Content\Controller
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split Comment
|
||||
*
|
||||
* @param string $commentClass The comment/review class
|
||||
* @param \IPS\Content\Comment $comment The comment/review
|
||||
* @param \IPS\Content\Item $item The item
|
||||
* @return void
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function _split( $commentClass, $comment, $item )
|
||||
{
|
||||
parent::_split( $commentClass, $comment, $item );
|
||||
|
||||
$item->rebuildPopularTime();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user