Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -16,19 +16,102 @@ namespace IPS\forums;
|
||||
*/
|
||||
class _Application extends \IPS\Application
|
||||
{
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
/* If the viewing member cannot view the board (ex: guests must login first), then send a 404 Not Found header here, before the Login page shows in the dispatcher */
|
||||
if ( !\IPS\Member::loggedIn()->group['g_view_board'] and ( \IPS\Request::i()->module == 'forums' and \IPS\Request::i()->controller == 'forums' and isset( \IPS\Request::i()->rss ) ) )
|
||||
/* Handle RSS requests */
|
||||
if ( \IPS\Request::i()->module == 'forums' and \IPS\Request::i()->controller == 'forums' and isset( \IPS\Request::i()->rss ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2F219/1', 404, '' );
|
||||
$member = NULL;
|
||||
if( \IPS\Request::i()->member AND \IPS\Request::i()->key )
|
||||
{
|
||||
$member = \IPS\Member::load( \IPS\Request::i()->member );
|
||||
if( !\IPS\Login::compareHashes( md5( ( $member->members_pass_hash ?: $member->email ) . $member->members_pass_salt ), (string) \IPS\Request::i()->key ) )
|
||||
{
|
||||
$member = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
$this->sendForumRss( $member ?? new \IPS\Member );
|
||||
|
||||
if( !\IPS\Member::loggedIn()->group['g_view_board'] )
|
||||
{
|
||||
\IPS\Output::i()->error( 'node_error', '2F219/1', 404, '' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the forum's RSS feed for the indicated member
|
||||
*
|
||||
* @param \IPS\Member $member Member
|
||||
* @return void
|
||||
*/
|
||||
protected function sendForumRss( $member )
|
||||
{
|
||||
try
|
||||
{
|
||||
$forum = \IPS\forums\Forum::load( \IPS\Request::i()->id );
|
||||
|
||||
if( !$forum->can( 'view', $member ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* We'll let the regular controller handle the error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* RSS feeds are not available if the setting is off, or there is nothing to include */
|
||||
if ( !\IPS\Settings::i()->forums_rss OR !$forum->topics )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Users can see topics posted by other users? Also, exclude moved links. */
|
||||
$where = array( array( 'forums_topics.moved_to IS NULL' ), array( 'forums_topics.forum_id=?', $forum->id ) );
|
||||
if ( !$forum->memberCanAccessOthersTopics( $member ) )
|
||||
{
|
||||
$where[] = array( 'starter_id = ?', $member->member_id );
|
||||
}
|
||||
|
||||
/* Init table (it won't show anything until after the password check, but it sets navigation and titles) */
|
||||
$iterator = \IPS\forums\Topic::getItemsWithPermission( $where, 'forums_topics.last_post DESC', \IPS\Settings::i()->forums_topics_per_page, 'view', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY, 0, $member, FALSE, FALSE, FALSE, FALSE, NULL, $forum, TRUE, TRUE, TRUE, FALSE );
|
||||
|
||||
/* Set the title, either topics or questions */
|
||||
if ( $forum->forums_bitoptions['bw_enable_answers'] )
|
||||
{
|
||||
$rssTitle = sprintf( $member->language()->get( 'forum_rss_title_questions'), $member->language()->get( "forums_forum_{$forum->id}" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$rssTitle = sprintf( $member->language()->get( 'forum_rss_title_topics'), $member->language()->get( "forums_forum_{$forum->id}" ) );
|
||||
}
|
||||
|
||||
/* Can we view the content (permission_showtopic may allow us to view the list, but not the content)? */
|
||||
$canViewContent = $forum->can('read', $member );
|
||||
|
||||
/* Build the document */
|
||||
$document = \IPS\Xml\Rss::newDocument( $forum->url(), $rssTitle, $rssTitle );
|
||||
foreach ( $iterator as $topic )
|
||||
{
|
||||
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', array(), TRUE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Archive Query
|
||||
@@ -39,6 +122,12 @@ class _Application extends \IPS\Application
|
||||
public static function archiveWhere( $rules )
|
||||
{
|
||||
$where = array();
|
||||
|
||||
if ( \IPS\CIC )
|
||||
{
|
||||
return \IPS\Cicloud\getForumArchiveWhere();
|
||||
}
|
||||
|
||||
foreach ( $rules as $rule )
|
||||
{
|
||||
$clause = NULL;
|
||||
@@ -177,8 +266,8 @@ class _Application extends \IPS\Application
|
||||
*/
|
||||
public function convertLegacyParameters()
|
||||
{
|
||||
/* Convert &showtopic= @link */
|
||||
if ( isset( \IPS\Request::i()->showtopic ) and is_numeric( \IPS\Request::i()->showtopic ) )
|
||||
/* Convert &showtopic= (link) */
|
||||
if ( isset( \IPS\Request::i()->showtopic ) and \is_numeric( \IPS\Request::i()->showtopic ) )
|
||||
{
|
||||
$base = NULL;
|
||||
$seoTemplate = NULL;
|
||||
@@ -198,19 +287,19 @@ class _Application extends \IPS\Application
|
||||
|
||||
$url = \IPS\Http\Url::internal( 'app=forums&module=forums&controller=topic&id=' . \IPS\Request::i()->showtopic, $base, $seoTemplate, $seoTitles );
|
||||
|
||||
if ( isset( \IPS\Request::i()->p ) or isset( \IPS\Request::i()->findpost ) )
|
||||
if ( isset( \IPS\Request::i()->p ) or isset( \IPS\Request::i()->findpost ) or isset( \IPS\Request::i()->comment ) )
|
||||
{
|
||||
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->p ?: \IPS\Request::i()->findpost ) );
|
||||
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->p ?: ( \IPS\Request::i()->findpost ?: \IPS\Request::i()->comment ) ) );
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->page ) )
|
||||
{
|
||||
$url = $url->setQueryString( array( 'page' => \IPS\Request::i()->page ) );
|
||||
$url = $url->setPage( 'page', \IPS\Request::i()->page );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
|
||||
/* Convert &showforum= */
|
||||
if ( isset( \IPS\Request::i()->showforum ) and is_numeric( \IPS\Request::i()->showforum ) )
|
||||
if ( isset( \IPS\Request::i()->showforum ) and \is_numeric( \IPS\Request::i()->showforum ) )
|
||||
{
|
||||
$base = NULL;
|
||||
$seoTemplate = NULL;
|
||||
@@ -233,7 +322,7 @@ class _Application extends \IPS\Application
|
||||
}
|
||||
|
||||
/* Convert /topic/123-example/&p= */
|
||||
if ( isset( \IPS\Request::i()->p ) AND is_numeric( \IPS\Request::i()->p ) AND ( \IPS\Request::i()->url() instanceof \IPS\Http\Url\Friendly ) AND \IPS\Request::i()->url()->seoTemplate == 'forums_topic' )
|
||||
if ( isset( \IPS\Request::i()->p ) AND \is_numeric( \IPS\Request::i()->p ) AND ( \IPS\Request::i()->url() instanceof \IPS\Http\Url\Friendly ) AND \IPS\Request::i()->url()->seoTemplate == 'forums_topic' )
|
||||
{
|
||||
/* We do this a little differently as the topic seo title is already known at this point */
|
||||
try
|
||||
@@ -244,4 +333,16 @@ class _Application extends \IPS\Application
|
||||
catch( \Exception $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of specific links to add to the sitemap
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function sitemapLinks()
|
||||
{
|
||||
return array(
|
||||
\IPS\Http\Url::internal( 'app=forums&module=forums&controller=index', 'front', 'forums' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Forums mutations
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\Types;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forums mutationss GraphQL API
|
||||
*/
|
||||
abstract class _Mutation
|
||||
{
|
||||
/**
|
||||
* Get the supported query types in this app
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function mutations()
|
||||
{
|
||||
return [
|
||||
'createTopic' => new \IPS\forums\api\GraphQL\Mutations\CreateTopic(),
|
||||
'replyTopic' => new \IPS\forums\api\GraphQL\Mutations\ReplyTopic(),
|
||||
'postReaction' => new \IPS\forums\api\GraphQL\Mutations\PostReaction(),
|
||||
'markForumRead' => new \IPS\forums\api\GraphQL\Mutations\MarkForumRead(),
|
||||
'markTopicRead' => new \IPS\forums\api\GraphQL\Mutations\MarkTopicRead(),
|
||||
'markTopicSolved' => new \IPS\forums\api\GraphQL\Mutations\MarkTopicSolved(),
|
||||
'voteInPoll' => new \IPS\forums\api\GraphQL\Mutations\VoteInPoll(),
|
||||
'voteQuestion' => new \IPS\forums\api\GraphQL\Mutations\VoteQuestion(),
|
||||
'voteAnswer' => new \IPS\forums\api\GraphQL\Mutations\VoteAnswer(),
|
||||
'setBestAnswer' => new \IPS\forums\api\GraphQL\Mutations\SetBestAnswer(),
|
||||
'reportPost' => new \IPS\forums\api\GraphQL\Mutations\ReportPost(),
|
||||
'revokePostReport' => new \IPS\forums\api\GraphQL\Mutations\RevokePostReport(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Create topic mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create topic mutation for GraphQL API
|
||||
*/
|
||||
class _CreateTopic extends \IPS\Content\Api\GraphQL\ItemMutator
|
||||
{
|
||||
/**
|
||||
* Class
|
||||
*/
|
||||
protected $class = 'IPS\forums\Topic';
|
||||
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Create a new topic";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'forumID' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'title' => TypeRegistry::nonNull( TypeRegistry::string() ),
|
||||
'content' => TypeRegistry::nonNull( TypeRegistry::string() ),
|
||||
'tags' => TypeRegistry::listOf( TypeRegistry::string() ),
|
||||
'state' => TypeRegistry::itemState(),
|
||||
'postKey' => TypeRegistry::string()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
/* Get forum */
|
||||
try
|
||||
{
|
||||
$forum = \IPS\forums\Forum::loadAndCheckPerms( $args['forumID'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_FORUM', '1F294/2', 400 );
|
||||
}
|
||||
|
||||
/* Check permission */
|
||||
if ( !$forum->can( 'add', \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', '2F294/9', 403 );
|
||||
}
|
||||
|
||||
/* Check we have a title and a post */
|
||||
if ( !$args['title'] )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_TITLE', '1F294/5', 400 );
|
||||
}
|
||||
if ( !$args['content'] )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1F294/4', 400 );
|
||||
}
|
||||
|
||||
|
||||
$item = $this->_create( $args, $forum, $args['postKey'] ?? NULL );
|
||||
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Mark a forum read mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 9 Nov 2018
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark forum read mutation for GraphQL API
|
||||
*/
|
||||
class _MarkForumRead extends \IPS\Node\Api\GraphQL\NodeMutator
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Mark a forum as read";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::forum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$forum = \IPS\forums\Forum::loadAndCheckPerms( \intval( $args['id'] ) );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_NODE', 'GQL/0004/2', 403 );
|
||||
}
|
||||
|
||||
$this->_markRead( $forum );
|
||||
return $forum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Mark a topic read mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 28 Nov 2018
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark topic read mutation for GraphQL API
|
||||
*/
|
||||
class _MarkTopicRead extends \IPS\Content\Api\GraphQL\ItemMutator
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Mark a topic as read";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( $args['id'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', 'GQL/0005/1', 400 );
|
||||
}
|
||||
|
||||
if( !$topic->can('read') )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_ID', 'GQL/0005/2', 403 );
|
||||
}
|
||||
|
||||
$this->_markRead( $topic );
|
||||
return $topic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Mark a topic solved mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 1 Jul 2020
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark topic solved mutation for GraphQL API
|
||||
*/
|
||||
class _MarkTopicSolved extends \IPS\Node\Api\GraphQL\NodeMutator
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Mark a topic solved";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'answer' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'solved' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'defaultValue' => TRUE
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @return \IPS\forums\Topic
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( \intval( $args['id'] ) );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', 'GQL', 403 );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( \intval( $args['answer'] ) );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', 'GQL', 403 );
|
||||
}
|
||||
|
||||
/* This is "solved" mode */
|
||||
if ( !$topic->canSolve() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', 'GQL', 403 );
|
||||
}
|
||||
|
||||
|
||||
if( $args['solved'] )
|
||||
{
|
||||
$topic->toggleSolveComment( $post->pid, TRUE );
|
||||
|
||||
if( $post->author()->member_id != \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
$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();
|
||||
}
|
||||
}
|
||||
else if ( $topic->mapped('solved_comment_id') )
|
||||
{
|
||||
$topic->toggleSolveComment( $post->pid, FALSE );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->insert( 'core_moderator_logs', array(
|
||||
'member_id' => \IPS\Member::loggedIn()->member_id,
|
||||
'member_name' => \IPS\Member::loggedIn()->name,
|
||||
'ctime' => time(),
|
||||
'note' => json_encode( array( $post->pid => $args['solved'] ) ),
|
||||
'ip_address' => \IPS\Request::i()->ipAddress(),
|
||||
'appcomponent' => 'forums',
|
||||
'module' => 'forums',
|
||||
'controller' => 'topic',
|
||||
'do' => $args['solved'] ? 'solve' : 'unsolve',
|
||||
'lang_key' => $args['solved'] ? 'modlog__best_answer_set' : 'modlog__best_answer_unset',
|
||||
'class' => "IPS\forums\Topic",
|
||||
'item_id' => $args['id'],
|
||||
) );
|
||||
|
||||
return $topic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: React to a post mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* React to post mutation for GraphQL API
|
||||
*/
|
||||
class _PostReaction extends \IPS\Content\Api\GraphQL\CommentMutator
|
||||
{
|
||||
/**
|
||||
* Class
|
||||
*/
|
||||
protected $class = 'IPS\forums\Topic\Post';
|
||||
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "React to a post";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'postID' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'reactionID' => TypeRegistry::int(),
|
||||
'removeReaction' => TypeRegistry::boolean()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
/* Get topic */
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['postID'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1F295/1', 403 );
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
if( isset( $args['removeReaction'] ) && $args['removeReaction'] )
|
||||
{
|
||||
$this->_unreactComment( $post );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_reactComment( $args['reactionID'], $post );
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Reply to topic mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reply to topic mutation for GraphQL API
|
||||
*/
|
||||
class _ReplyTopic extends \IPS\Content\Api\GraphQL\CommentMutator
|
||||
{
|
||||
/**
|
||||
* Class
|
||||
*/
|
||||
protected $class = 'IPS\forums\Topic\Post';
|
||||
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Create a new post";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'topicID' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'content' => TypeRegistry::nonNull( TypeRegistry::string() ),
|
||||
'replyingTo' => TypeRegistry::id(),
|
||||
'postKey' => TypeRegistry::string()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
/* Get topic */
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( $args['topicID'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', '1F295/1', 403 );
|
||||
}
|
||||
|
||||
/* Get author */
|
||||
if ( !$topic->canComment( \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', '2F294/A', 403 );
|
||||
}
|
||||
|
||||
/* Check we have a post */
|
||||
if ( !$args['content'] )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1F295/3', 403 );
|
||||
}
|
||||
|
||||
$originalPost = NULL;
|
||||
|
||||
if( isset( $args['replyingTo'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$originalPost = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['replyingTo'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
// Just ignore it
|
||||
}
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
return $this->_createComment( $args, $topic, $args['postKey'] ?? NULL, $originalPost );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Report a post mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Jun 2019
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report post mutation for GraphQL API
|
||||
*/
|
||||
class _ReportPost extends \IPS\Content\Api\GraphQL\CommentMutator
|
||||
{
|
||||
/**
|
||||
* Class
|
||||
*/
|
||||
protected $class = 'IPS\forums\Topic\Post';
|
||||
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Report a post";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'reason' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'defaultValue' => 0
|
||||
],
|
||||
'additionalInfo' => TypeRegistry::string()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Topic\Post
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
/* Get post */
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['id'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1F295/1', 403 );
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
return $this->_reportComment( $args, $post );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Revoke a post report mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 15 Jun 2019
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke post report mutation for GraphQL API
|
||||
*/
|
||||
class _RevokePostReport extends \IPS\Content\Api\GraphQL\CommentMutator
|
||||
{
|
||||
/**
|
||||
* Class
|
||||
*/
|
||||
protected $class = 'IPS\forums\Topic\Post';
|
||||
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Report a post";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'reportID'=> TypeRegistry::nonNull( TypeRegistry::id() )
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Topic\Post
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
/* Get post */
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['id'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1F295/1', 403 );
|
||||
}
|
||||
|
||||
/* Do it */
|
||||
return $this->_revokeCommentReport( $args, $post );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Set a post as best answer
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 08 Jan 2019
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a post as best answer mutation for GraphQL API
|
||||
*/
|
||||
class _SetBestAnswer
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Set a post as best answer";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['id'] );
|
||||
$topic = $post->item();
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', 'GQL/0010/1', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->can('read') )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_ID', 'GQL/0010/2', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NON_QUESTION', 'GQL/0010/3', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->canSetBestAnswer() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', 'GQL/0010/4', 403 );
|
||||
}
|
||||
|
||||
// Do we have an existing best answer
|
||||
if ( $topic->topic_answered_pid )
|
||||
{
|
||||
try
|
||||
{
|
||||
$oldBestAnswer = \IPS\forums\Topic\Post::load( $topic->topic_answered_pid );
|
||||
$oldBestAnswer->post_bwoptions['best_answer'] = FALSE;
|
||||
$oldBestAnswer->save();
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
$post->post_bwoptions['best_answer'] = TRUE;
|
||||
$post->save();
|
||||
|
||||
$topic->topic_answered_pid = $post->pid;
|
||||
$topic->save();
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Vote on an answer
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 02 Jan 2019
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vote on an answer mutation for GraphQL API
|
||||
*/
|
||||
class _VoteAnswer
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Vote on an answer";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'vote' => TypeRegistry::nonNull( \IPS\forums\api\GraphQL\TypeRegistry::vote() ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['id'] );
|
||||
$topic = $post->item();
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', 'GQL/0009/1', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->can('read') )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_ID', 'GQL/0009/2', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NON_QUESTION', 'GQL/0009/3', 403 );
|
||||
}
|
||||
|
||||
if( !$post->canVote() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'CANNOT_VOTE', 'GQL/0009/4', 403 );
|
||||
}
|
||||
|
||||
$rating = $args['vote'] == 'UP' ? 1 : -1;
|
||||
|
||||
/* Have we already rated ? */
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->delete( 'forums_answer_ratings', array( 'topic=? AND post=? AND `member`=?', $topic->tid, $post->pid, \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
catch ( \UnderflowException $e ){}
|
||||
|
||||
\IPS\Db::i()->insert( 'forums_answer_ratings', array(
|
||||
'post' => $post->pid,
|
||||
'topic' => $topic->tid,
|
||||
'member' => \IPS\Member::loggedIn()->member_id,
|
||||
'rating' => $rating,
|
||||
'date' => time()
|
||||
), TRUE );
|
||||
|
||||
$post->post_field_int = (int) \IPS\Db::i()->select( 'SUM(rating)', 'forums_answer_ratings', array( 'post=?', $post->pid ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
|
||||
$post->save();
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Vote in poll mutation
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 5 Dec 2018
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use GraphQL\Type\Definition\InputObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vote in poll mutation for GraphQL API
|
||||
*/
|
||||
class _VoteInPoll extends \IPS\Poll\Api\GraphQL\PollMutator
|
||||
{
|
||||
/**
|
||||
* Class
|
||||
*/
|
||||
protected $class = 'IPS\forums\Topic';
|
||||
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Vote in a poll in a topic";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'itemID' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'poll' => TypeRegistry::listOf(
|
||||
new InputObjectType([
|
||||
'name' => 'core_PollQuestionInput',
|
||||
'fields' => [
|
||||
'id' => TypeRegistry::id(),
|
||||
'choices' => TypeRegistry::listOf( TypeRegistry::int() )
|
||||
]
|
||||
])
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
/* Get topic */
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( $args['itemID'] );
|
||||
$poll = $topic->getPoll();
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_TOPIC', 'GQL/0006/1', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->can('read') || $poll === NULL )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_POLL', 'GQL/0006/2', 403 );
|
||||
}
|
||||
|
||||
$this->_vote( $poll, $args['poll'] );
|
||||
|
||||
return $topic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Vote on a question
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 02 Jan 2019
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Mutations;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vote on a question mutation for GraphQL API
|
||||
*/
|
||||
class _VoteQuestion
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Vote on a question";
|
||||
|
||||
/*
|
||||
* Mutation arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return [
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'vote' => TypeRegistry::nonNull( \IPS\forums\api\GraphQL\TypeRegistry::vote() ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mutation return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this mutation
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( $args['id'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', 'GQL/0008/1', 400 );
|
||||
}
|
||||
|
||||
if( !$topic->can('read') )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_ID', 'GQL/0008/2', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NON_QUESTION', 'GQL/0008/3', 403 );
|
||||
}
|
||||
|
||||
if( !$topic->canVote() )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'CANNOT_VOTE', 'GQL/0008/4', 403 );
|
||||
}
|
||||
|
||||
$rating = $args['vote'] == 'UP' ? 1 : -1;
|
||||
|
||||
// If we have an existing vote, undo that
|
||||
$ratings = $topic->votes();
|
||||
if ( isset( $ratings[ \IPS\Member::loggedIn()->member_id ] ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'forums_question_ratings', array( 'topic=? AND member=?', $topic->tid, \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->insert( 'forums_question_ratings', array(
|
||||
'topic' => $topic->tid,
|
||||
'forum' => $topic->forum_id,
|
||||
'member' => \IPS\Member::loggedIn()->member_id,
|
||||
'rating' => $rating,
|
||||
'date' => time()
|
||||
), TRUE );
|
||||
|
||||
/* Rebuild count */
|
||||
$topic->question_rating = \IPS\Db::i()->select( 'SUM(rating)', 'forums_question_ratings', array( 'topic=?', $topic->tid ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
|
||||
$topic->save();
|
||||
|
||||
return $topic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Forum query
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Queries;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forum query for GraphQL API
|
||||
*/
|
||||
class _Forum
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Returns a forum";
|
||||
|
||||
/*
|
||||
* Query arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return array(
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() ),
|
||||
'password' => TypeRegistry::string()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::forum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this query
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Forum
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
$forum = \IPS\forums\Forum::load( $args['id'] );
|
||||
|
||||
if( !$forum->can( 'view', $context['member'] ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
return $forum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Forums query
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Queries;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forums query for GraphQL API
|
||||
*/
|
||||
class _Forums
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Returns a list of forums";
|
||||
|
||||
/*
|
||||
* Query arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return array(
|
||||
'id' => TypeRegistry::id()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return TypeRegistry::listOf( \IPS\forums\api\GraphQL\TypeRegistry::forum() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this query
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return array
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
\IPS\forums\Forum::loadIntoMemory('view', $context['member']);
|
||||
return \IPS\forums\Forum::roots();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Post query
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Queries;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post query for GraphQL API
|
||||
*/
|
||||
class _Post
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Returns a post";
|
||||
|
||||
/*
|
||||
* Query arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return array(
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this query
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Topic\Post
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( $args['id'] );
|
||||
|
||||
if( !$post->item()->canView() )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Topic query
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Queries;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Topic query for GraphQL API
|
||||
*/
|
||||
class _Topic
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Returns a topic";
|
||||
|
||||
/*
|
||||
* Query arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return array(
|
||||
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this query
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Topic\Post
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::loadAndCheckPerms( $args['id'] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', '1F294/2', 400 );
|
||||
}
|
||||
|
||||
if( !$topic->can('read') )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_ID', '2F294/9', 403 );
|
||||
}
|
||||
|
||||
return $topic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Topics query
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Queries;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Topics query for GraphQL API
|
||||
*/
|
||||
class _Topics
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Returns a list of topics";
|
||||
|
||||
/*
|
||||
* Query arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return array(
|
||||
'forums' => TypeRegistry::listOf( TypeRegistry::int() ),
|
||||
'offset' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'defaultValue' => 0
|
||||
],
|
||||
'limit' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'defaultValue' => 25
|
||||
],
|
||||
'orderBy' => [
|
||||
'type' => TypeRegistry::eNum([
|
||||
'name' => 'forums_fluid_order_by',
|
||||
'description' => 'Fields on which topics can be sorted',
|
||||
'values' => \IPS\forums\api\GraphQL\Types\TopicType::getOrderByOptions()
|
||||
]),
|
||||
'defaultValue' => NULL // will use default sort option
|
||||
],
|
||||
'orderDir' => [
|
||||
'type' => TypeRegistry::eNum([
|
||||
'name' => 'forums_fluid_order_dir',
|
||||
'description' => 'Directions in which items can be sorted',
|
||||
'values' => [ 'ASC', 'DESC' ]
|
||||
]),
|
||||
'defaultValue' => 'DESC'
|
||||
],
|
||||
'honorPinned' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'defaultValue' => true
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return TypeRegistry::listOf( \IPS\forums\api\GraphQL\TypeRegistry::topic() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this query
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\forums\Topic\Post
|
||||
*/
|
||||
public function resolve($val, $args, $context, $info)
|
||||
{
|
||||
\IPS\forums\Forum::loadIntoMemory('view', \IPS\Member::loggedIn() );
|
||||
|
||||
$where = array( 'container' => array( array( 'forums_forums.password IS NULL' ) ) );
|
||||
$forumIDs = [];
|
||||
|
||||
/* Are we filtering by forums? */
|
||||
if( isset( $args['forums'] ) && \count( $args['forums'] ) )
|
||||
{
|
||||
foreach( $args['forums'] as $id )
|
||||
{
|
||||
$forum = \IPS\forums\Forum::loadAndCheckPerms( $id );
|
||||
$forumIDs[] = $forum->id;
|
||||
}
|
||||
|
||||
if( \count( $forumIDs ) )
|
||||
{
|
||||
$where['container'][] = array( \IPS\Db::i()->in( 'forums_forums.id', array_filter( $forumIDs ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Get sorting */
|
||||
try
|
||||
{
|
||||
if( $args['orderBy'] === NULL )
|
||||
{
|
||||
$orderBy = 'last_post';
|
||||
}
|
||||
else
|
||||
{
|
||||
$orderBy = \IPS\forums\Topic::$databaseColumnMap[ $args['orderBy'] ];
|
||||
}
|
||||
|
||||
if( $args['orderBy'] === 'last_comment' )
|
||||
{
|
||||
$orderBy = \is_array( $orderBy ) ? array_pop( $orderBy ) : $orderBy;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$orderBy = 'last_post';
|
||||
}
|
||||
|
||||
$sortBy = "{$orderBy} {$args['orderDir']}";
|
||||
$offset = max( $args['offset'], 0 );
|
||||
$limit = min( $args['limit'], 50 );
|
||||
|
||||
/* Figure out pinned status */
|
||||
if ( $args['honorPinned'] )
|
||||
{
|
||||
$column = \IPS\forums\Topic::$databaseTable . '.' . \IPS\forums\Topic::$databasePrefix . \IPS\forums\Topic::$databaseColumnMap['pinned'];
|
||||
$sortBy = "{$column} DESC, {$sortBy}";
|
||||
}
|
||||
|
||||
return \IPS\forums\Topic::getItemsWithPermission( $where, $sortBy, array( $offset, $limit ), 'read' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Forums queries
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\Types;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forums queries for GraphQL API
|
||||
*/
|
||||
abstract class _Query
|
||||
{
|
||||
/**
|
||||
* Get the supported query types in this app
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function queries()
|
||||
{
|
||||
return [
|
||||
'forums' => new \IPS\forums\api\GraphQL\Queries\Forums(),
|
||||
'forum' => new \IPS\forums\api\GraphQL\Queries\Forum(),
|
||||
'topics' => new \IPS\forums\api\GraphQL\Queries\Topics(),
|
||||
'topic' => new \IPS\forums\api\GraphQL\Queries\Topic(),
|
||||
'post' => new \IPS\forums\api\GraphQL\Queries\Post()
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Types registry
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 7 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\Types;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forum type registry. GraphQL requires exactly one instance of each type,
|
||||
* so we'll generate singletons here.
|
||||
* @todo automate this somehow?
|
||||
*/
|
||||
class _TypeRegistry
|
||||
{
|
||||
protected static $forum;
|
||||
protected static $post;
|
||||
protected static $topic;
|
||||
protected static $vote;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Defined to suppress static warnings
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ForumType
|
||||
*/
|
||||
public static function forum()
|
||||
{
|
||||
return self::$forum ?: (self::$forum = new \IPS\forums\api\GraphQL\Types\ForumType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PostType
|
||||
*/
|
||||
public static function post()
|
||||
{
|
||||
return self::$post ?: (self::$post = new \IPS\forums\api\GraphQL\Types\PostType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TopicType
|
||||
*/
|
||||
public static function topic()
|
||||
{
|
||||
return self::$topic ?: (self::$topic = new \IPS\forums\api\GraphQL\Types\TopicType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return VoteType
|
||||
*/
|
||||
public static function vote()
|
||||
{
|
||||
return self::$vote ?: (self::$vote = new \IPS\forums\api\GraphQL\Types\VoteType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Forum Type
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Types;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ForumType for GraphQL API
|
||||
*/
|
||||
class _ForumType extends \IPS\Node\Api\GraphQL\NodeType
|
||||
{
|
||||
/*
|
||||
* @brief The item classname we use for this type
|
||||
*/
|
||||
protected static $nodeClass = '\IPS\forums\Forum';
|
||||
|
||||
/*
|
||||
* @brief GraphQL type name
|
||||
*/
|
||||
protected static $typeName = 'forums_Forum';
|
||||
|
||||
/*
|
||||
* @brief GraphQL type description
|
||||
*/
|
||||
protected static $typeDescription = 'A forum';
|
||||
|
||||
/*
|
||||
* @brief Follow data passed in to FollowType resolver
|
||||
*/
|
||||
protected static $followData = array('app' => 'forums', 'area' => 'forum');
|
||||
|
||||
/**
|
||||
* Return the fields available in this type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields()
|
||||
{
|
||||
$defaultFields = parent::fields();
|
||||
$forumFields = array(
|
||||
'solvedEnabled' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($forum) {
|
||||
return ( $forum->forums_bitoptions['bw_enable_answers_member'] || $forum->forums_bitoptions['bw_enable_answers_moderator'] );
|
||||
}
|
||||
],
|
||||
'lastPostAuthor' => [
|
||||
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
|
||||
'resolve' => function ($forum, $args) {
|
||||
return self::lastPostAuthor( $forum, $args );
|
||||
}
|
||||
],
|
||||
'lastPostDate' => [
|
||||
'type' => TypeRegistry::string(),
|
||||
'resolve' => function ($forum, $args) {
|
||||
return self::lastPostDate( $forum, $args );
|
||||
}
|
||||
],
|
||||
'featureColor' => [
|
||||
'type' => TypeRegistry::string(),
|
||||
'resolve' => function ($forum) {
|
||||
return $forum->feature_color;
|
||||
}
|
||||
],
|
||||
'isRedirectForum' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($forum) {
|
||||
return (bool) $forum->redirect_on;
|
||||
}
|
||||
],
|
||||
'redirectHits' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'resolve' => function ($forum) {
|
||||
return $forum->redirect_on ? (int) $forum->redirect_hits : NULL;
|
||||
}
|
||||
],
|
||||
'passwordProtected' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($forum) {
|
||||
return $forum->password !== NULL;
|
||||
}
|
||||
],
|
||||
'passwordRequired' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($forum) {
|
||||
if( $forum->password === NULL || \IPS\Member::loggedIn()->inGroup( explode( ',', $forum->password_override ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// Duplicate fields that have different names in forums
|
||||
$forumFields['topicCount'] = $defaultFields['itemCount'];
|
||||
$forumFields['postCount'] = $defaultFields['commentCount'];
|
||||
$forumFields['subforums'] = $defaultFields['children'];
|
||||
$forumFields['topics'] = $defaultFields['items'];
|
||||
|
||||
// Remove duplicated fields
|
||||
unset( $defaultFields['itemCount'] );
|
||||
unset( $defaultFields['commentCount'] );
|
||||
unset( $defaultFields['children'] );
|
||||
unset( $defaultFields['items'] );
|
||||
|
||||
return array_merge( $defaultFields, $forumFields );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item type that goes with this node type
|
||||
*
|
||||
* @return ObjectType
|
||||
*/
|
||||
public static function getItemType()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a password before returning items
|
||||
*
|
||||
* @param \IPS\forums\Forum
|
||||
* @param array Arguments passed to this resolver
|
||||
* @return array
|
||||
*/
|
||||
protected static function items($forum, $args)
|
||||
{
|
||||
// If there's no password or our group is excluded, just continue
|
||||
if( $forum->password === NULL || \IPS\Member::loggedIn()->inGroup( explode( ',', $forum->password_override ) ) )
|
||||
{
|
||||
return parent::items($forum, $args);
|
||||
}
|
||||
|
||||
if( !isset( $args['password'] ) || !\IPS\Login::compareHashes( md5( $forum->password ), md5( $args['password'] ) ) )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'INCORRECT_PASSWORD', 'GQL/0002/1', 403 );
|
||||
}
|
||||
|
||||
return parent::items($forum, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve last post author field
|
||||
*
|
||||
* @param \IPS\forums\Forum
|
||||
* @param array Arguments passed to this resolver
|
||||
* @return array
|
||||
*/
|
||||
protected static function lastPostAuthor($forum, $args)
|
||||
{
|
||||
$lastComment = $forum->lastPost();
|
||||
|
||||
if( $lastComment )
|
||||
{
|
||||
return $lastComment['author'];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve last post date field
|
||||
*
|
||||
* @param \IPS\forums\Forum
|
||||
* @param array Arguments passed to this resolver
|
||||
* @return array
|
||||
*/
|
||||
protected static function lastPostDate($forum, $args)
|
||||
{
|
||||
$lastComment = $forum->lastPost();
|
||||
|
||||
if( $lastComment )
|
||||
{
|
||||
return $lastComment['date'];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Post Type
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Types;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* PostType for GraphQL API
|
||||
*/
|
||||
class _PostType extends \IPS\Content\Api\GraphQL\CommentType
|
||||
{
|
||||
/*
|
||||
* @brief The item classname we use for this type
|
||||
*/
|
||||
protected static $commentClass = '\IPS\forums\Topic\Post';
|
||||
|
||||
/*
|
||||
* @brief GraphQL type name
|
||||
*/
|
||||
protected static $typeName = 'forums_Post';
|
||||
|
||||
/*
|
||||
* @brief GraphQL type description
|
||||
*/
|
||||
protected static $typeDescription = 'A post';
|
||||
|
||||
/**
|
||||
* Get the item type that goes with this item type
|
||||
*
|
||||
* @return ObjectType
|
||||
*/
|
||||
public static function getItemType()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::topic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields available in this type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields()
|
||||
{
|
||||
$defaultFields = parent::fields();
|
||||
$postFields = array(
|
||||
'topic' => [
|
||||
'type' => \IPS\forums\api\GraphQL\TypeRegistry::topic(),
|
||||
'resolve' => function ($post) {
|
||||
return $post->item();
|
||||
}
|
||||
],
|
||||
/* Q&A STUFF */
|
||||
'isQuestion' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'description' => "Boolean indicating whether this post is a question, i.e. the first post in a question topic",
|
||||
'resolve' => function ($post) {
|
||||
return $post->item()->isQuestion() && $post->new_topic;
|
||||
}
|
||||
],
|
||||
'answerVotes' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'resolve' => function ($post) {
|
||||
return $post->post_field_int;
|
||||
}
|
||||
],
|
||||
'isBestAnswer' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'description' => "Whether this post is the best answer in a question",
|
||||
'resolve' => function ($post) {
|
||||
return $post->post_bwoptions['best_answer'];
|
||||
}
|
||||
],
|
||||
'canVoteUp' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($post) {
|
||||
if( !$post->item()->isQuestion() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $post->canVote(1);
|
||||
}
|
||||
],
|
||||
'canVoteDown' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($post) {
|
||||
if( !$post->item()->isQuestion() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $post->canVote(-1) && \IPS\Settings::i()->forums_questions_downvote;
|
||||
}
|
||||
],
|
||||
'vote' => [
|
||||
'type' => \IPS\forums\api\GraphQL\TypeRegistry::vote(),
|
||||
'resolve' => function ($post) {
|
||||
$ratings = $post->item()->answerVotes( \IPS\Member::loggedIn() );
|
||||
|
||||
if( !$post->item()->isQuestion() || !isset( $ratings[ $post->pid ] ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $ratings[ $post->pid ] === -1 ? 'DOWN' : 'UP';
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// Duplicate fields that have different names in posts
|
||||
//$defaultFields['topic'] = $defaultFields['item'];
|
||||
|
||||
// Remove duplicated fields
|
||||
unset( $defaultFields['item'] );
|
||||
|
||||
return array_merge( $defaultFields, $postFields );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the definite article, but without the item type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function definiteArticleNoItem($post, $options = array())
|
||||
{
|
||||
$type = $post->item()->isQuestion() ? 'answer_lc' : 'post_lc';
|
||||
return \IPS\Member::loggedIn()->language()->addToStack($type, FALSE, $options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Topic Type
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 10 May 2017
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Types;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\_TypeRegistry;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* TopicType for GraphQL API
|
||||
*/
|
||||
class _TopicType extends \IPS\Content\Api\GraphQL\ItemType
|
||||
{
|
||||
/*
|
||||
* @brief The item classname we use for this type
|
||||
*/
|
||||
protected static $itemClass = '\IPS\forums\Topic';
|
||||
|
||||
/*
|
||||
* @brief GraphQL type name
|
||||
*/
|
||||
protected static $typeName = 'forums_Topic';
|
||||
|
||||
/*
|
||||
* @brief GraphQL type description
|
||||
*/
|
||||
protected static $typeDescription = 'A topic';
|
||||
|
||||
/*
|
||||
* @brief Follow data passed in to FollowType resolver
|
||||
*/
|
||||
protected static $followData = array('app' => 'forums', 'area' => 'topic');
|
||||
|
||||
/**
|
||||
* Return the fields available in this type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields()
|
||||
{
|
||||
// Extend our fields with topic-specific stuff
|
||||
$defaultFields = parent::fields();
|
||||
$topicFields = array(
|
||||
'forum' => [
|
||||
'type' => \IPS\forums\api\GraphQL\TypeRegistry::forum(),
|
||||
'resolve' => function ($item) {
|
||||
return $item->container();
|
||||
}
|
||||
],
|
||||
'isArchived' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
return (bool) $topic->isArchived();
|
||||
}
|
||||
],
|
||||
'isHot' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
foreach( $topic->stats(FALSE) as $k => $v )
|
||||
{
|
||||
if( \in_array( $k, $topic->hotStats ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
],
|
||||
|
||||
/* SOLVED STUFF */
|
||||
'isSolved' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
return (bool) $topic->isSolved();
|
||||
}
|
||||
],
|
||||
'solvedId' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'resolve' => function ($topic) {
|
||||
if( $topic->isSolved() ){
|
||||
return $topic->mapped('solved_comment_id');
|
||||
}
|
||||
}
|
||||
],
|
||||
'canMarkSolved' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
return $topic->canSolve();
|
||||
}
|
||||
],
|
||||
'solvedComment' => [
|
||||
'type' => \IPS\forums\api\GraphQL\TypeRegistry::post(),
|
||||
'resolve' => function ($topic) {
|
||||
if( !$topic->isSolved() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$solved = \IPS\forums\Topic\Post::load( $topic->mapped('solved_comment_id') );
|
||||
return $solved;
|
||||
}
|
||||
catch (\Exception $err)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
/* Q&A STUFF */
|
||||
'isQuestion' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
return $topic->isQuestion();
|
||||
}
|
||||
],
|
||||
'questionVotes' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'resolve' => function ($topic) {
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return \intval( $topic->question_rating );
|
||||
}
|
||||
],
|
||||
'canVoteUp' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $topic->canVote(1);
|
||||
}
|
||||
],
|
||||
'canVoteDown' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $topic->canVote(-1) && \IPS\Settings::i()->forums_questions_downvote;
|
||||
}
|
||||
],
|
||||
'vote' => [
|
||||
'type' => \IPS\forums\api\GraphQL\TypeRegistry::vote(),
|
||||
'resolve' => function ($topic) {
|
||||
$topicVotes = $topic->votes();
|
||||
|
||||
if( !$topic->isQuestion() || !isset( $topicVotes[ \IPS\Member::loggedIn()->member_id ] ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $topicVotes[ \IPS\Member::loggedIn()->member_id ] === -1 ? 'DOWN' : 'UP';
|
||||
}
|
||||
],
|
||||
'hasBestAnswer' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
return !!$topic->topic_answered_pid;
|
||||
}
|
||||
],
|
||||
'bestAnswerID' => [
|
||||
'type' => TypeRegistry::id(),
|
||||
'resolve' => function ($topic) {
|
||||
if( !$topic->isQuestion() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $topic->topic_answered_pid;
|
||||
}
|
||||
],
|
||||
'canSetBestAnswer' => [
|
||||
'type' => TypeRegistry::boolean(),
|
||||
'resolve' => function ($topic) {
|
||||
return $topic->canSetBestAnswer();
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// Questions get their comment count reduced by one in the model, but for the API
|
||||
// we'll reverse that change to keep topics & questions consistent.
|
||||
$topicFields['postCount'] = $defaultFields['commentCount'];
|
||||
$topicFields['postCount']['resolve'] = function ($topic, $args) {
|
||||
if( $args['includeHidden'] )
|
||||
{
|
||||
return $topic->commentCount() + ( $topic->isQuestion() ? 1 : 0 );
|
||||
}
|
||||
|
||||
return $topic->mapped('num_comments');
|
||||
};
|
||||
|
||||
// Duplicate fields that have different names in topics
|
||||
//$topicFields['forum'] = $defaultFields['container'];
|
||||
$topicFields['posts'] = $defaultFields['comments'];
|
||||
$topicFields['lastPostAuthor'] = $defaultFields['lastCommentAuthor'];
|
||||
$topicFields['lastPostDate'] = $defaultFields['lastCommentDate'];
|
||||
|
||||
// Remove duplicated fields
|
||||
unset( $defaultFields['container'] );
|
||||
unset( $defaultFields['comments'] );
|
||||
unset( $defaultFields['commentCount'] );
|
||||
unset( $defaultFields['lastCommentAuthor'] );
|
||||
unset( $defaultFields['lastCommentDate'] );
|
||||
|
||||
return array_merge( $defaultFields, $topicFields );
|
||||
}
|
||||
|
||||
public static function args()
|
||||
{
|
||||
return array_merge( parent::args(), array(
|
||||
'password' => [
|
||||
'type' => TypeRegistry::string()
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return item permission fields.
|
||||
* Here we adjust the resolver for the commentInformation field to check whether this is
|
||||
* a poll-only topic.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getItemPermissionFields()
|
||||
{
|
||||
$defaultFields = parent::getItemPermissionFields();
|
||||
$existingResolver = $defaultFields['commentInformation']['resolve'];
|
||||
|
||||
$defaultFields['commentInformation']['resolve'] = function ($topic, $args, $context) use ( $existingResolver ) {
|
||||
if( $topic->canComment( \IPS\Member::loggedIn(), FALSE ) && ( $topic->getPoll() and $topic->getPoll()->poll_only ) )
|
||||
{
|
||||
return 'topic_poll_can_comment';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $existingResolver($topic, $args, $context);
|
||||
}
|
||||
};
|
||||
|
||||
return $defaultFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the available sorting options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOrderByOptions()
|
||||
{
|
||||
$defaultArgs = parent::getOrderByOptions();
|
||||
return array_merge( $defaultArgs, array('last_comment', 'num_comments', 'views', 'author_name', 'last_comment_name', 'date', 'votes') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the comment type that goes with this item type
|
||||
*
|
||||
* @return ObjectType
|
||||
*/
|
||||
protected static function getCommentType()
|
||||
{
|
||||
return \IPS\forums\api\GraphQL\TypeRegistry::post();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the comments field - overridden from ItemType
|
||||
* If this is a question and order isn't date, then force order by votes
|
||||
*
|
||||
* @param \IPS\forums\Topic
|
||||
* @param array Arguments passed to this resolver
|
||||
* @return array
|
||||
*/
|
||||
protected static function comments($topic, $args)
|
||||
{
|
||||
if( $topic->isQuestion() && $args['orderBy'] !== 'date' )
|
||||
{
|
||||
if( $topic->isArchived() )
|
||||
{
|
||||
$args['orderBy'] = "archive_is_first desc, archive_bwoptions";
|
||||
$args['orderDir'] = "DESC";
|
||||
}
|
||||
else
|
||||
{
|
||||
$args['orderBy'] = "new_topic DESC, post_bwoptions DESC, post_field_int DESC, post_date";
|
||||
$args['orderDir'] = "ASC";
|
||||
}
|
||||
}
|
||||
elseif( !$topic->isQuestion() && $args['orderBy'] === 'votes' )
|
||||
{
|
||||
$args['orderBy'] = 'date'; // Only Q&A can order by votes
|
||||
}
|
||||
|
||||
return parent::comments($topic, $args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Vote Type
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 25 Jan 2019
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\forums\api\GraphQL\Types;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* VoteType for GraphQL API
|
||||
*/
|
||||
class _VoteType extends \GraphQL\Type\Definition\EnumType
|
||||
{
|
||||
/**
|
||||
* Get object type
|
||||
*
|
||||
* @return ObjectType
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$config = [
|
||||
'name' => 'forums_VoteType',
|
||||
'values' => ['UP', 'DOWN']
|
||||
];
|
||||
|
||||
parent::__construct( $config );
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\api;
|
||||
|
||||
/* 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;
|
||||
@@ -32,6 +32,7 @@ class _forums extends \IPS\Node\Api\NodeController
|
||||
* GET /forums/forums
|
||||
* Get list of forums
|
||||
*
|
||||
* @apiparam int clubs 0|1 Include club forums, default: 1
|
||||
* @apiparam int page Page number
|
||||
* @apiparam int perPage Number of results per page - defaults to 25
|
||||
* @note For requests using an OAuth Access Token for a particular member, only forums the authorized user can view will be included
|
||||
@@ -77,10 +78,20 @@ class _forums extends \IPS\Node\Api\NodeController
|
||||
* @apiparam int sitemap_priority 1-9 1 highest priority
|
||||
* @apiparam int min_content The minimum amount of posts to be able to view
|
||||
* @apiparam int can_see_others 0|1 Users can see topics posted by other users?
|
||||
* @apiparam object permissions An object with the keys as permission options (view, read, add, reply, attachments) and values as permissions to use (which may be * to grant access to all groups, or an array of group IDs to permit access to)
|
||||
* @apiparam string redirect_url If creating a redirect forum, the URL to redirect too.
|
||||
* @return \IPS\forums\Forum
|
||||
* @throws 1F363/2 NO_TITLE A title for the forum must be supplied
|
||||
* @throws 1F363/3 NO_REDIRECT_URL No redirect URL supplied.
|
||||
* @throws 1F363/4 INVALID_TYPE Invalid type of forum.
|
||||
*/
|
||||
public function POSTindex()
|
||||
{
|
||||
if ( !\IPS\Request::i()->title )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'NO_TITLE', '1F363/2', 400 );
|
||||
}
|
||||
|
||||
return new \IPS\Api\Response( 201, $this->_create()->apiOutput( $this->member ) );
|
||||
}
|
||||
|
||||
@@ -98,14 +109,19 @@ class _forums extends \IPS\Node\Api\NodeController
|
||||
* @apiparam int sitemap_priority 1-9 1 highest priority
|
||||
* @apiparam int min_content The minimum amount of posts to be able to view
|
||||
* @apiparam int can_see_others 0|1 Users can see topics posted by other users?
|
||||
* @apiparam object permissions An object with the keys as permission options (view, read, add, reply, attachments) and values as permissions to use (which may be * to grant access to all groups, or an array of group IDs to permit access to)
|
||||
* @apiparam string redirect_url If editing a redirect forum, the URL to redirect too.
|
||||
* @param int $id ID Number
|
||||
* @return \IPS\forums\Forum
|
||||
* @throws 1F363/3 NO_REDIRECT_URL No redirect URL supplied.
|
||||
* @throws 1F363/4 INVALID_TYPE Invalid type of forum.
|
||||
*/
|
||||
public function POSTitem( $id )
|
||||
{
|
||||
$class = $this->class;
|
||||
$forum = $class::load( $id );
|
||||
|
||||
return new \IPS\Api\Response( 201, $this->_createOrUpdate( $forum )->apiOutput( $this->member ) );
|
||||
return new \IPS\Api\Response( 200, $this->_createOrUpdate( $forum )->apiOutput( $this->member ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,27 +129,26 @@ class _forums extends \IPS\Node\Api\NodeController
|
||||
* Delete a forum
|
||||
*
|
||||
* @apiclientonly
|
||||
* @param int $id ID Number
|
||||
* @param int $id ID Number
|
||||
* @apiparam int deleteChildrenOrMove The ID number of the new parent or -1 to delete all child nodes.
|
||||
* @return void
|
||||
* @throws 1S359/1 INVALID_ID The node ID does not exist
|
||||
* @throws 1S359/2 INVALID_TARGET The target node cannot be deleted because the new parent node does not exist
|
||||
* @throws 1S359/3 HAS_CHILDREN The target node cannot be deleted because it has children (pass deleteChildrenOrMove in the request to specify how to handle the children)
|
||||
*/
|
||||
public function DELETEitem( $id )
|
||||
{
|
||||
return $this->_delete( $id );
|
||||
return $this->_delete( $id, \IPS\Request::i()->deleteChildrenOrMove ?? NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update node
|
||||
*
|
||||
* @param \IPS\Node\Model $node The node
|
||||
* @param \IPS\Node\Model $forum The node
|
||||
* @return \IPS\Node\Model
|
||||
*/
|
||||
protected function _createOrUpdate( \IPS\Node\Model $forum )
|
||||
{
|
||||
if ( !\IPS\Request::i()->title )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'NO_TITLE', '', 400 );
|
||||
}
|
||||
|
||||
foreach ( array( 'title' => "forums_forum_{$forum->id}", 'description' => "forums_forum_{$forum->id}_desc" ) as $fieldKey => $langKey )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->$fieldKey ) )
|
||||
@@ -147,7 +162,47 @@ class _forums extends \IPS\Node\Api\NodeController
|
||||
}
|
||||
}
|
||||
|
||||
$forum->parent_id = (int) \IPS\Request::i()->parent?: -1;
|
||||
$forum->parent_id = (int) \IPS\Request::i()->parent ?: -1;
|
||||
|
||||
if ( !isset( \IPS\Request::i()->type ) )
|
||||
{
|
||||
if ( $forum->parent_id === -1 )
|
||||
{
|
||||
\IPS\Request::i()->type = 'category';
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Request::i()->type = 'normal';
|
||||
}
|
||||
}
|
||||
|
||||
switch( \IPS\Request::i()->type )
|
||||
{
|
||||
case 'category':
|
||||
$forum->sub_can_post = 0;
|
||||
break;
|
||||
|
||||
case 'normal':
|
||||
$forum->sub_can_post = 1;
|
||||
break;
|
||||
|
||||
case 'qa':
|
||||
$forum->forums_bitoptions['bw_enable_answers'] = TRUE;
|
||||
break;
|
||||
|
||||
case 'redirect':
|
||||
if ( !isset( \IPS\Request::i()->redirect_url ) )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'NO_REDIRECT_URL', '1F363/3', 400 );
|
||||
}
|
||||
|
||||
$forum->redirect_on = 1;
|
||||
$forum->redirect_url = \IPS\Request::i()->redirect_url;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \IPS\Api\Exception( 'INVALID_TYPE', '1F363/4', 400 );
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->password ) )
|
||||
{
|
||||
@@ -159,6 +214,21 @@ class _forums extends \IPS\Node\Api\NodeController
|
||||
$forum->skin_id = \IPS\Request::i()->theme;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->sitemap_priority ) )
|
||||
{
|
||||
$forum->ipseo_priority = \IPS\Request::i()->sitemap_priority;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->min_content ) )
|
||||
{
|
||||
$forum->min_content = \IPS\Request::i()->min_content;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->can_see_others ) )
|
||||
{
|
||||
$forum->can_view_others = \IPS\Request::i()->can_see_others;
|
||||
}
|
||||
|
||||
return parent::_createOrUpdate( $forum );
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\api;
|
||||
|
||||
/* 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;
|
||||
@@ -117,7 +117,7 @@ class _posts extends \IPS\Content\Api\CommentController
|
||||
* POST /forums/posts
|
||||
* Create a post
|
||||
*
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, hidden will only be honoured if the authentictaed user has permission to hide content).
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, hidden will only be honoured if the authenticated user has permission to hide content).
|
||||
* @reqapiparam int topic The ID number of the topic the post should be created in
|
||||
* @reqapiparam int author The ID number of the member making the post (0 for guest). Required for requests made using an API Key or the Client Credentials Grant Type. For requests using an OAuth Access Token for a particular member, that member will always be the author
|
||||
* @apiparam string author_name If author is 0, the guest name that should be used
|
||||
@@ -183,7 +183,7 @@ class _posts extends \IPS\Content\Api\CommentController
|
||||
* POST /forums/posts/{id}
|
||||
* Edit a post
|
||||
*
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, hidden will only be honoured if the authentictaed user has permission to hide content).
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, hidden will only be honoured if the authenticated user has permission to hide content).
|
||||
* @param int $id ID Number
|
||||
* @apiparam int author The ID number of the member making the post (0 for guest). Ignored for requests using an OAuth Access Token for a particular member.
|
||||
* @apiparam string author_name If author is 0, the guest name that should be used
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\api;
|
||||
|
||||
/* 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,7 +42,7 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
* @apiparam int pinned If 1, only topics which are pinned are returned, if 0 only not pinned
|
||||
* @apiparam int featured If 1, only topics which are featured are returned, if 0 only not featured
|
||||
* @apiparam int archived If 1, only topics which are archived are returned, if 0 only not archived
|
||||
* @apiparam string sortBy What to sort by. Can be 'date', 'title' or leave unspecified for ID
|
||||
* @apiparam string sortBy What to sort by. Can be 'date', 'title', 'updated' or leave unspecified for ID
|
||||
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
|
||||
* @apiparam int page Page number
|
||||
* @apiparam int perPage Number of results per page - defaults to 25
|
||||
@@ -145,6 +145,9 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
{
|
||||
$item->topic_close_time = ( new \DateTime( \IPS\Request::i()->close_time ) )->getTimestamp();
|
||||
}
|
||||
|
||||
/* Do we have a poll to attach? */
|
||||
$this->_createOrUpdatePoll( $item, $type );
|
||||
|
||||
/* Pass up */
|
||||
return parent::_createOrUpdate( $item, $type );
|
||||
@@ -154,7 +157,7 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
* POST /forums/topics
|
||||
* Create a topic
|
||||
*
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, locked will only be honoured if the authentictaed user has permission to lock topics).
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, locked will only be honoured if the authenticated user has permission to lock topics).
|
||||
* @reqapiparam int forum The ID number of the forum the topic should be created in
|
||||
* @apiparam int author The ID number of the member creating the topic (0 for guest). Required for requests made using an API Key or the Client Credentials Grant Type. For requests using an OAuth Access Token for a particular member, that member will always be the author
|
||||
* @apiparam string author_name If author is 0, the guest name that should be used
|
||||
@@ -170,11 +173,15 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
* @apiparam int hidden 0 = unhidden; 1 = hidden, pending moderator approval; -1 = hidden (as if hidden by a moderator)
|
||||
* @apiparam int pinned 1/0 indicating if the topic should be pinned
|
||||
* @apiparam int featured 1/0 indicating if the topic should be featured
|
||||
* @apiparam string poll_title Poll title (to create a poll)
|
||||
* @apiparam bool poll_public Make the poll public
|
||||
* @apiparam bool poll_only Make this a poll-only topic
|
||||
* @apiparam array poll_options Array of objects with keys 'title' (string), 'answers' (array of objects with key 'value' set to the choice) and 'multichoice' (bool)
|
||||
* @throws 1F294/2 NO_FORUM The forum ID does not exist
|
||||
* @throws 1F294/3 NO_AUTHOR The author ID does not exist
|
||||
* @throws 1F294/5 NO_TITLE No title was supplied
|
||||
* @throws 1F294/4 NO_POST No post was supplied
|
||||
* @throws 2F294/9 NO_PERMISSION The authorized user does not have permission to create a topic in that forum
|
||||
* @throws 2F294/C NO_PERMISSION The authorized user does not have permission to create a topic in that forum
|
||||
* @return \IPS\forums\Topic
|
||||
*/
|
||||
public function POSTindex()
|
||||
@@ -194,7 +201,7 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
{
|
||||
if ( !$forum->can( 'add', $this->member ) )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'NO_PERMISSION', '2F294/9', 403 );
|
||||
throw new \IPS\Api\Exception( 'NO_PERMISSION', '2F294/C', 403 );
|
||||
}
|
||||
$author = $this->member;
|
||||
}
|
||||
@@ -233,7 +240,7 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
* POST /forums/topics/{id}
|
||||
* Edit a topic
|
||||
*
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, locked will only be honoured if the authentictaed user has permission to lock topics).
|
||||
* @note For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, locked will only be honoured if the authenticated user has permission to lock topics).
|
||||
* @apiparam int forum The ID number of the forum the topic should be created in
|
||||
* @apiparam int author The ID number of the member creating the topic (0 for guest). Ignored for requests using an OAuth Access Token for a particular member.
|
||||
* @apiparam string author_name If author is 0, the guest name that should be used
|
||||
@@ -249,6 +256,11 @@ class _topics extends \IPS\Content\Api\ItemController
|
||||
* @apiparam int hidden 1/0 indicating if the topic should be hidden
|
||||
* @apiparam int pinned 1/0 indicating if the topic should be pinned
|
||||
* @apiparam int featured 1/0 indicating if the topic should be featured
|
||||
* @apiparam string poll_title Poll title (to create a poll)
|
||||
* @apiparam bool poll_public Make the poll public
|
||||
* @apiparam bool poll_only Make this a poll-only topic
|
||||
* @apiparam array poll_options Array of objects with keys 'title' (string), 'answers' (array of objects with key 'value' set to the choice) and 'multichoice' (bool)
|
||||
* @param int $id ID Number
|
||||
* @throws 2F294/6 INVALID_ID The topic ID does not exist or the authorized user does not have permission to view it
|
||||
* @throws 1F294/7 NO_FORUM The forum ID does not exist or the authorized user does not have permission to post in it
|
||||
* @throws 1F294/8 NO_AUTHOR The author ID does not exist
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
"do": "",
|
||||
"restriction": "savedActions_manage"
|
||||
},
|
||||
"rss": {
|
||||
"tab": "community",
|
||||
"controller": "rss",
|
||||
"do": "",
|
||||
"restriction": "rss_manage"
|
||||
},
|
||||
"settings": {
|
||||
"tab": "community",
|
||||
"controller": "settings",
|
||||
|
||||
@@ -18,13 +18,6 @@
|
||||
"savedActions_add": "savedActions_add",
|
||||
"savedActions_edit": "savedActions_edit",
|
||||
"savedActions_delete": "savedActions_delete"
|
||||
},
|
||||
"rss": {
|
||||
"rss_manage": "rss_manage",
|
||||
"rss_add": "rss_add",
|
||||
"rss_edit": "rss_edit",
|
||||
"rss_delete": "rss_delete",
|
||||
"rss_run": "rss_run"
|
||||
}
|
||||
},
|
||||
"stats": {
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
"edit forum"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=forums&do=form&searchResult=forum_best_answer": {
|
||||
"lang_key": "bw_enable_answers_moderator",
|
||||
"restriction": "forums_manage",
|
||||
"keywords": [
|
||||
"answer",
|
||||
"best answer",
|
||||
"qa",
|
||||
"solved"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=forums&searchResult=bw_disable_prefixes": {
|
||||
"lang_key": "bw_disable_prefixes",
|
||||
"restriction": "forums_manage",
|
||||
@@ -476,163 +486,6 @@
|
||||
"sort order"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss": {
|
||||
"lang_key": "menu__forums_forums_rss",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"feed",
|
||||
"rss import"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&do=form": {
|
||||
"lang_key": "menu__forums_forums_rss",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"Atom Feed",
|
||||
"feed import",
|
||||
"RSS Feed"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_auth_pass": {
|
||||
"lang_key": "rss_import_auth_pass",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"authorization password",
|
||||
"http authorization",
|
||||
"http authorization password"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_auth_user": {
|
||||
"lang_key": "rss_import_auth_user",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"authorization username",
|
||||
"http authorization",
|
||||
"http authorization username"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_forum_id": {
|
||||
"lang_key": "rss_import_forum_id",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss forum"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_mid": {
|
||||
"lang_key": "rss_import_mid",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss author"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_showlink": {
|
||||
"lang_key": "rss_import_showlink",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"link text",
|
||||
"text link"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_topic_hide": {
|
||||
"lang_key": "rss_import_topic_hide",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss topic hidden",
|
||||
"rss topic unhidden"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_topic_open": {
|
||||
"lang_key": "rss_import_topic_open",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss topic closed",
|
||||
"rss topic open"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_topic_pre": {
|
||||
"lang_key": "rss_import_topic_pre",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss topic prefix"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_1_rss_import_url": {
|
||||
"lang_key": "rss_import_url",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss url"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_auth_pass": {
|
||||
"lang_key": "rss_import_auth_pass",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"http authorization",
|
||||
"http authorization password"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_auth_user": {
|
||||
"lang_key": "rss_import_auth_user",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"authorization username",
|
||||
"http authorization username"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_forum_id": {
|
||||
"lang_key": "rss_import_forum_id",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss forum"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_mid": {
|
||||
"lang_key": "rss_import_mid",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"author",
|
||||
"rss author"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_showlink": {
|
||||
"lang_key": "rss_import_showlink",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss link text"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_topic_hide": {
|
||||
"lang_key": "rss_import_topic_hide",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss topic hidden",
|
||||
"rss topic unhidden"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_topic_open": {
|
||||
"lang_key": "rss_import_topic_open",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"rss topic closed",
|
||||
"rss topic open"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_topic_pre": {
|
||||
"lang_key": "rss_import_topic_pre",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"prefix",
|
||||
"rss topic prefix",
|
||||
"topic prefix"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=rss&searchResult=form_rss_import_url": {
|
||||
"lang_key": "rss_import_url",
|
||||
"restriction": "rss_manage",
|
||||
"keywords": [
|
||||
"feed url"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=savedActions": {
|
||||
"lang_key": "menu__forums_forums_savedActions",
|
||||
"restriction": "savedActions_manage",
|
||||
@@ -863,6 +716,42 @@
|
||||
"rss export"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=settings&searchResult=form_forums_topic_activity": {
|
||||
"lang_key": "forums_topic_activity",
|
||||
"restriction": "settings_access",
|
||||
"keywords": [
|
||||
"desktop",
|
||||
"topic",
|
||||
"topic activity",
|
||||
"topic summary"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=settings&searchResult=form_forums_topic_activity_features": {
|
||||
"lang_key": "forums_topic_activity_features",
|
||||
"restriction": "settings_access",
|
||||
"keywords": [
|
||||
"attachments",
|
||||
"top post",
|
||||
"topic summary"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=settings&searchResult=form_forums_topics_show_meta": {
|
||||
"lang_key": "forums_topics_show_meta",
|
||||
"restriction": "settings_access",
|
||||
"keywords": [
|
||||
"comments",
|
||||
"posts"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=settings&searchResult=forums_topic_activity_desktop": {
|
||||
"lang_key": "forums_topic_activity_desktop",
|
||||
"restriction": "settings_access",
|
||||
"keywords": [
|
||||
"desktop",
|
||||
"tablet",
|
||||
"topic summary"
|
||||
]
|
||||
},
|
||||
"app=forums&module=forums&controller=settings&tab=archiving": {
|
||||
"lang_key": "archiving",
|
||||
"restriction": "archive_manage",
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<build>
|
||||
<module key="admin/forums"><![CDATA[{"default_controller":null,"protected":0,"default":1}]]></module>
|
||||
<module key="admin/stats"><![CDATA[{"default_controller":"topics","protected":0,"default":0}]]></module>
|
||||
<module key="front/forums"><![CDATA[{"default_controller":"index","protected":0,"default":1}]]></module>
|
||||
<task frequency="P0Y0M0DT0H5M0S">archive</task>
|
||||
<task frequency="P0Y0M0DT0H5M0S">unarchive</task>
|
||||
<setting key="archive_last_post_cloud"><![CDATA[{"key":"archive_last_post_cloud","default":"3","report":"full"}]]></setting>
|
||||
<setting key="archive_on"><![CDATA[{"key":"archive_on","default":"0","report":"full"}]]></setting>
|
||||
<setting key="archive_remote_sql_database"><![CDATA[{"key":"archive_remote_sql_database","default":"","report":"none"}]]></setting>
|
||||
<setting key="archive_remote_sql_host"><![CDATA[{"key":"archive_remote_sql_host","default":"","report":"none"}]]></setting>
|
||||
<setting key="archive_remote_sql_pass"><![CDATA[{"key":"archive_remote_sql_pass","default":"","report":"none"}]]></setting>
|
||||
<setting key="archive_remote_sql_user"><![CDATA[{"key":"archive_remote_sql_user","default":"","report":"none"}]]></setting>
|
||||
<setting key="archive_sql_port"><![CDATA[{"key":"archive_sql_port","default":"","report":"none"}]]></setting>
|
||||
<setting key="archive_sql_socket"><![CDATA[{"key":"archive_sql_socket","default":"","report":"none"}]]></setting>
|
||||
<setting key="archive_sql_tbl_prefix"><![CDATA[{"key":"archive_sql_tbl_prefix","default":"","report":"none"}]]></setting>
|
||||
<setting key="email_truncate"><![CDATA[{"key":"email_truncate","default":"1","report":"full"}]]></setting>
|
||||
<setting key="forums_answers_downvote"><![CDATA[{"key":"forums_answers_downvote","default":"1","report":"full"}]]></setting>
|
||||
<setting key="forums_default_view"><![CDATA[{"key":"forums_default_view","default":"table","report":"full"}]]></setting>
|
||||
<setting key="forums_default_view_choose"><![CDATA[{"key":"forums_default_view_choose","default":"0","report":"full"}]]></setting>
|
||||
<setting key="forums_fluid_pinned"><![CDATA[{"key":"forums_fluid_pinned","default":"1","report":"full"}]]></setting>
|
||||
<setting key="forums_new_questions"><![CDATA[{"key":"forums_new_questions","default":"0","report":"full"}]]></setting>
|
||||
<setting key="forums_popular_now"><![CDATA[{"key":"forums_popular_now","default":"{\"posts\":\"10\",\"minutes\":\"60\"}","report":"bool"}]]></setting>
|
||||
<setting key="forums_posts_per_page"><![CDATA[{"key":"forums_posts_per_page","default":"25","report":"full"}]]></setting>
|
||||
<setting key="forums_questions_downvote"><![CDATA[{"key":"forums_questions_downvote","default":"0","report":"full"}]]></setting>
|
||||
<setting key="forums_rss"><![CDATA[{"key":"forums_rss","default":"1","report":"full"}]]></setting>
|
||||
<setting key="forums_topic_activity"><![CDATA[{"key":"forums_topic_activity","default":"[\"desktop\",\"mobile\"]","report":"full"}]]></setting>
|
||||
<setting key="forums_topic_activity_desktop"><![CDATA[{"key":"forums_topic_activity_desktop","default":"sidebar","report":"full"}]]></setting>
|
||||
<setting key="forums_topic_activity_features"><![CDATA[{"key":"forums_topic_activity_features","default":"[\"popularDays\", \"topPost\", \"uploads\"]","report":"none"}]]></setting>
|
||||
<setting key="forums_topics_activity_pages_show"><![CDATA[{"key":"forums_topics_activity_pages_show","default":"3","report":"full"}]]></setting>
|
||||
<setting key="forums_topics_per_page"><![CDATA[{"key":"forums_topics_per_page","default":"25","report":"full"}]]></setting>
|
||||
<setting key="forums_topics_show_meta"><![CDATA[{"key":"forums_topics_show_meta","default":"[\"time\", \"moderation\"]","report":"full"}]]></setting>
|
||||
<setting key="forums_view_list_choose"><![CDATA[{"key":"forums_view_list_choose","default":"1","report":"full"}]]></setting>
|
||||
<setting key="forums_view_list_method"><![CDATA[{"key":"forums_view_list_method","default":"list","report":"full"}]]></setting>
|
||||
<widget key="forumStatistics"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true}]]></widget>
|
||||
<widget key="hotTopics"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true}]]></widget>
|
||||
<widget key="topicFeed"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":[],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="postFeed"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":[],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="poll"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums"><![CDATA[{"lang_key":"menu__forums_forums_forums","restriction":"forums_manage","keywords":["categories","forum","forums"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&do=form"><![CDATA[{"lang_key":"menu__forums_forums_forums","restriction":"forums_manage","keywords":["edit forum"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&do=form&searchResult=forum_best_answer"><![CDATA[{"lang_key":"bw_enable_answers_moderator","restriction":"forums_manage","keywords":["answer","best answer","qa","solved"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=bw_disable_prefixes"><![CDATA[{"lang_key":"bw_disable_prefixes","restriction":"forums_manage","keywords":["can set","can set tag prefixes","tag prefixes"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=bw_disable_tagging"><![CDATA[{"lang_key":"bw_disable_tagging","restriction":"forums_manage","keywords":["can use tags","tags","use tags"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_1_forum_description"><![CDATA[{"lang_key":"forum_description","restriction":"forums_manage","keywords":["category description","forum description"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_1_forum_name"><![CDATA[{"lang_key":"forum_name","restriction":"forums_manage","keywords":["category name","forum name"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_1_forum_parent_id"><![CDATA[{"lang_key":"forum_parent_id","restriction":"forums_manage","keywords":["parent","parent forum"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_1_forum_type"><![CDATA[{"lang_key":"forum_type","restriction":"forums_manage","keywords":["category type","discussions","questions","redirect"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_allow_poll"><![CDATA[{"lang_key":"forum_allow_poll","restriction":"forums_manage","keywords":["allow polls","polls"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_description"><![CDATA[{"lang_key":"forum_description","restriction":"forums_manage","keywords":["forum description"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_inc_postcount"><![CDATA[{"lang_key":"forum_inc_postcount","restriction":"forums_manage","keywords":["increase content","increase content counts","increase counts"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_min_posts_post"><![CDATA[{"lang_key":"forum_min_posts_post","restriction":"forums_manage","keywords":["minimum content count","minimum count"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_name"><![CDATA[{"lang_key":"forum_name","restriction":"forums_manage","keywords":["forum name"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_parent_id"><![CDATA[{"lang_key":"forum_parent_id","restriction":"forums_manage","keywords":["parent","parent forum"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_show_rules"><![CDATA[{"lang_key":"forum_show_rules","restriction":"forums_manage","keywords":["rules","show rules"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_2_forum_type"><![CDATA[{"lang_key":"forum_type","restriction":"forums_manage","keywords":["category","forum type","questions","redirect"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_allow_poll"><![CDATA[{"lang_key":"forum_allow_poll","restriction":"forums_manage","keywords":["allow polls","polls"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_description"><![CDATA[{"lang_key":"forum_description","restriction":"forums_manage","keywords":["description","forum description"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_inc_postcount"><![CDATA[{"lang_key":"forum_inc_postcount","restriction":"forums_manage","keywords":["content counts","increase content","increase content counts"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_min_posts_post"><![CDATA[{"lang_key":"forum_min_posts_post","restriction":"forums_manage","keywords":["count post","minimum content count"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_name"><![CDATA[{"lang_key":"forum_name","restriction":"forums_manage","keywords":["forum name"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_parent_id"><![CDATA[{"lang_key":"forum_parent_id","restriction":"forums_manage","keywords":["parent","parent forum"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_show_rules"><![CDATA[{"lang_key":"forum_show_rules","restriction":"forums_manage","keywords":["rules","show rules"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=form_new_forum_type"><![CDATA[{"lang_key":"forum_type","restriction":"forums_manage","keywords":["category","discussions","forum type","questions","redirect"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_allow_rating"><![CDATA[{"lang_key":"forum_forum_allow_rating","restriction":"forums_manage","keywords":["enable star","star","star ratings"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_can_view_others"><![CDATA[{"lang_key":"forum_can_view_others","restriction":"forums_manage","keywords":["other users","see topics","topics"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_disable_sharelinks"><![CDATA[{"lang_key":"forum_disable_sharelinks","restriction":"forums_manage","keywords":["enable sharing","sharing"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_icon"><![CDATA[{"lang_key":"forum_icon","restriction":"forums_manage","keywords":["forum icon","icon"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_ipseo_priority"><![CDATA[{"lang_key":"forum_ipseo_priority","restriction":"forums_manage","keywords":["sitemap priority"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_min_posts_view"><![CDATA[{"lang_key":"forum_min_posts_view","restriction":"forums_manage","keywords":["minimum content","minimum count","see forums"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_password_on"><![CDATA[{"lang_key":"forum_password_on","restriction":"forums_manage","keywords":["password","password protected","protected"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_permission_custom_error"><![CDATA[{"lang_key":"forum_permission_custom_error","restriction":"forums_manage","keywords":["custom error","error","no permission"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_permission_showtopic"><![CDATA[{"lang_key":"forum_permission_showtopic","restriction":"forums_manage","keywords":["read permission","without permission"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_preview_posts"><![CDATA[{"lang_key":"forum_preview_posts","restriction":"forums_manage","keywords":["approved","must approved","posts must"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&searchResult=forum_sort_key"><![CDATA[{"lang_key":"forum_sort_key","restriction":"forums_manage","keywords":["default sort","sort order"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=bw_disable_prefixes"><![CDATA[{"lang_key":"bw_disable_prefixes","restriction":"forums_manage","keywords":["can set tag prefixes","prefixes","set prefixes"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=bw_disable_tagging"><![CDATA[{"lang_key":"bw_disable_tagging","restriction":"forums_manage","keywords":["can use tags","tags","use tags"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_allow_poll"><![CDATA[{"lang_key":"forum_allow_poll","restriction":"forums_manage","keywords":["allow polls","polls"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_description"><![CDATA[{"lang_key":"forum_description","restriction":"forums_manage","keywords":["forum description"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_inc_postcount"><![CDATA[{"lang_key":"forum_inc_postcount","restriction":"forums_manage","keywords":["content counts","increase content","increase content counts","increase counts"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_min_posts_post"><![CDATA[{"lang_key":"forum_min_posts_post","restriction":"forums_manage","keywords":["content count post","minimum content count post","minimum count","minimum post"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_name"><![CDATA[{"lang_key":"forum_name","restriction":"forums_manage","keywords":["forum name"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_parent_id"><![CDATA[{"lang_key":"forum_parent_id","restriction":"forums_manage","keywords":["parent","parent forum"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_show_rules"><![CDATA[{"lang_key":"forum_show_rules","restriction":"forums_manage","keywords":["show rules"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=form_new_forum_type"><![CDATA[{"lang_key":"forum_type","restriction":"forums_manage","keywords":["categories","discussions","forum type","questions","redirect"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_allow_rating"><![CDATA[{"lang_key":"forum_forum_allow_rating","restriction":"forums_manage","keywords":["enable ratings","enable star ratings","star ratings"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_can_view_others"><![CDATA[{"lang_key":"forum_can_view_others","restriction":"forums_manage","keywords":["other users","see topics"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_disable_sharelinks"><![CDATA[{"lang_key":"forum_disable_sharelinks","restriction":"forums_manage","keywords":["enable sharing","sharing"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_icon"><![CDATA[{"lang_key":"forum_icon","restriction":"forums_manage","keywords":["forum icon","icon"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_ipseo_priority"><![CDATA[{"lang_key":"forum_ipseo_priority","restriction":"forums_manage","keywords":["priority","sitemap","sitemap priority"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_min_posts_view"><![CDATA[{"lang_key":"forum_min_posts_view","restriction":"forums_manage","keywords":["content count","minimum content","minimum content count","minimum count"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_password_on"><![CDATA[{"lang_key":"forum_password_on","restriction":"forums_manage","keywords":["forum password","password","protected"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_permission_custom_error"><![CDATA[{"lang_key":"forum_permission_custom_error","restriction":"forums_manage","keywords":["custom error","custom permission error","permission error"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_permission_showtopic"><![CDATA[{"lang_key":"forum_permission_showtopic","restriction":"forums_manage","keywords":["read permissions","users without","users without read permissions","without permissions"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_preview_posts"><![CDATA[{"lang_key":"forum_preview_posts","restriction":"forums_manage","keywords":["must approved","posts approved","posts must approved"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=forums&subnode=0&parent=2&searchResult=forum_sort_key"><![CDATA[{"lang_key":"forum_sort_key","restriction":"forums_manage","keywords":["default sort","default sort order","sort order"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions"><![CDATA[{"lang_key":"menu__forums_forums_savedActions","restriction":"savedActions_manage","keywords":["multi moderation","multimod","saved actions"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&do=form"><![CDATA[{"lang_key":"menu__forums_forums_savedActions","restriction":"savedActions_manage","keywords":["saved actions"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_mm_forums"><![CDATA[{"lang_key":"mm_forums","restriction":"savedActions_manage","keywords":["multimod forums","settings forums"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_mm_title"><![CDATA[{"lang_key":"mm_title","restriction":"savedActions_manage","keywords":["multimod name","name","settings name"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_approve"><![CDATA[{"lang_key":"topic_approve","restriction":"savedActions_manage","keywords":["hide","unhide"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_move"><![CDATA[{"lang_key":"topic_move","restriction":"savedActions_manage","keywords":["move"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_pin"><![CDATA[{"lang_key":"topic_pin","restriction":"savedActions_manage","keywords":["pin","unpin"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_reply"><![CDATA[{"lang_key":"topic_reply","restriction":"savedActions_manage","keywords":["add reply","reply"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_state"><![CDATA[{"lang_key":"topic_state","restriction":"savedActions_manage","keywords":["lock","unlock"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_title_end"><![CDATA[{"lang_key":"topic_title_end","restriction":"savedActions_manage","keywords":["add end","end title"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_1_topic_title_st"><![CDATA[{"lang_key":"topic_title_st","restriction":"savedActions_manage","keywords":["add start","start title"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_mm_forums"><![CDATA[{"lang_key":"mm_forums","restriction":"savedActions_manage","keywords":["actions forums","multimod forums"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_mm_title"><![CDATA[{"lang_key":"mm_title","restriction":"savedActions_manage","keywords":["actions name","multimod name","saved actions name"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_approve"><![CDATA[{"lang_key":"topic_approve","restriction":"savedActions_manage","keywords":["hide","properties","unhide"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_move"><![CDATA[{"lang_key":"topic_move","restriction":"savedActions_manage","keywords":["move","move forum"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_pin"><![CDATA[{"lang_key":"topic_pin","restriction":"savedActions_manage","keywords":[" pin topic","properties","unpin topic"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_reply"><![CDATA[{"lang_key":"topic_reply","restriction":"savedActions_manage","keywords":["add reply"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_state"><![CDATA[{"lang_key":"topic_state","restriction":"savedActions_manage","keywords":["lock","properties lock","properties unlock","unlock"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_title_end"><![CDATA[{"lang_key":"topic_title_end","restriction":"savedActions_manage","keywords":["add end","add title","end title"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=savedActions&searchResult=form_new_topic_title_st"><![CDATA[{"lang_key":"topic_title_st","restriction":"savedActions_manage","keywords":["add start","add title","start title"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings"><![CDATA[{"lang_key":"menu__forums_forums_settings","restriction":"settings_access","keywords":["forum settings"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_answers_downvote"><![CDATA[{"lang_key":"forums_answers_downvote","restriction":"settings_access","keywords":["answers","questions"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_default_view"><![CDATA[{"lang_key":"forums_default_view","restriction":"settings_access","keywords":["fluid","grid","mode","table","view"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_new_questions"><![CDATA[{"lang_key":"forums_new_questions","restriction":"settings_access","keywords":["answers","questions"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_popular_now"><![CDATA[{"lang_key":"forums_popular_now","restriction":"settings_access","keywords":["hot","popular"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_posts_per_page"><![CDATA[{"lang_key":"forums_posts_per_page","restriction":"settings_access","keywords":["posts per page"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_questions_downvote"><![CDATA[{"lang_key":"forums_questions_downvote","restriction":"settings_access","keywords":["answers","questions"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_rss"><![CDATA[{"lang_key":"forums_rss","restriction":"settings_access","keywords":["rss export"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_topic_activity"><![CDATA[{"lang_key":"forums_topic_activity","restriction":"settings_access","keywords":["desktop","topic","topic activity","topic summary"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_topic_activity_features"><![CDATA[{"lang_key":"forums_topic_activity_features","restriction":"settings_access","keywords":["attachments","top post","topic summary"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=form_forums_topics_show_meta"><![CDATA[{"lang_key":"forums_topics_show_meta","restriction":"settings_access","keywords":["comments","posts"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&searchResult=forums_topic_activity_desktop"><![CDATA[{"lang_key":"forums_topic_activity_desktop","restriction":"settings_access","keywords":["desktop","tablet","topic summary"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&tab=archiving"><![CDATA[{"lang_key":"archiving","restriction":"archive_manage","keywords":["archive","archiving"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&tab=archiving&searchResult=form_archive_on"><![CDATA[{"lang_key":"archive_on","restriction":"settings_access","keywords":["enable archiving"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=forums&controller=settings&tab=settings"><![CDATA[{"lang_key":"forum_settings","restriction":"settings_access","keywords":["forum settings"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=stats&controller=posts"><![CDATA[{"lang_key":"menu__forums_stats_posts","restriction":"posts_manage","keywords":["New Post Statistics","new post stats","post statistics","post stats"]}]]></acpsearch>
|
||||
<acpsearch key="app=forums&module=stats&controller=topics"><![CDATA[{"lang_key":"menu__forums_stats_topics","restriction":"topics_manage","keywords":["new topic stats","topic statistics","topic stats"]}]]></acpsearch>
|
||||
</build>
|
||||
@@ -18,7 +18,7 @@
|
||||
{$email->parseTextForEmail( $comment->content(), $email->language )|raw}
|
||||
</div>
|
||||
</td>
|
||||
</tr>]]></template_content_html><template_data>$comment, $email</template_data><template_content_plaintext><![CDATA[{{if $comment->item()->isQuestion()}}{$email->language->addToStack("x_answered_a_question", FALSE, array( 'sprintf' => array( $comment->author()->name ) ) )}{{else}}{$email->language->addToStack("x_replied_to_a_topic", FALSE, array( 'sprintf' => array( $comment->author()->name ) ) )}{{endif}}: {$comment->item()->mapped('title')} ({$comment->url()})
|
||||
</tr>]]></template_content_html><template_data>$comment, $email</template_data><template_content_plaintext><![CDATA[{{if $comment->item()->isQuestion()}}{$email->language->addToStack("x_answered_a_question", FALSE, array( 'htmlsprintf' => array( $comment->author()->name ) ) )}{{else}}{$email->language->addToStack("x_replied_to_a_topic", FALSE, array( 'htmlsprintf' => array( $comment->author()->name ) ) )}{{endif}}: {$comment->item()->mapped('title')} ({$comment->url()})
|
||||
]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>forums</template_app><template_name>digests__item</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
|
||||
<td dir='{dir}' width='40' align='center' valign='top' class=' '>
|
||||
<img src='{$topic->author()->get_photo( true, true )}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
|
||||
@@ -26,9 +26,9 @@
|
||||
<td dir='{dir}' align='left'>
|
||||
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
|
||||
{{if $topic->isQuestion()}}
|
||||
{$email->language->addToStack("x_asked_new_question", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->_title ) ) )}
|
||||
{$email->language->addToStack("x_asked_new_question", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->getTitleForLanguage( $email->language ) ) ) )}
|
||||
{{else}}
|
||||
{$email->language->addToStack("x_created_topic_in", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->_title ) ) )}
|
||||
{$email->language->addToStack("x_created_topic_in", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->getTitleForLanguage( $email->language ) ) ) )}
|
||||
{{endif}}
|
||||
</p>
|
||||
<h2 style="font-family: 'Helvetica Neue', helvetica, sans-serif; font-size: 20px; font-weight: 500 !important; margin: 0;">
|
||||
@@ -59,5 +59,5 @@
|
||||
</strong>
|
||||
</p>
|
||||
</td>
|
||||
</tr>]]></template_content_html><template_data>$topic, $email</template_data><template_content_plaintext><![CDATA[{{if $topic->isQuestion()}}{$email->language->addToStack("x_asked_new_question", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->_title ) ) )}{{else}}{$email->language->addToStack("x_created_topic_in", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->_title ) ) )}{{endif}}: {$topic->title} ({$topic->url()})
|
||||
</tr>]]></template_content_html><template_data>$topic, $email</template_data><template_content_plaintext><![CDATA[{{if $topic->isQuestion()}}{$email->language->addToStack("x_asked_new_question", FALSE, array( 'htmlsprintf' => array( $topic->author()->name, $topic->container()->getTitleForLanguage( $email->language ) ) ) )}{{else}}{$email->language->addToStack("x_created_topic_in", FALSE, array( 'htmlsprintf' => array( $topic->author()->name, $topic->container()->getTitleForLanguage( $email->language ) ) ) )}{{endif}}: {$topic->title} ({$topic->url()})
|
||||
]]></template_content_plaintext><template_pinned>0</template_pinned></template></emails>
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"core": {
|
||||
"RssImport": {
|
||||
"RssImport": "IPS\\forums\\extensions\\core\\RssImport\\RssImport"
|
||||
},
|
||||
"ContentRouter": {
|
||||
"Topics": "IPS\\forums\\extensions\\core\\ContentRouter\\Topics"
|
||||
},
|
||||
"LiveSearch": {
|
||||
"Forums": "IPS\\forums\\extensions\\core\\LiveSearch\\Forums"
|
||||
},
|
||||
"ContentModeratorPermissions": {
|
||||
"Topics": "IPS\\forums\\extensions\\core\\ContentModeratorPermissions\\Topics"
|
||||
},
|
||||
"FileStorage": {
|
||||
"Icons": "IPS\\forums\\extensions\\core\\FileStorage\\Icons",
|
||||
"Cards": "IPS\\forums\\extensions\\core\\FileStorage\\Cards"
|
||||
},
|
||||
"Announcements": {
|
||||
"Forums": "IPS\\forums\\extensions\\core\\Announcements\\Forums"
|
||||
},
|
||||
"EditorLocations": {
|
||||
"Forums": "IPS\\forums\\extensions\\core\\EditorLocations\\Forums"
|
||||
},
|
||||
"Permissions": {
|
||||
"Permissions": "IPS\\forums\\extensions\\core\\Permissions\\Permissions"
|
||||
},
|
||||
"CreateMenu": {
|
||||
"Topic": "IPS\\forums\\extensions\\core\\CreateMenu\\Topic"
|
||||
},
|
||||
"Queue": {
|
||||
"DeleteLegacyTopics": "IPS\\forums\\extensions\\core\\Queue\\DeleteLegacyTopics",
|
||||
"TopicStarterIds": "IPS\\forums\\extensions\\core\\Queue\\TopicStarterIds",
|
||||
"DeleteLegacyPosts": "IPS\\forums\\extensions\\core\\Queue\\DeleteLegacyPosts",
|
||||
"HiddenFirstPost": "IPS\\forums\\extensions\\core\\Queue\\HiddenFirstPost",
|
||||
"RebuildNewTopicFlag": "IPS\\forums\\extensions\\core\\Queue\\RebuildNewTopicFlag",
|
||||
"RebuildSolvedIndex": "IPS\\forums\\extensions\\core\\Queue\\RebuildSolvedIndex"
|
||||
},
|
||||
"FrontNavigation": {
|
||||
"Forums": "IPS\\forums\\extensions\\core\\FrontNavigation\\Forums"
|
||||
},
|
||||
"MemberSync": {
|
||||
"Forums": "IPS\\forums\\extensions\\core\\MemberSync\\Forums"
|
||||
},
|
||||
"MobileNavigation": {
|
||||
"Topics": "IPS\\forums\\extensions\\core\\MobileNavigation\\Topics",
|
||||
"Forums": "IPS\\forums\\extensions\\core\\MobileNavigation\\Forums"
|
||||
},
|
||||
"BBCode": {
|
||||
"post": "IPS\\forums\\extensions\\core\\BBCode\\post",
|
||||
"topic": "IPS\\forums\\extensions\\core\\BBCode\\topic",
|
||||
"snapback": "IPS\\forums\\extensions\\core\\BBCode\\snapback"
|
||||
},
|
||||
"AdvertisementLocations": {
|
||||
"IndexView": "IPS\\forums\\extensions\\core\\AdvertisementLocations\\IndexView",
|
||||
"TopicView": "IPS\\forums\\extensions\\core\\AdvertisementLocations\\TopicView",
|
||||
"ForumListing": "IPS\\forums\\extensions\\core\\AdvertisementLocations\\ForumListing"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@
|
||||
"forums_forum": {
|
||||
"friendly": "forum/{#id}-{?}",
|
||||
"real": "app=forums&module=forums&controller=forums",
|
||||
"verify": "\\IPS\\forums\\Forum"
|
||||
"verify": "\\IPS\\forums\\Forum",
|
||||
"seoPagination": true
|
||||
},
|
||||
"forums_clubs": {
|
||||
"friendly": "forum/clubs",
|
||||
@@ -44,7 +45,8 @@
|
||||
"forums_topic": {
|
||||
"friendly": "topic/{#id}-{?}",
|
||||
"real": "app=forums&module=forums&controller=topic",
|
||||
"verify": "\\IPS\\forums\\Topic"
|
||||
"verify": "\\IPS\\forums\\Topic",
|
||||
"seoPagination": true
|
||||
},
|
||||
"forums": {
|
||||
"friendly": "",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<javascript app="forums">
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.flow.js" javascript_type="controller" javascript_version="103038" javascript_position="1000100"><![CDATA[/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.flow.js" javascript_type="controller" javascript_version="105100" javascript_position="1000100"><![CDATA[/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -220,7 +220,7 @@
|
||||
}
|
||||
});
|
||||
}(jQuery, _));]]></file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumList.js" javascript_type="controller" javascript_version="103038" javascript_position="1000100"><![CDATA[/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumList.js" javascript_type="controller" javascript_version="105100" javascript_position="1000100"><![CDATA[/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -287,7 +287,7 @@
|
||||
}
|
||||
});
|
||||
}(jQuery, _));]]></file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumPage.js" javascript_type="controller" javascript_version="103038" javascript_position="1000100">/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumPage.js" javascript_type="controller" javascript_version="105100" javascript_position="1000100">/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -346,7 +346,7 @@
|
||||
}
|
||||
});
|
||||
}(jQuery, _));</file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.hovercard.js" javascript_type="controller" javascript_version="103038" javascript_position="1000100">/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.hovercard.js" javascript_type="controller" javascript_version="105100" javascript_position="1000100">/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -396,7 +396,7 @@
|
||||
}
|
||||
});
|
||||
}(jQuery, _));</file>
|
||||
<file javascript_app="forums" javascript_location="admin" javascript_path="controllers/settings" javascript_name="ips.settings.archiveRules.js" javascript_type="controller" javascript_version="103038" javascript_position="1000050"><![CDATA[/**
|
||||
<file javascript_app="forums" javascript_location="admin" javascript_path="controllers/settings" javascript_name="ips.settings.archiveRules.js" javascript_type="controller" javascript_version="105100" javascript_position="1000050"><![CDATA[/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -461,7 +461,39 @@
|
||||
});
|
||||
}(jQuery, _));
|
||||
]]></file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.answers.js" javascript_type="controller" javascript_version="103038" javascript_position="1000050"><![CDATA[/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.activity.js" javascript_type="controller" javascript_version="105100" javascript_position="1000050">/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
* ips.topic.activity.js - Topic activity controller
|
||||
*
|
||||
* Author: Rikki Tissier
|
||||
*/
|
||||
;( function($, _, undefined){
|
||||
"use strict";
|
||||
|
||||
ips.controller.register('forums.front.topic.activity', {
|
||||
|
||||
initialize: function () {
|
||||
this.on('click', '[data-action="toggleOverview"]', this.toggleOverview );
|
||||
},
|
||||
|
||||
toggleOverview: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if( this.scope.hasClass('cTopicOverview--expanded') ){
|
||||
this.scope.find('[data-role="preview"]').removeClass('ipsHide');
|
||||
this.scope.find('[data-role="overview"]').addClass('ipsHide');
|
||||
this.scope.removeClass('cTopicOverview--expanded');
|
||||
} else {
|
||||
this.scope.find('[data-role="preview"]').addClass('ipsHide');
|
||||
this.scope.find('[data-role="overview"]').removeClass('ipsHide');
|
||||
this.scope.addClass('cTopicOverview--expanded');
|
||||
}
|
||||
}
|
||||
});
|
||||
}(jQuery, _));</file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.answers.js" javascript_type="controller" javascript_version="105100" javascript_position="1000050"><![CDATA[/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -496,26 +528,62 @@
|
||||
|
||||
var self = this;
|
||||
var clicked = $( e.currentTarget );
|
||||
var positive = clicked.hasClass('cAnswerRate_up');
|
||||
var voteCount = this.scope.find('[data-role="voteCount"]');
|
||||
var currentVotes = parseInt( voteCount.attr('data-voteCount') );
|
||||
|
||||
this.scope.find('.cAnswerRate_up').toggleClass( 'ipsType_positive', positive );
|
||||
this.scope.find('.cAnswerRate_down').toggleClass( 'ipsType_negative', !positive );
|
||||
this.scope.toggleClass( 'cRatingColumn_up', positive ).toggleClass( 'cRatingColumn_down', !positive );
|
||||
|
||||
var newVoteCount = 0;
|
||||
|
||||
if( positive ){
|
||||
newVoteCount = currentVotes + 1;
|
||||
if( this.scope.find('.cAnswerRate_up').is('.ipsType_positive') ) {
|
||||
var currentVote = 'positive';
|
||||
}
|
||||
else if( this.scope.find('.cAnswerRate_down').is('.ipsType_negative') ) {
|
||||
var currentVote = 'negative';
|
||||
}
|
||||
else {
|
||||
newVoteCount = currentVotes - 1;
|
||||
var currentVote = false;
|
||||
}
|
||||
|
||||
var positive = clicked.hasClass('cAnswerRate_up');
|
||||
var voteCount = this.scope.find('[data-role="voteCount"]');
|
||||
var currentVotes = parseInt( voteCount.attr('data-voteCount') );
|
||||
|
||||
var newVoteCount = 0;
|
||||
var setPositive = false;
|
||||
var setNegative = false;
|
||||
|
||||
// Do we have a current vote?
|
||||
if( currentVote !== false ) {
|
||||
// If our current vote is positive and we clicked it again, we're removing our vote
|
||||
if( positive && currentVote == 'positive' ) {
|
||||
newVoteCount = currentVotes - 1;
|
||||
}
|
||||
// If our current vote is negative and we clicked it again, we're removing our vote
|
||||
else if( !positive && currentVote == 'negative' ) {
|
||||
newVoteCount = currentVotes + 1;
|
||||
}
|
||||
// Otherwise if our current vote is positive and we clicked negative...
|
||||
else if( !positive && currentVote == 'positive' ) {
|
||||
newVoteCount = currentVotes - 2;
|
||||
setNegative = true;
|
||||
}
|
||||
// Or our current vote is negative and we clicked positive
|
||||
else if( positive && currentVote == 'negative' ) {
|
||||
newVoteCount = currentVotes + 2;
|
||||
setPositive = true;
|
||||
}
|
||||
}
|
||||
// Otherwise if we clicked the positive icon...
|
||||
else if( positive ) {
|
||||
newVoteCount = currentVotes + 1;
|
||||
setPositive = true;
|
||||
}
|
||||
// Or we clicked the negative icon
|
||||
else {
|
||||
newVoteCount = currentVotes - 1;
|
||||
setNegative = true;
|
||||
}
|
||||
|
||||
this.setStyles( setPositive, setNegative );
|
||||
|
||||
voteCount
|
||||
.toggleClass( 'ipsType_positive', positive )
|
||||
.toggleClass( 'ipsType_negative', !positive )
|
||||
.toggleClass( 'ipsType_positive', setPositive )
|
||||
.toggleClass( 'ipsType_negative', setNegative )
|
||||
.text( newVoteCount )
|
||||
.attr( 'data-voteCount', newVoteCount );
|
||||
|
||||
@@ -524,42 +592,48 @@
|
||||
this.ajaxObj.abort();
|
||||
}
|
||||
|
||||
if( positive ){
|
||||
this.scope.find('a.cAnswerRate_up').addClass('ipsHide');
|
||||
this.scope.find('span.cAnswerRate_up').removeClass('ipsHide');
|
||||
} else {
|
||||
this.scope.find('a.cAnswerRate_down').addClass('ipsHide');
|
||||
this.scope.find('span.cAnswerRate_down').removeClass('ipsHide');
|
||||
}
|
||||
|
||||
this.ajaxObj = ips.getAjax()( clicked.attr('href') )
|
||||
.done( function (response) {
|
||||
|
||||
Debug.log( response );
|
||||
|
||||
if( !response.canVoteUp ){
|
||||
self.scope.find('a.cAnswerRate_up').addClass('ipsHide');
|
||||
self.scope.find('span.cAnswerRate_up').removeClass('ipsHide');
|
||||
} else {
|
||||
self.scope.find('a.cAnswerRate_up').removeClass('ipsHide');
|
||||
self.scope.find('span.cAnswerRate_up').addClass('ipsHide');
|
||||
}
|
||||
|
||||
if( !response.canVoteDown ){
|
||||
self.scope.find('a.cAnswerRate_down').addClass('ipsHide');
|
||||
self.scope.find('span.cAnswerRate_down').removeClass('ipsHide');
|
||||
} else {
|
||||
self.scope.find('a.cAnswerRate_down').removeClass('ipsHide');
|
||||
self.scope.find('span.cAnswerRate_down').addClass('ipsHide');
|
||||
}
|
||||
|
||||
voteCount.text( response.votes );
|
||||
self.scope.find('.ipsType_light').text( ips.pluralize( ips.getString( 'votes_no_number' ), response.votes ) );
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset CSS classes
|
||||
*
|
||||
* @param {bool} Set positive
|
||||
* @param {bool} Set negative
|
||||
*/
|
||||
setStyles: function( setPositive, setNegative ) {
|
||||
this.scope.find('.cAnswerRate_up').toggleClass( 'ipsType_positive', setPositive );
|
||||
this.scope.find('.cAnswerRate_down').toggleClass( 'ipsType_negative', setNegative );
|
||||
this.scope.toggleClass( 'cRatingColumn_up', setPositive ).toggleClass( 'cRatingColumn_down', setNegative );
|
||||
|
||||
// Reset tooltips
|
||||
this.scope.find('a.cAnswerRate_up').removeAttr( '_title' );
|
||||
this.scope.find('a.cAnswerRate_down').removeAttr( '_title' );
|
||||
|
||||
if( setPositive ) {
|
||||
this.scope.find('a.cAnswerRate_up').attr( 'title', ips.getString('js_remove_your_vote') );
|
||||
}
|
||||
else {
|
||||
this.scope.find('a.cAnswerRate_up').attr( 'title', ips.getString('js_vote_answer_up') );
|
||||
}
|
||||
|
||||
if( setNegative ) {
|
||||
this.scope.find('a.cAnswerRate_down').attr( 'title', ips.getString('js_remove_your_vote') );
|
||||
}
|
||||
else {
|
||||
this.scope.find('a.cAnswerRate_down').attr( 'title', ips.getString('js_vote_answer_down') );
|
||||
}
|
||||
}
|
||||
});
|
||||
}(jQuery, _));]]></file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.reply.js" javascript_type="controller" javascript_version="103038" javascript_position="1000050">/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.reply.js" javascript_type="controller" javascript_version="105100" javascript_position="1000050">/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -583,12 +657,11 @@
|
||||
* @returns {void}
|
||||
*/
|
||||
replyToTopic: function (e) {
|
||||
e.preventDefault();
|
||||
$( document ).trigger( 'replyToTopic' );
|
||||
}
|
||||
});
|
||||
}(jQuery, _));</file>
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.view.js" javascript_type="controller" javascript_version="103038" javascript_position="1000050">/**
|
||||
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.view.js" javascript_type="controller" javascript_version="105100" javascript_position="1000050">/**
|
||||
* Invision Community
|
||||
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
||||
*
|
||||
@@ -603,8 +676,38 @@
|
||||
|
||||
initialize: function () {
|
||||
$( document ).on( 'replyToTopic', _.bind( this.replyToTopic, this ) );
|
||||
this.on( 'click', '[data-action="showMoreActivity"]', this.showActivity );
|
||||
this.on( 'click', '[data-action="closeMoreActivity"]', this.hideActivity );
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens up the activity box when placed under the first post
|
||||
*
|
||||
* @param {event} e Event object
|
||||
* @returns {void}
|
||||
*/
|
||||
showActivity: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
this.scope.find('[data-role="moreActivity"]').show();
|
||||
this.scope.find('[data-action="showMoreActivity"]').hide();
|
||||
this.scope.find('[data-action="closeMoreActivity"]').show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the activity box when placed under the first post
|
||||
*
|
||||
* @param {event} e Event object
|
||||
* @returns {void}
|
||||
*/
|
||||
hideActivity: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
this.scope.find('[data-role="moreActivity"]').hide();
|
||||
this.scope.find('[data-action="showMoreActivity"]').show();
|
||||
this.scope.find('[data-action="closeMoreActivity"]').hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Triggers the initialize event on the editor
|
||||
*
|
||||
@@ -612,11 +715,11 @@
|
||||
* @returns {void}
|
||||
*/
|
||||
replyToTopic: function (e) {
|
||||
var editorID = this.scope.find('[data-role="replyArea"] [data-role="contentEditor"]').attr('name');
|
||||
|
||||
if( editorID ){
|
||||
this.trigger('initializeEditor', { editorID: editorID } );
|
||||
}
|
||||
ips.ui.editor.getObjWithInit( this.scope.find('[data-role="replyArea"] [data-ipsEditor]'), function(editor){
|
||||
editor.unminimize(function(){
|
||||
editor.focus();
|
||||
});
|
||||
} );
|
||||
}
|
||||
});
|
||||
}(jQuery, _));</file>
|
||||
@@ -630,9 +733,11 @@ controllers</order>
|
||||
jquery
|
||||
mustache
|
||||
jstz
|
||||
IntersectionObserver
|
||||
Debug.js
|
||||
app.js</order>
|
||||
<order app="global" path="/dev/js//library//jquery">jquery.js
|
||||
jquery-migrate.js
|
||||
jquery.history.js
|
||||
jquery.transform.js</order>
|
||||
<order app="global" path="/dev/js//library//linkify">linkify.min.js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<language>
|
||||
<app key="forums" version="103038">
|
||||
<app key="forums" version="105100">
|
||||
<word key="__app_forums" js="0">Forums</word>
|
||||
<word key="frontnavigation_forums" js="0">Forums</word>
|
||||
<word key="__indefart_post" js="0">a post in a topic</word>
|
||||
@@ -17,14 +17,16 @@
|
||||
<word key="module__forums_forums" js="0">Forums</word>
|
||||
<word key="module__forums_stats" js="0">Statistics</word>
|
||||
<word key="filestorage__forums_Icons" js="0">Forum Icons</word>
|
||||
<word key="filestorage__forums_Cards" js="0">Forum Cards</word>
|
||||
<word key="post" js="0">Post</word>
|
||||
<word key="post_lc" js="0">post</word>
|
||||
<word key="answer" js="0">Answer</word>
|
||||
<word key="answer_lc" js="0">answer</word>
|
||||
<word key="editor__forums_Forums" js="0">Forums and Topics</word>
|
||||
<word key="acp_search_title_forums_Forums" js="0">Forums</word>
|
||||
<word key="menu__forums_forums" js="0">Forums</word>
|
||||
<word key="menu__forums_forums_forums" js="0">Forums</word>
|
||||
<word key="menu__forums_forums_savedActions" js="0">Saved Actions</word>
|
||||
<word key="menu__forums_forums_rss" js="0">RSS/Atom Feeds</word>
|
||||
<word key="menu__forums_stats" js="0">Forums</word>
|
||||
<word key="menu__forums_stats_topics" js="0">New Topics</word>
|
||||
<word key="menu__forums_stats_posts" js="0">New Posts</word>
|
||||
@@ -38,12 +40,6 @@
|
||||
<word key="r__archive_manage" js="0">Can manage archive settings?</word>
|
||||
<word key="r__settings_access" js="0">Can access settings?</word>
|
||||
<word key="r__forum_settings" js="0">Can manage forums settings?</word>
|
||||
<word key="r__rss" js="0">Feeds</word>
|
||||
<word key="r__rss_manage" js="0">Can view feed imports?</word>
|
||||
<word key="r__rss_add" js="0">Can create feed imports?</word>
|
||||
<word key="r__rss_edit" js="0">Can edit feed imports?</word>
|
||||
<word key="r__rss_delete" js="0">Can delete feed imports?</word>
|
||||
<word key="r__rss_run" js="0">Can run feed imports?</word>
|
||||
<word key="r__savedActions" js="0">Saved Actions</word>
|
||||
<word key="r__savedActions_manage" js="0">Can view saved actions?</word>
|
||||
<word key="r__savedActions_add" js="0">Can create saved actions?</word>
|
||||
@@ -76,16 +72,18 @@
|
||||
<word key="can_delete_post" js="0">Can delete posts/answers?</word>
|
||||
<word key="can_read_all_topics" js="0">Can view all topics/questions?</word>
|
||||
<word key="can_read_all_topics_desc" js="0">Some forums are set up to only show topics/questions to the user that posted them. When this setting is enabled, the moderator will be able to view topics/questions they did not post in those forums.</word>
|
||||
<word key="can_set_best_answer" js="0">Can set best answer for questions?</word>
|
||||
<word key="can_set_best_answer" js="0">Can set best answer/solved for questions and topics?</word>
|
||||
<word key="can_feature_comments_topic" js="0">Can recommend posts on a topic?</word>
|
||||
<word key="can_unfeature_comments_topic" js="0">Can remove post recommendations on a topic?</word>
|
||||
<word key="can_add_item_message_topic" js="0">Can add messages to topics?</word>
|
||||
<word key="can_edit_item_message_topic" js="0">Can edit messages on topics?</word>
|
||||
<word key="can_delete_item_message_topic" js="0">Can delete messages on topics?</word>
|
||||
<word key="can_toggle_item_moderation_topic" js="0">Can enable/disable moderation on topics?</word>
|
||||
<word key="forums" js="0">Forums</word>
|
||||
<word key="forums_sg" js="0">Forum</word>
|
||||
<word key="forums_add_child" js="0">Create Subforum</word>
|
||||
<word key="forums_add_child_cat" js="0">Create Forum</word>
|
||||
<word key="all_public" js="0">All public</word>
|
||||
<word key="forum_name" js="0">Name</word>
|
||||
<word key="forum_description" js="0">Description</word>
|
||||
<word key="forum_description_placeholder" js="0">Add a description...</word>
|
||||
@@ -146,6 +144,8 @@
|
||||
<word key="forum_can_view_others_desc" js="0"><![CDATA[Moderators can (where they have permission) see all topics. You can use this setting to create a forum where users can communicate privately with staff.<br>Topics posted in a forum that doesn't allow others to view topics will not show in any sidebar, header or footer blocks.]]></word>
|
||||
<word key="forum_can_view_others_qa" js="0">Users can see questions asked by other users?</word>
|
||||
<word key="forum_can_view_others_qa_desc" js="0">Moderators can (where they have permission) see all questions. You can use this setting to create a private support forum.</word>
|
||||
<word key="forum_can_view_others_club" js="0">Users can see topics posted by other users?</word>
|
||||
<word key="forum_can_view_others_club_desc" js="0">You and any other moderators or leaders of this club will be able to see all topics. You can use this setting to create a forum where users can communicate privately with the club moderators.</word>
|
||||
<word key="forum_permission_showtopic" js="0">Users without read permission can open forum?</word>
|
||||
<word key="forum_permission_showtopic_desc" js="0">If a user does have permission to see the forum but not to read the topics, this setting controls whether or not they can open the forum and see the topic titles.</word>
|
||||
<word key="forum_permission_showtopic_qa" js="0">Users without read permission can open forum?</word>
|
||||
@@ -175,6 +175,12 @@
|
||||
<word key="forum_use_feature_color" js="0">Use a Feature Color?</word>
|
||||
<word key="forum_use_feature_color_desc" js="0">A feature color will show the forum title as a badge when used in a description.</word>
|
||||
<word key="forum_feature_color" js="0">Feature color</word>
|
||||
<word key="forum_card_image" js="0">Grid Card Image</word>
|
||||
<word key="forum_card_image_desc" js="0">When viewing forums as a grid, your chosen image will appear as the background.</word>
|
||||
<word key="bw_enable_answers_moderator" js="0">Enable Solved?</word>
|
||||
<word key="bw_enable_answers_moderator_desc" js="0">Moderators can mark posts as the solution.</word>
|
||||
<word key="bw_enable_answers__member" js="0">Allow the topic starter to mark solved?</word>
|
||||
<word key="bw_enable_answers__member_desc" js="0">Optionally allow the topic starter to also mark posts as the solution.</word>
|
||||
<word key="rebuilding_starter_ids" js="0">Rebuilding topic starter IDs</word>
|
||||
<word key="forums_topic_post" js="0">Forum Posts</word>
|
||||
<word key="forums_topic" js="0">Forum Topics</word>
|
||||
@@ -195,7 +201,6 @@
|
||||
<word key="forums_new_questions_best" js="0">Questions where a best answer has not been chosen.</word>
|
||||
<word key="forums_new_questions_any" js="0">Questions which have not received any answers.</word>
|
||||
<word key="forums_rss" js="0">Enable RSS feeds?</word>
|
||||
<word key="forums_rss_desc" js="0"><![CDATA[Only content that is available to guests will be shown. For more options, create a <a href='{internal.app=core&module=discovery&controller=rss}'>Custom RSS Feed</a>]]></word>
|
||||
<word key="forums_topics_per_page" js="0">Topics per page</word>
|
||||
<word key="forums_default_view" js="0">Default forum view</word>
|
||||
<word key="forums_default_view_table" js="0">Table: A traditional forum index table view</word>
|
||||
@@ -210,6 +215,7 @@
|
||||
<word key="forums_default_view_choose_error" js="0">You must select at least two views for members to choose from</word>
|
||||
<word key="archiving" js="0">Archiving</word>
|
||||
<word key="archiving_blurb" js="0">If you have a very large site, it can be beneficial to reduce the size of the database table storing posts. Archiving topics is an alternative to deleting which allows them to still exist and be viewed as normal, but moves them to a separate database table. Archived topics cannot be posted in or edited, and will not show in search results. You can unarchive topics after they've been archived if you change your mind.</word>
|
||||
<word key="archiving_blurb_cloud" js="0"><![CDATA[Archiving older <strong>non-pinned</strong> and <strong>non-featured</strong> topics keeps your community running smoothly. Archived topics cannot be posted in or edited, and will not show in search results. You can unarchive topics after they've been archived if you change your mind.]]></word>
|
||||
<word key="archive_topics_where" js="0"><![CDATA[Archive topics when <em>all</em> of the following conditions are true...]]></word>
|
||||
<word key="archive_topic_forums" js="0">In forums</word>
|
||||
<word key="archive_topic_not_forums" js="0">In forums</word>
|
||||
@@ -232,6 +238,8 @@
|
||||
<word key="archive_not_topic_view" js="0">Views</word>
|
||||
<word key="archive_not_topic_rating" js="0">Rating</word>
|
||||
<word key="archive_last_post" js="0">Last Post</word>
|
||||
<word key="archive_last_post_cloud" js="0">Last Post</word>
|
||||
<word key="archive_last_post_suffix" js="0">years ago</word>
|
||||
<word key="archive_not_last_post" js="0">Last Post</word>
|
||||
<word key="archive_storage" js="0">Archived Post Storage</word>
|
||||
<word key="archive_storage_location" js="0">Move archived posts to</word>
|
||||
@@ -240,11 +248,11 @@
|
||||
<word key="archive_storage_location_remote" js="0">A remote database</word>
|
||||
<word key="greater_than" js="0">More than</word>
|
||||
<word key="less_than" js="0">Less than</word>
|
||||
<word key="any_time" js="0">Any time</word>
|
||||
<word key="archive_rules_effects" js="0">Number of topics that will be archived with selected rules</word>
|
||||
<word key="forum_sort_key" js="0">Default sort order</word>
|
||||
<word key="forum_sort_key_qa" js="0">Default sort order</word>
|
||||
<word key="archive_settings" js="0">Archiving Settings</word>
|
||||
<word key="archive_settings_cloud" js="0">Archive where...</word>
|
||||
<word key="archive_on" js="0">Enable Archiving?</word>
|
||||
<word key="task__archive" js="0">Archives posts.</word>
|
||||
<word key="task__unarchive" js="0">Unarchives posts.</word>
|
||||
@@ -267,6 +275,8 @@
|
||||
<word key="archive_sql_tbl_prefix_desc" js="0">If provided, the archive database table created will be prefixed with the value provided. It is recommended this is left blank.</word>
|
||||
<word key="archive_remote_db_error" js="0">There was a problem with the remote database details provided: %s</word>
|
||||
<word key="acplogs__archive_settings" js="0">Edited Archive Settings</word>
|
||||
<word key="archived_topic_missing_posts" js="0">This topic's posts are not available currently. Please try again in a few minutes.</word>
|
||||
<word key="archived_topic_missing_posts_admin" js="0">Error Information (only shown to administrators)</word>
|
||||
<word key="perm_forum_perm__label" js="0"></word>
|
||||
<word key="perm_forum_perm__view" js="0">See Forum</word>
|
||||
<word key="perm_forum_perm__view_rest" js="0"><![CDATA[See Forum<br><small>(with {# [1:item][?:items]} of content)</small>]]></word>
|
||||
@@ -319,7 +329,7 @@
|
||||
<word key="topic_tags" js="0">Tags</word>
|
||||
<word key="topic_content" js="0"></word>
|
||||
<word key="topic_auto_follow" js="0"></word>
|
||||
<word key="topic_auto_follow_suffix" js="0">Notify me of replies</word>
|
||||
<word key="topic_auto_follow_suffix" js="0">Follow topic</word>
|
||||
<word key="topic_pollTab" js="0">Poll</word>
|
||||
<word key="topic_poll" js="0"></word>
|
||||
<word key="topic_open_time" js="0">Unlock time</word>
|
||||
@@ -380,6 +390,7 @@
|
||||
<word key="vote_answer_down" js="0">Vote this answer down</word>
|
||||
<word key="vote_question_up" js="0">Vote this question up</word>
|
||||
<word key="vote_question_down" js="0">Vote this question down</word>
|
||||
<word key="remove_your_vote" js="0">Remove your vote</word>
|
||||
<word key="best_answers" js="0">Best Answers</word>
|
||||
<word key="set_as_best_answer" js="0">Mark this as a best answer</word>
|
||||
<word key="unset_as_best_answer" js="0">Unset as best answer</word>
|
||||
@@ -445,8 +456,8 @@
|
||||
<word key="edit_topic" js="0">Edit Topic</word>
|
||||
<word key="edit_reply" js="0">Edit Post</word>
|
||||
<word key="go_to_forum" js="0">Go to %s</word>
|
||||
<word key="go_back_to_forum" js="0">Go To Topic Listing</word>
|
||||
<word key="go_back_to_qa_forum" js="0">Go To Question Listing</word>
|
||||
<word key="go_back_to_forum" js="0">Go to topic listing</word>
|
||||
<word key="go_back_to_qa_forum" js="0">Go to question listing</word>
|
||||
<word key="first_unread_post" js="0">Go to first unread post</word>
|
||||
<word key="get_last_post" js="0">Go to last post</word>
|
||||
<word key="topic_is_archived" js="0">Archived</word>
|
||||
@@ -471,7 +482,7 @@
|
||||
<word key="embed_topic" js="0">Forum Topic</word>
|
||||
<word key="questions_with_best_answers" js="0">Questions With Best Answers</word>
|
||||
<word key="questions_without_best_answers" js="0">Questions Without Best Answers</word>
|
||||
<word key="this_is_a_popular_post" js="0">This is a popular post.</word>
|
||||
<word key="this_is_a_popular_post" js="0">Popular Post</word>
|
||||
<word key="rate_this_topic" js="0">Rate this topic</word>
|
||||
<word key="rate_this_question" js="0">Rate this question</word>
|
||||
<word key="sign_in_rate_question" js="0">Sign in to rate this question</word>
|
||||
@@ -502,6 +513,12 @@
|
||||
<word key="topic_locks_at" js="0">Topic will be automatically locked %s at %s</word>
|
||||
<word key="topic_locks_at_short" js="0">Locks %s</word>
|
||||
<word key="club_node_forums" js="0">Club Forums</word>
|
||||
<word key="topic_meta_unread" js="0">Unread replies</word>
|
||||
<word key="forum_follower_count" js="0">{# [1:follower][?:followers]}</word>
|
||||
<word key="topic_follower_count" js="0">{# [1:follower][?:followers]}</word>
|
||||
<word key="forums_topic_list_snippet" js="0">Expanded View: Show topics with a preview of the post</word>
|
||||
<word key="forums_topic_list_list" js="0">Condensed View: Show topics as a list</word>
|
||||
<word key="topic_snippet_last_reply" js="0"><![CDATA[Last reply by %s, <a href='%s' title='Go to last post'>%s</a>]]></word>
|
||||
<word key="saved_actions" js="0">Saved Actions</word>
|
||||
<word key="saved_actions_sg" js="0">Saved Action</word>
|
||||
<word key="mm_title" js="0">Name</word>
|
||||
@@ -524,11 +541,11 @@
|
||||
<word key="modlog__saved_action" js="0"><![CDATA[Ran "%s" saved action on topic: <a href='%s'>%s</a>]]></word>
|
||||
<word key="modlog__unarchived_topic" js="0"><![CDATA[Unarchived topic: <a href='%s'>%s</a>]]></word>
|
||||
<word key="modlog__removed_archive_exclude_topic" js="0"><![CDATA[Removed 'exlude from archive' state from topic: <a href='%s'>%s</a>]]></word>
|
||||
<word key="task__rssimport" js="0">Checks RSS/Atom feeds for new articles and imports into Forums.</word>
|
||||
<word key="queue_deleting_legacy_topics" js="0">Deleting legacy topic data</word>
|
||||
<word key="queue_deleting_legacy_posts" js="0">Deleting legacy post data</word>
|
||||
<word key="queue_fixing_hidden_first_post" js="0">Updating incorrectly hidden topics</word>
|
||||
<word key="queue_rebuilding_new_topic_flag" js="0">Rebuilding new topic flag in posts</word>
|
||||
<word key="queue_rebuilding_solved_posts" js="0">Rebuilding solved post index</word>
|
||||
<word key="block_forumStatistics" js="0">Forum Statistics</word>
|
||||
<word key="block_forumStatistics_desc" js="0">Shows general forum statistics</word>
|
||||
<word key="total_topics" js="0">Total Topics</word>
|
||||
@@ -551,9 +568,13 @@
|
||||
<word key="x_replied_to_a_topic" js="0">%s replied to a topic</word>
|
||||
<word key="x_answered_a_question" js="0">%s answered a question</word>
|
||||
<word key="loc_forums_viewing_topic" js="0">Viewing Topic: %s</word>
|
||||
<word key="loc_forums_viewing_topic_action" js="0">%s is reading a topic</word>
|
||||
<word key="loc_forums_viewing_forum" js="0">Viewing Forum: %s</word>
|
||||
<word key="loc_forums_viewing_forum_action" js="0">%s is browsing a forum</word>
|
||||
<word key="loc_forums_creating_topic" js="0">Creating Topic in: %s</word>
|
||||
<word key="loc_forums_creating_topic_action" js="0">%s is creating a topic</word>
|
||||
<word key="loc_forums_index" js="0">Viewing Forums Index</word>
|
||||
<word key="loc_forums_index_action" js="0">%s is viewing the forum list</word>
|
||||
<word key="ad_forum_listing" js="0">After the first topic in each forum</word>
|
||||
<word key="ad_topic_view" js="0">After the first post in each topic</word>
|
||||
<word key="ad_fluid_index_view" js="0">Fluid view topic listing, between topic rows</word>
|
||||
@@ -574,17 +595,34 @@
|
||||
<word key="widget_feed_container_topic" js="0">Forums</word>
|
||||
<word key="block_topicFeed_title" js="0">Topics</word>
|
||||
<word key="block_postFeed_title" js="0">Posts</word>
|
||||
<word key="rssimport_task_error" js="0">Attempting to import the feed failed with the following message: %s</word>
|
||||
<word key="block_poll" js="0">Poll</word>
|
||||
<word key="block_poll_desc" js="0">Create a block with a poll from a topic</word>
|
||||
<word key="widget_poll_tid" js="0">Topic</word>
|
||||
<word key="widget_poll_tid_desc" js="0">Start typing the name of the topic</word>
|
||||
<word key="poll_view_topic" js="0">View topic</word>
|
||||
<word key="poll_widget_no_poll" js="0">The selected topic does not have an active poll.</word>
|
||||
<word key="__api_forums_posts" js="0">Posts</word>
|
||||
<word key="__api_forums_topics" js="0">Topics</word>
|
||||
<word key="__api_forums_forums" js="0">Forums</word>
|
||||
<word key="recommend_post" js="0">Recommend Post</word>
|
||||
<word key="recommended_posts" js="0">Recommended Posts</word>
|
||||
<word key="enable_topic_moderation" js="0">Enable Post Approval</word>
|
||||
<word key="disable_topic_moderation" js="0">Disable Post Approval</word>
|
||||
<word key="topic_moderation_enabled" js="0">Post Approval Enabled</word>
|
||||
<word key="enable_topic_moderation_confirm" js="0">If enabled, all new comments will require moderator approval before they will be displayed in this topic.</word>
|
||||
<word key="disable_topic_moderation_confirm" js="0">If disabled, new comments will no longer require moderator approval.</word>
|
||||
<word key="unsolve_content" js="0">Unmark as Solution</word>
|
||||
<word key="solve_content" js="0">Mark as Solution</word>
|
||||
<word key="this_is_a_solved_post" js="0">Solution</word>
|
||||
<word key="solved_and_go" js="0">Go to solution</word>
|
||||
<word key="this_is_solved" js="0">Solved</word>
|
||||
<word key="unsolved_topics" js="0">Unsolved Topics</word>
|
||||
<word key="solved_topics" js="0">Solved Topics</word>
|
||||
<word key="widget_feed_status_solved" js="0">Solved</word>
|
||||
<word key="solved_either" js="0">Solved and Unsolved</word>
|
||||
<word key="solved_solved" js="0">Solved</word>
|
||||
<word key="solved_unsolved" js="0">Unsolved</word>
|
||||
<word key="solved_byline" js="0">Solved by %s</word>
|
||||
<word key="forums_simple_name_with_container" js="0"><![CDATA[By %s in <a href='%s'>%s</a>]]></word>
|
||||
<word key="forums_show_all_forums" js="0">Table view</word>
|
||||
<word key="forums_show_all_forums_tooltip" js="0">Show a table of categories and forums</word>
|
||||
@@ -596,6 +634,74 @@
|
||||
<word key="forums_simple_dialog_title" js="0">Filter by forum</word>
|
||||
<word key="done_forum_filtering" js="0">Done</word>
|
||||
<word key="forums_chosen_forums" js="0">These Forums</word>
|
||||
<word key="forums_view_list_method" js="0">Default topic list view</word>
|
||||
<word key="forums_view_list_choose" js="0">Members can choose?</word>
|
||||
<word key="forums_view_list_choose_desc" js="0">Choose whether you wish to allow your members to toggle between the views. When set to 'no', members will always use the default topic list view.</word>
|
||||
<word key="topicactivity_created" js="0">Created</word>
|
||||
<word key="topicactivity_topposters" js="0">Top Posters In This Topic</word>
|
||||
<word key="topicactivity_topposters_qa" js="0">Top Posters For This Question</word>
|
||||
<word key="topicactivity_popularposts" js="0">Popular Posts</word>
|
||||
<word key="topicactivity_populardays" js="0">Popular Days</word>
|
||||
<word key="topicactivity_images" js="0">Posted Images</word>
|
||||
<word key="topicactivity_number_posts" js="0">{# [1:post][?:posts]}</word>
|
||||
<word key="forums_topic_activity" js="0">Devices</word>
|
||||
<word key="forums_topic_activity_desktop_on" js="0">Desktops/tablets</word>
|
||||
<word key="forums_topic_activity_mobile_on" js="0">Mobile devices</word>
|
||||
<word key="forums_topic_activity_mobile_on_desc" js="0">This will always show under the first post for mobile devices</word>
|
||||
<word key="forums_topic_activity_desktop" js="0">Position on Desktop/Tablet</word>
|
||||
<word key="forums_topic_activity_desktop_sidebar" js="0">Sidebar</word>
|
||||
<word key="forums_topic_activity_desktop_post" js="0">Under the first post</word>
|
||||
<word key="forums_topics_activity_pages_show_unlimited" js="0">Always show</word>
|
||||
<word key="forums_topics_activity_pages_show" js="0">Criteria</word>
|
||||
<word key="forums_topics_activity_pages_show_prefix" js="0">When the number of pages is at least</word>
|
||||
<word key="topic_summary_settings" js="0">Topic Summary Settings</word>
|
||||
<word key="forums_topic_activity_features" js="0">Content</word>
|
||||
<word key="forums_topic_activity_features_popularDays" js="0">Popular Days</word>
|
||||
<word key="forums_topic_activity_features_popularDays_desc" js="0">A list of the 4 days which had the most posts</word>
|
||||
<word key="forums_topic_activity_features_topPost" js="0">Top Posts</word>
|
||||
<word key="forums_topic_activity_features_topPost_desc" js="0">A list of the 3 posts with the most positive reactions</word>
|
||||
<word key="forums_topic_activity_features_uploads" js="0">Posted Images</word>
|
||||
<word key="forums_topics_show_meta" js="0">Show</word>
|
||||
<word key="forums_topic_show_meta_time" js="0">Large time gaps between posts</word>
|
||||
<word key="forums_topic_show_meta_moderation" js="0">Moderation events between posts</word>
|
||||
<word key="mobilenavigation_Topics" js="0">All Topics</word>
|
||||
<word key="mobilenavigation_Forums" js="0">Forums</word>
|
||||
<word key="app_forums" js="0">Forums</word>
|
||||
<word key="app_create_new_topic" js="0">Create New Topic</word>
|
||||
<word key="app_topics_title" js="0">Topics</word>
|
||||
<word key="app_subforums_title" js="0">Subforums</word>
|
||||
<word key="app_no_forum" js="0">The forum does not exist.</word>
|
||||
<word key="app_no_topic" js="0">The topic does not exist.</word>
|
||||
<word key="app_incorrect_forum_password" js="0">The password to this forum wasn't provided</word>
|
||||
<word key="app_no_post" js="0">The post does not exist.</word>
|
||||
<word key="app_invalid_topic" js="0">The topic couldn't be loaded.</word>
|
||||
<word key="app_not_question" js="0">This topic cannot be voted upon.</word>
|
||||
<word key="app_cannot_vote" js="0">You cannot vote on this question.</word>
|
||||
<word key="app_error_voting_question" js="0">There was a problem voting on this question.</word>
|
||||
<word key="app_replace_best_answer_title" js="0">Confirm</word>
|
||||
<word key="app_replace_best_answer_text" js="0">Are you sure you want to replace the current Best Answer with this one?</word>
|
||||
<word key="app_question_asked_by" js="0">Question asked by {{name}}</word>
|
||||
<word key="app_this_is_best_answer" js="0">Best answer to this question</word>
|
||||
<word key="app_all_topics" js="0">All Topics</word>
|
||||
<word key="app_all_topics_desc" js="0">Showing all topics from all forums</word>
|
||||
<word key="app_create_topic" js="0">Create Topic</word>
|
||||
<word key="app_confirm_discard_topic" js="0">Are you sure you want to discard this topic without posting?</word>
|
||||
<word key="app_confirm_discard_post" js="0">Are you sure you want to discard this reply without posting?</word>
|
||||
<word key="app_title_required" js="0">Title Required</word>
|
||||
<word key="app_title_required_desc" js="0">You must enter a topic title.</word>
|
||||
<word key="app_post_required" js="0">Post Required</word>
|
||||
<word key="app_post_required_desc" js="0">You must enter a post.</word>
|
||||
<word key="app_error_posting_topic" js="0">Sorry, there was an error posting this topic. </word>
|
||||
<word key="app_error_posting_post" js="0">Sorry, there was an error posting this reply. </word>
|
||||
<word key="app_topic_title" js="0">Topic Title</word>
|
||||
<word key="app_post_title" js="0">Post</word>
|
||||
<word key="app_topic_cannot_reply" js="0">Cannot Reply</word>
|
||||
<word key="app_topic_locked_can_comment" js="0">Locked, but you can reply...</word>
|
||||
<word key="app_topic_poll_can_comment" js="0">Poll-only, but you can reply...</word>
|
||||
<word key="app_topic_locked_cannot_comment" js="0">You don't have permission to reply because this topic is locked.</word>
|
||||
<word key="app_topic_restricted_cannot_comment" js="0">Your account is currently restricted from posting.</word>
|
||||
<word key="app_topic_unacknowledged_warning_cannot_post" js="0">You have received a warning that you must acknowledge before being able to post.</word>
|
||||
<word key="app_topic_member_exceeded_posts_per_day" js="0">You have reached the maximum number posts you can make per day.</word>
|
||||
<word key="forumMarkedRead" js="1">Forum marked as read</word>
|
||||
<word key="topicMarkedRead" js="1">Topic marked as read</word>
|
||||
<word key="js_num_topic_posts" js="1">{# [1:post][?:posts]} in this topic</word>
|
||||
@@ -603,5 +709,8 @@
|
||||
<word key="topicsFromAllForums" js="1">Showing topics from all forums</word>
|
||||
<word key="topicsFromXForums" js="1">Showing topics from {# [1:forum][?:forums]}</word>
|
||||
<word key="markForumAsReadConfirm" js="1">Are you sure you want to mark all topics in this forum as read?</word>
|
||||
<word key="js_vote_answer_up" js="1">Vote this answer up</word>
|
||||
<word key="js_vote_answer_down" js="1">Vote this answer down</word>
|
||||
<word key="js_remove_your_vote" js="1">Remove your vote</word>
|
||||
</app>
|
||||
</language>
|
||||
@@ -2,17 +2,20 @@
|
||||
"admin": {
|
||||
"forums": {
|
||||
"default_controller": null,
|
||||
"protected": 0
|
||||
"protected": 0,
|
||||
"default": 1
|
||||
},
|
||||
"stats": {
|
||||
"default_controller": "topics",
|
||||
"protected": 0
|
||||
"protected": 0,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"front": {
|
||||
"forums": {
|
||||
"default_controller": "index",
|
||||
"protected": 0
|
||||
"protected": 0,
|
||||
"default": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -631,6 +631,20 @@
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"card_image": {
|
||||
"allow_null": true,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "Card image file name",
|
||||
"decimals": null,
|
||||
"default": null,
|
||||
"length": 255,
|
||||
"name": "card_image",
|
||||
"type": "VARCHAR",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
@@ -659,12 +673,48 @@
|
||||
"min_posts_view": {
|
||||
"type": "key",
|
||||
"name": "min_posts_view",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"min_posts_view"
|
||||
]
|
||||
},
|
||||
"can_view_others": {
|
||||
"type": "key",
|
||||
"name": "can_view_others",
|
||||
"columns": [
|
||||
"can_view_others"
|
||||
],
|
||||
"length": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"forum_password": {
|
||||
"type": "key",
|
||||
"name": "forum_password",
|
||||
"columns": [
|
||||
"password"
|
||||
],
|
||||
"length": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"widget_performance": {
|
||||
"type": "key",
|
||||
"name": "widget_performance",
|
||||
"columns": [
|
||||
"min_posts_view",
|
||||
"password",
|
||||
"password_override",
|
||||
"can_view_others"
|
||||
],
|
||||
"length": [
|
||||
null,
|
||||
null,
|
||||
250,
|
||||
null
|
||||
]
|
||||
}
|
||||
},
|
||||
"collation": "utf8mb4_unicode_ci",
|
||||
@@ -936,18 +986,18 @@
|
||||
"zerofill": false
|
||||
},
|
||||
"views": {
|
||||
"allow_null": true,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 10,
|
||||
"name": "views",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"length": 10,
|
||||
"decimals": null,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
"allow_null": true,
|
||||
"default": "0",
|
||||
"comment": "",
|
||||
"unsigned": true,
|
||||
"zerofill": false,
|
||||
"auto_increment": false,
|
||||
"binary": false
|
||||
},
|
||||
"forum_id": {
|
||||
"allow_null": false,
|
||||
@@ -1230,18 +1280,16 @@
|
||||
"zerofill": false
|
||||
},
|
||||
"topic_meta_data": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": 0,
|
||||
"length": 1,
|
||||
"name": "topic_meta_data",
|
||||
"type": "BIT",
|
||||
"unsigned": false,
|
||||
"type": "TINYINT",
|
||||
"length": 1,
|
||||
"decimals": null,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
"allow_null": false,
|
||||
"default": "0",
|
||||
"comment": "",
|
||||
"unsigned": true,
|
||||
"auto_increment": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
@@ -1442,14 +1490,14 @@
|
||||
"last_post": "<%TIME%>",
|
||||
"starter_name": "<%ADMIN_NAME%>",
|
||||
"last_poster_name": "<%ADMIN_NAME%>",
|
||||
"poll_state": null,
|
||||
"poll_state": "",
|
||||
"last_vote": "0",
|
||||
"views": "0",
|
||||
"forum_id": "2",
|
||||
"approved": "1",
|
||||
"author_mode": "0",
|
||||
"pinned": "0",
|
||||
"moved_to": null,
|
||||
"moved_to": "",
|
||||
"topic_firstpost": "1",
|
||||
"topic_queuedposts": "0",
|
||||
"topic_open_time": "0",
|
||||
@@ -1463,7 +1511,9 @@
|
||||
"topic_answered_pid": "0",
|
||||
"popular_time": "0",
|
||||
"featured": "0",
|
||||
"question_rating": "0"
|
||||
"question_rating": "0",
|
||||
"topic_hiddenposts": "0",
|
||||
"topic_meta_data": "0"
|
||||
}
|
||||
],
|
||||
"comment": "",
|
||||
@@ -1859,7 +1909,7 @@
|
||||
"author_name": "<%ADMIN_NAME%>",
|
||||
"ip_address": "<%IP_ADDRESS%>",
|
||||
"post_date": "<%TIME%>",
|
||||
"post": "<p>Welcome to your new Invision Community!<\/p> <br \/><p> Congratulations on your purchase of our software and setting up your community. Please take some time and read through the Getting Started Guide and Administrator Documentation. The Getting Started Guide will walk you through some of the necessary steps to setting up an IP.Board and starting your community. The Administrator Documentation takes you through the details of the capabilities of IP.Board.<\/p> <br \/><p> You can remove this message, topic, forum or even category at any time.<\/p> <br \/><p><a href='https:\/\/remoteservices.invisionpower.com\/docs\/getting-started' rel='external'>Go to the documentation now...<\/a><br \/><p>Nulled by IPBMafia.ru<\/p>",
|
||||
"post": "<p>Welcome to your new Invision Community!<\/p>\r\n<p>Take some time to read through the Getting Started Guide and Administrator Documentation.<\/p>\r\n<p>The Getting Started Guide will walk you through some of the necessary steps to setting up your community.<\/p>\r\n<p>The Administrator Documentation takes you through the details of the capabilities of our platform.<\/p>\r\n<p><a href='https:\/\/remoteservices.invisionpower.com\/docs\/getting-started' rel='external'>Go to the Documentation<\/a><\/p><br \/><p>Nulled by IPBMafia.ru<\/p>",
|
||||
"queued": "0",
|
||||
"topic_id": "1",
|
||||
"new_topic": "1",
|
||||
@@ -1979,13 +2029,13 @@
|
||||
"member_rating": {
|
||||
"type": "unique",
|
||||
"name": "member_rating",
|
||||
"columns": [
|
||||
"member",
|
||||
"post"
|
||||
],
|
||||
"length": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"post",
|
||||
"member"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
@@ -2115,8 +2165,8 @@
|
||||
"type": "unique",
|
||||
"name": "member_rating",
|
||||
"columns": [
|
||||
"topic",
|
||||
"member"
|
||||
"member",
|
||||
"topic"
|
||||
],
|
||||
"length": [
|
||||
null,
|
||||
@@ -2132,6 +2182,18 @@
|
||||
"length": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"topic": {
|
||||
"type": "key",
|
||||
"name": "topic",
|
||||
"columns": [
|
||||
"topic",
|
||||
"member"
|
||||
],
|
||||
"length": [
|
||||
null,
|
||||
null
|
||||
]
|
||||
}
|
||||
},
|
||||
"comment": "",
|
||||
@@ -2859,344 +2921,6 @@
|
||||
"comment": "",
|
||||
"reporting": "count"
|
||||
},
|
||||
"forums_rss_import": {
|
||||
"name": "forums_rss_import",
|
||||
"columns": {
|
||||
"rss_import_id": {
|
||||
"allow_null": false,
|
||||
"auto_increment": true,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": null,
|
||||
"length": 10,
|
||||
"name": "rss_import_id",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_enabled": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 1,
|
||||
"name": "rss_import_enabled",
|
||||
"type": "TINYINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_title": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": 255,
|
||||
"name": "rss_import_title",
|
||||
"type": "VARCHAR",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_url": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": 255,
|
||||
"name": "rss_import_url",
|
||||
"type": "VARCHAR",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_forum_id": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 10,
|
||||
"name": "rss_import_forum_id",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_mid": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 20,
|
||||
"name": "rss_import_mid",
|
||||
"type": "BIGINT",
|
||||
"unsigned": true,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_pergo": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 3,
|
||||
"name": "rss_import_pergo",
|
||||
"type": "SMALLINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_time": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 3,
|
||||
"name": "rss_import_time",
|
||||
"type": "SMALLINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_last_import": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 10,
|
||||
"name": "rss_import_last_import",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_showlink": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 255,
|
||||
"name": "rss_import_showlink",
|
||||
"type": "VARCHAR",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_topic_open": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 1,
|
||||
"name": "rss_import_topic_open",
|
||||
"type": "TINYINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_topic_hide": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 1,
|
||||
"name": "rss_import_topic_hide",
|
||||
"type": "TINYINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_topic_pre": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "",
|
||||
"length": 50,
|
||||
"name": "rss_import_topic_pre",
|
||||
"type": "VARCHAR",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_allow_html": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 1,
|
||||
"name": "rss_import_allow_html",
|
||||
"type": "TINYINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_auth": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 1,
|
||||
"name": "rss_import_auth",
|
||||
"type": "TINYINT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_import_auth_user": {
|
||||
"name": "rss_import_auth_user",
|
||||
"type": "VARCHAR",
|
||||
"length": 255,
|
||||
"decimals": null,
|
||||
"values": [],
|
||||
"allow_null": true,
|
||||
"default": "Not Needed",
|
||||
"comment": "",
|
||||
"unsigned": false,
|
||||
"zerofill": false,
|
||||
"auto_increment": false,
|
||||
"binary": false
|
||||
},
|
||||
"rss_import_auth_pass": {
|
||||
"name": "rss_import_auth_pass",
|
||||
"type": "VARCHAR",
|
||||
"length": 255,
|
||||
"decimals": null,
|
||||
"values": [],
|
||||
"allow_null": true,
|
||||
"default": "Not Needed",
|
||||
"comment": "",
|
||||
"unsigned": false,
|
||||
"zerofill": false,
|
||||
"auto_increment": false,
|
||||
"binary": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"PRIMARY": {
|
||||
"type": "primary",
|
||||
"name": "PRIMARY",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"rss_import_id"
|
||||
]
|
||||
},
|
||||
"rss_grab": {
|
||||
"type": "key",
|
||||
"name": "rss_grab",
|
||||
"length": [
|
||||
null,
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"rss_import_enabled",
|
||||
"rss_import_last_import"
|
||||
]
|
||||
}
|
||||
},
|
||||
"comment": "",
|
||||
"reporting": "count"
|
||||
},
|
||||
"forums_rss_imported": {
|
||||
"name": "forums_rss_imported",
|
||||
"columns": {
|
||||
"rss_imported_guid": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 32,
|
||||
"name": "rss_imported_guid",
|
||||
"type": "CHAR",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_imported_tid": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 10,
|
||||
"name": "rss_imported_tid",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"rss_imported_impid": {
|
||||
"allow_null": false,
|
||||
"auto_increment": false,
|
||||
"binary": false,
|
||||
"comment": "",
|
||||
"decimals": null,
|
||||
"default": "0",
|
||||
"length": 10,
|
||||
"name": "rss_imported_impid",
|
||||
"type": "INT",
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"PRIMARY": {
|
||||
"type": "primary",
|
||||
"name": "PRIMARY",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"rss_imported_guid"
|
||||
]
|
||||
},
|
||||
"rss_imported_impid": {
|
||||
"type": "key",
|
||||
"name": "rss_imported_impid",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"columns": [
|
||||
"rss_imported_impid"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"forums_view_method": {
|
||||
"name": "forums_view_method",
|
||||
"columns": {
|
||||
@@ -3227,17 +2951,33 @@
|
||||
"unsigned": false,
|
||||
"values": [],
|
||||
"zerofill": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "VARCHAR",
|
||||
"length": 16,
|
||||
"decimals": null,
|
||||
"values": null,
|
||||
"allow_null": false,
|
||||
"default": "index",
|
||||
"comment": "",
|
||||
"unsigned": false,
|
||||
"zerofill": false,
|
||||
"auto_increment": false,
|
||||
"binary": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"PRIMARY": {
|
||||
"type": "primary",
|
||||
"name": "PRIMARY",
|
||||
"length": [
|
||||
null
|
||||
],
|
||||
"member_id": {
|
||||
"type": "unique",
|
||||
"name": "member_id",
|
||||
"columns": [
|
||||
"member_id"
|
||||
"member_id",
|
||||
"type"
|
||||
],
|
||||
"length": [
|
||||
null,
|
||||
null
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
[
|
||||
{
|
||||
"key": "archive_last_post_cloud",
|
||||
"default": "3",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "archive_on",
|
||||
"default": "0",
|
||||
@@ -39,6 +44,11 @@
|
||||
"default": "",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "email_truncate",
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_answers_downvote",
|
||||
"default": "1",
|
||||
@@ -84,9 +94,44 @@
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_topic_activity",
|
||||
"default": "[\"desktop\",\"mobile\"]",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_topic_activity_desktop",
|
||||
"default": "sidebar",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_topic_activity_features",
|
||||
"default": "[\"popularDays\", \"topPost\", \"uploads\"]",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "forums_topics_activity_pages_show",
|
||||
"default": "3",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_topics_per_page",
|
||||
"default": "25",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_topics_show_meta",
|
||||
"default": "[\"time\", \"moderation\"]",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_view_list_choose",
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "forums_view_list_method",
|
||||
"default": "list",
|
||||
"report": "full"
|
||||
}
|
||||
]
|
||||
@@ -1 +1 @@
|
||||
{"archive":"P0Y0M0DT0H5M0S","rssimport":"P0Y0M0DT0H15M0S","unarchive":"P0Y0M0DT0H5M0S"}
|
||||
{"archive":"P0Y0M0DT0H5M0S","unarchive":"P0Y0M0DT0H5M0S"}
|
||||
+2099
-1020
File diff suppressed because it is too large.
Load diff
@@ -244,5 +244,96 @@
|
||||
"103035": "4.3.6",
|
||||
"103036": "4.3.6",
|
||||
"103037": "4.3.6",
|
||||
"103038": "4.3.6"
|
||||
"103038": "4.3.6",
|
||||
"103039": "4.3.6",
|
||||
"104000": "4.4.0 Beta 1",
|
||||
"104001": "4.4.0 Beta 2",
|
||||
"104002": "4.4.0 Beta 3",
|
||||
"104003": "4.4.0 Beta 4",
|
||||
"104005": "4.4.0",
|
||||
"104006": "4.4.0",
|
||||
"104007": "4.4.0",
|
||||
"104008": "4.4.0",
|
||||
"104009": "4.4.1",
|
||||
"104010": "4.4.1 Beta 2",
|
||||
"104011": "4.4.1",
|
||||
"104012": "4.4.1",
|
||||
"104013": "4.4.1",
|
||||
"104014": "4.4.1",
|
||||
"104015": "4.4.2 Beta 1",
|
||||
"104016": "4.4.2",
|
||||
"104017": "4.4.2",
|
||||
"104018": "4.4.2",
|
||||
"104019": "4.4.2",
|
||||
"104020": "4.4.2",
|
||||
"104021": "4.4.3 Beta 1",
|
||||
"104022": "4.4.3 Beta 2",
|
||||
"104023": "4.4.3",
|
||||
"104024": "4.4.3",
|
||||
"104025": "4.4.3",
|
||||
"104026": "4.4.4 Beta 1",
|
||||
"104027": "4.4.4",
|
||||
"104028": "4.4.4",
|
||||
"104029": "4.4.4",
|
||||
"104030": "4.4.5 Beta 1",
|
||||
"104031": "4.4.5 Beta 2",
|
||||
"104032": "4.4.5 Beta 2",
|
||||
"104033": "4.4.5",
|
||||
"104034": "4.4.5",
|
||||
"104035": "4.4.5",
|
||||
"104036": "4.4.5",
|
||||
"104037": "4.4.5",
|
||||
"104038": "4.4.6",
|
||||
"104039": "4.4.6",
|
||||
"104040": "4.4.6",
|
||||
"104041": "4.4.7 Beta 1",
|
||||
"104042": "4.4.7 Beta 2",
|
||||
"104043": "4.4.7 Beta 3",
|
||||
"104044": "4.4.7",
|
||||
"104045": "4.4.8 Beta 1",
|
||||
"104046": "4.4.8 Beta 2",
|
||||
"104047": "4.4.8",
|
||||
"104048": "4.4.9 Beta 1",
|
||||
"104049": "4.4.9",
|
||||
"104050": "4.4.9",
|
||||
"104051": "4.4.9",
|
||||
"104052": "4.4.9",
|
||||
"104053": "4.4.9.1",
|
||||
"104054": "4.4.9.1",
|
||||
"104055": "4.4.9.2",
|
||||
"104056": "4.4.9.2",
|
||||
"104057": "4.4.10 Beta 1",
|
||||
"104058": "4.4.10 Beta 2",
|
||||
"104059": "4.4.10 Beta 3",
|
||||
"104060": "4.4.10 Beta 4",
|
||||
"104061": "4.4.10",
|
||||
"104062": "4.4.10",
|
||||
"104063": "4.4.10",
|
||||
"104064": "4.4.10",
|
||||
"104065": "4.4.10",
|
||||
"104066": "4.4.10",
|
||||
"104067": "4.4.10",
|
||||
"104068": "4.4.10",
|
||||
"104069": "4.4.10",
|
||||
"105013": "4.5.0 Beta 1",
|
||||
"105014": "4.5.0 Beta 1",
|
||||
"105015": "4.5.0 Beta 2",
|
||||
"105016": "4.5.0 Beta 3",
|
||||
"105017": "4.5.0 Beta 4",
|
||||
"105018": "4.5.0 Beta 4",
|
||||
"105019": "4.5.0 Beta 4",
|
||||
"105020": "4.5.0 Beta 4",
|
||||
"105021": "4.5.0 Beta 5",
|
||||
"105022": "4.5.0 Beta 6",
|
||||
"105023": "4.5.0 Beta 6",
|
||||
"105024": "4.5.0 Beta 7",
|
||||
"105025": "4.5.0 Beta 8",
|
||||
"105026": "4.5.0 Beta 8",
|
||||
"105027": "4.5.0 Beta 8",
|
||||
"105028": "4.5.0 Beta 9",
|
||||
"105029": "4.5.0 Beta 10",
|
||||
"105030": "4.5.0 Beta 11",
|
||||
"105031": "4.5.0 Beta 11",
|
||||
"105032": "4.5.0 Beta 12",
|
||||
"105100": "4.5.0"
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\AdvertisementLocations;
|
||||
|
||||
/* 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\extensions\core\AdvertisementLocations;
|
||||
|
||||
/* 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\extensions\core\AdvertisementLocations;
|
||||
|
||||
/* 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\extensions\core\Announcements;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\BBCode;
|
||||
|
||||
/* 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;
|
||||
@@ -60,7 +60,7 @@ class _post
|
||||
{
|
||||
try
|
||||
{
|
||||
$node->setAttribute( 'href', (string) \IPS\forums\Topic\Post::load( intval( $matches[2] ) )->url() );
|
||||
$node->setAttribute( 'href', (string) \IPS\forums\Topic\Post::load( \intval( $matches[2] ) )->url() );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\BBCode;
|
||||
|
||||
/* 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;
|
||||
@@ -60,7 +60,7 @@ class _snapback
|
||||
{
|
||||
try
|
||||
{
|
||||
$node->setAttribute( 'href', (string) \IPS\forums\Topic\Post::load( intval( $matches[2] ) )->url() );
|
||||
$node->setAttribute( 'href', (string) \IPS\forums\Topic\Post::load( \intval( $matches[2] ) )->url() );
|
||||
$node->appendChild( $document->createEntityReference( 'larr' ) );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\BBCode;
|
||||
|
||||
/* 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;
|
||||
@@ -60,7 +60,7 @@ class _topic
|
||||
{
|
||||
try
|
||||
{
|
||||
$node->setAttribute( 'href', (string) \IPS\forums\Topic::load( intval( $matches[2] ) )->url() );
|
||||
$node->setAttribute( 'href', (string) \IPS\forums\Topic::load( \intval( $matches[2] ) )->url() );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\ContentModeratorPermissions;
|
||||
|
||||
/* 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;
|
||||
@@ -45,7 +45,7 @@ class _Topics
|
||||
{
|
||||
$return = array();
|
||||
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'forums_forums', 'can_view_others=0' )->first() )
|
||||
if ( \IPS\Db::i()->select( 'COUNT(*)', 'forums_forums', 'can_view_others=0 AND club_id IS NULL' )->first() )
|
||||
{
|
||||
$return['can_read_all_topics'] = 'YesNo';
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class _Topics
|
||||
*/
|
||||
public function reindexAuthorOnlyForums( $deleteFirst )
|
||||
{
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_forums', 'can_view_others=0' ), 'IPS\forums\Forum' ) as $forum )
|
||||
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_forums', 'can_view_others=0 AND club_id IS NULL' ), 'IPS\forums\Forum' ) as $forum )
|
||||
{
|
||||
if ( $deleteFirst )
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\ContentRouter;
|
||||
|
||||
/* 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\extensions\core\CreateMenu;
|
||||
|
||||
/* 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\extensions\core\EditorLocations;
|
||||
|
||||
/* 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;
|
||||
@@ -164,26 +164,46 @@ class _Forums
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Store image proxy status ( true = enabled )
|
||||
* @brief Use the cached image URL instead of the original URL
|
||||
*/
|
||||
protected $_imageProxyStatus = null;
|
||||
protected $proxyUrl = FALSE;
|
||||
|
||||
/**
|
||||
* Rebuild content to add or remove image proxy
|
||||
*
|
||||
* @param int|null $offset Offset to start from
|
||||
* @param int|null $max Maximum to parse
|
||||
* @param bool $status Enable/Disable Image Proxy
|
||||
* @param bool $proxyUrl Use the cached image URL instead of the original URL
|
||||
* @return int Number completed
|
||||
* @note This method is optional and will only be called if it exists
|
||||
*/
|
||||
public function rebuildImageProxy( $offset, $max, $status=TRUE )
|
||||
public function rebuildImageProxy( $offset, $max, $proxyUrl = FALSE )
|
||||
{
|
||||
$this->_imageProxyStatus = $status;
|
||||
|
||||
$this->proxyUrl = $proxyUrl;
|
||||
return $this->performRebuild( $offset, $max, 'parseImageProxy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Store lazy loading status ( true = enabled )
|
||||
*/
|
||||
protected $_lazyLoadStatus = null;
|
||||
|
||||
/**
|
||||
* Rebuild content to add or remove lazy loading
|
||||
*
|
||||
* @param int|null $offset Offset to start from
|
||||
* @param int|null $max Maximum to parse
|
||||
* @param bool $status Enable/Disable lazy loading
|
||||
* @return int Number completed
|
||||
* @note This method is optional and will only be called if it exists
|
||||
*/
|
||||
public function rebuildLazyLoad( $offset, $max, $status=TRUE )
|
||||
{
|
||||
$this->_lazyLoadStatus = $status;
|
||||
|
||||
return $this->performRebuild( $offset, $max, 'parseLazyLoad' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform rebuild - abstracted as the call for rebuildContent() and rebuildAttachmentImages() is nearly identical
|
||||
*
|
||||
@@ -205,11 +225,15 @@ class _Forums
|
||||
{
|
||||
if( $callback == 'parseImageProxy' )
|
||||
{
|
||||
$rebuilt = \IPS\Text\Parser::parseImageProxy( $word['word_custom'], $this->_imageProxyStatus );
|
||||
$rebuilt = \IPS\Text\Parser::removeImageProxy( $word['word_custom'], $this->proxyUrl );
|
||||
}
|
||||
elseif( $callback == 'parseLazyLoad' )
|
||||
{
|
||||
$rebuilt = \IPS\Text\Parser::parseLazyLoad( $word['word_custom'], $this->_lazyLoadStatus );
|
||||
}
|
||||
else
|
||||
{
|
||||
$rebuilt = call_user_func( $callback, $word['word_custom'] );
|
||||
$rebuilt = $callback( $word['word_custom'] );
|
||||
}
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief File Storage Extension: Cards
|
||||
* @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 24 January 2020
|
||||
*/
|
||||
|
||||
namespace IPS\forums\extensions\core\FileStorage;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: Cards
|
||||
*/
|
||||
class _Cards
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', 'forums_forums', 'card_image IS NOT NULL' )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move stored files
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws \Underflowexception When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void
|
||||
*/
|
||||
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
|
||||
{
|
||||
$file = \IPS\Db::i()->select( '*', 'forums_forums', 'card_image IS NOT NULL', 'id', array( $offset, 1 ) )->first();
|
||||
|
||||
try
|
||||
{
|
||||
$forum = \IPS\forums\Forum::constructFromData( $file );
|
||||
$forum->icon = \IPS\File::get( $oldConfiguration ?: 'forums_Cards', $forum->icon )->move( $storageConfiguration );
|
||||
$forum->save();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix all URLs
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @return void
|
||||
*/
|
||||
public function fixUrls( $offset )
|
||||
{
|
||||
$forum = \IPS\forums\Forum::constructFromData( \IPS\Db::i()->select( '*', 'forums_forums', 'card_image IS NOT NULL', 'id', array( $offset, 1 ) )->first() );
|
||||
|
||||
if ( $new = \IPS\File::repairUrl( $forum->icon ) )
|
||||
{
|
||||
$forum->icon = $new;
|
||||
$forum->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( $file )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->select( 'id', 'forums_forums', array( 'card_image=?', $file ) )->first();
|
||||
return TRUE;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'forums_forums', "card_image IS NOT NULL" ) as $forum )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'forums_Cards', $forum['icon'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\FileStorage;
|
||||
|
||||
/* 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\extensions\core\FrontNavigation;
|
||||
|
||||
/* 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\extensions\core\LiveSearch;
|
||||
|
||||
/* 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;
|
||||
@@ -26,7 +26,7 @@ class _Forums
|
||||
/**
|
||||
* Check we have access
|
||||
*
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAccess()
|
||||
{
|
||||
@@ -37,7 +37,7 @@ class _Forums
|
||||
/**
|
||||
* Get the search results
|
||||
*
|
||||
* @param string Search Term
|
||||
* @param string $searchTerm Search Term
|
||||
* @return array Array of results
|
||||
*/
|
||||
public function getResults( $searchTerm )
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\MemberSync;
|
||||
|
||||
/* 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;
|
||||
@@ -32,23 +32,30 @@ class _Forums
|
||||
*/
|
||||
public function onMerge( $member, $member2 )
|
||||
{
|
||||
\IPS\Db::i()->update( 'forums_answer_ratings', array( 'member' => $member->member_id ), array( 'member=?', $member2->member_id ), array(), NULL, \IPS\Db::IGNORE );
|
||||
\IPS\Db::i()->update( 'forums_question_ratings', array( 'member' => $member->member_id ), array( 'member=?', $member2->member_id ), array(), NULL, \IPS\Db::IGNORE );
|
||||
\IPS\Db::i()->update( 'forums_answer_ratings', array( 'member' => $member->member_id ), array( '`member`=?', $member2->member_id ), array(), NULL, \IPS\Db::IGNORE );
|
||||
\IPS\Db::i()->update( 'forums_question_ratings', array( 'member' => $member->member_id ), array( '`member`=?', $member2->member_id ), array(), NULL, \IPS\Db::IGNORE );
|
||||
\IPS\Db::i()->update( 'forums_view_method', array( 'member_id' => $member->member_id ), array( 'member_id=?', $member2->member_id ), array(), NULL, \IPS\Db::IGNORE );
|
||||
\IPS\Db::i()->update( 'forums_rss_import', array( 'rss_import_mid' => $member->member_id ), array( 'rss_import_mid=?', $member2->member_id ) );
|
||||
|
||||
if ( \IPS\Settings::i()->archive_on )
|
||||
{
|
||||
$archiveStorage = !\IPS\Settings::i()->archive_remote_sql_host ? \IPS\Db::i() : \IPS\Db::i( 'archive', array(
|
||||
'sql_host' => \IPS\Settings::i()->archive_remote_sql_host,
|
||||
'sql_user' => \IPS\Settings::i()->archive_remote_sql_user,
|
||||
'sql_pass' => \IPS\Settings::i()->archive_remote_sql_pass,
|
||||
'sql_database' => \IPS\Settings::i()->archive_remote_sql_database,
|
||||
'sql_port' => \IPS\Settings::i()->archive_sql_port,
|
||||
'sql_socket' => \IPS\Settings::i()->archive_sql_socket,
|
||||
'sql_tbl_prefix'=> \IPS\Settings::i()->archive_sql_tbl_prefix,
|
||||
'sql_utf8mb4' => isset( \IPS\Settings::i()->sql_utf8mb4 ) ? \IPS\Settings::i()->sql_utf8mb4 : FALSE
|
||||
) );
|
||||
/* Connect to the remote DB if needed */
|
||||
if ( \IPS\CIC2 )
|
||||
{
|
||||
$archiveStorage = \IPS\Cicloud\getForumArchiveDb();
|
||||
}
|
||||
else
|
||||
{
|
||||
$archiveStorage = ( !\IPS\Settings::i()->archive_remote_sql_host ) ? \IPS\Db::i() : \IPS\Db::i( 'archive', array(
|
||||
'sql_host' => \IPS\Settings::i()->archive_remote_sql_host,
|
||||
'sql_user' => \IPS\Settings::i()->archive_remote_sql_user,
|
||||
'sql_pass' => \IPS\Settings::i()->archive_remote_sql_pass,
|
||||
'sql_database' => \IPS\Settings::i()->archive_remote_sql_database,
|
||||
'sql_port' => \IPS\Settings::i()->archive_sql_port,
|
||||
'sql_socket' => \IPS\Settings::i()->archive_sql_socket,
|
||||
'sql_tbl_prefix'=> \IPS\Settings::i()->archive_sql_tbl_prefix,
|
||||
'sql_utf8mb4' => isset( \IPS\Settings::i()->sql_utf8mb4 ) ? \IPS\Settings::i()->sql_utf8mb4 : FALSE
|
||||
) );
|
||||
}
|
||||
$archiveStorage->update( 'forums_archive_posts', array( 'archive_author_id' => $member->member_id ), array( 'archive_author_id=?', $member2->member_id ) );
|
||||
}
|
||||
}
|
||||
@@ -61,9 +68,8 @@ class _Forums
|
||||
*/
|
||||
public function onDelete( $member )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'forums_answer_ratings', array( 'member=?', $member->member_id ) );
|
||||
\IPS\Db::i()->delete( 'forums_question_ratings', array( 'member=?', $member->member_id ) );
|
||||
\IPS\Db::i()->delete( 'forums_answer_ratings', array( '`member`=?', $member->member_id ) );
|
||||
\IPS\Db::i()->delete( 'forums_question_ratings', array( '`member`=?', $member->member_id ) );
|
||||
\IPS\Db::i()->delete( 'forums_view_method', array( 'member_id=?', $member->member_id ) );
|
||||
\IPS\Db::i()->update( 'forums_rss_import', array( 'rss_import_mid' => 0 ), array( 'rss_import_mid=?', $member->member_id ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Mobile Navigation Extension: Forums
|
||||
* @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 12 Jun 2019
|
||||
*/
|
||||
|
||||
namespace IPS\forums\extensions\core\MobileNavigation;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mobile Navigation Extension: Topics
|
||||
*/
|
||||
class _Forums extends \IPS\core\MobileNavigation\MobileNavigationAbstract
|
||||
{
|
||||
/**
|
||||
* Get Type Title which will display in the AdminCP Menu Manager
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function typeTitle()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('mobilenavigation_Forums');
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the currently logged in user access the content this item links to?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAccessContent()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'forums', 'forums', 'front' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function title()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('mobilenavigation_Forums');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Link
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function link()
|
||||
{
|
||||
return \IPS\Http\Url::internal( "app=forums&module=forums&controller=index&method=table", 'front', 'forums' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return icon
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function icon()
|
||||
{
|
||||
return 'LIST_ROWS';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Mobile Navigation Extension: Topics
|
||||
* @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 12 Jun 2019
|
||||
*/
|
||||
|
||||
namespace IPS\forums\extensions\core\MobileNavigation;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mobile Navigation Extension: Topics
|
||||
*/
|
||||
class _Topics extends \IPS\core\MobileNavigation\MobileNavigationAbstract
|
||||
{
|
||||
/**
|
||||
* Get Type Title which will display in the AdminCP Menu Manager
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function typeTitle()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('mobilenavigation_Topics');
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the currently logged in user access the content this item links to?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAccessContent()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'forums', 'forums', 'front' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function title()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('mobilenavigation_Topics');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Link
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function link()
|
||||
{
|
||||
return \IPS\Http\Url::internal( "app=forums&module=forums&controller=index&method=fluid", 'front', 'forums' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return icon
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function icon()
|
||||
{
|
||||
return 'COMMENTS';
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\Permissions;
|
||||
|
||||
/* 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\extensions\core\Queue;
|
||||
|
||||
/* 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;
|
||||
@@ -46,16 +46,16 @@ class _DeleteLegacyPosts
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
{
|
||||
$select = \IPS\Db::i()->select( '*', 'forums_posts', 'queued > 2', 'pid ASC', array( 0, 5 ) );
|
||||
if ( !count( $select ) )
|
||||
$select = \IPS\Db::i()->select( '*', 'forums_posts', 'queued > 2', 'pid ASC', array( 0, \IPS\REBUILD_NORMAL ) );
|
||||
if ( !\count( $select ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
|
||||
$done = 0;
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( $select, 'IPS\forums\Topic\Post' ) as $post )
|
||||
{
|
||||
$post->delete();
|
||||
$post->logDelete( FALSE );
|
||||
$done++;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\Queue;
|
||||
|
||||
/* 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;
|
||||
@@ -46,16 +46,16 @@ class _DeleteLegacyTopics
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
{
|
||||
$select = \IPS\Db::i()->select( '*', 'forums_topics', 'approved > 1', 'tid ASC', array( 0, 5 ) );
|
||||
if ( !count( $select ) )
|
||||
$select = \IPS\Db::i()->select( '*', 'forums_topics', 'approved > 1', 'tid ASC', array( 0, \IPS\REBUILD_NORMAL ) );
|
||||
if ( !\count( $select ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
|
||||
$done = 0;
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( $select, 'IPS\forums\Topic' ) as $topic )
|
||||
{
|
||||
$topic->delete();
|
||||
$topic->logDelete( FALSE );
|
||||
$done++;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\Queue;
|
||||
|
||||
/* 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;
|
||||
@@ -46,8 +46,8 @@ class _HiddenFirstPost
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
{
|
||||
$select = \IPS\Db::i()->select( '*', 'forums_posts', 'new_topic = 1 and queued = -1', 'topic_id ASC', array( 0, 50 ) );
|
||||
if ( !count( $select ) )
|
||||
$select = \IPS\Db::i()->select( '*', 'forums_posts', 'new_topic = 1 and queued = -1', 'topic_id ASC', array( 0, \IPS\REBUILD_SLOW ) );
|
||||
if ( !\count( $select ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\Queue;
|
||||
|
||||
/* 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;
|
||||
@@ -34,6 +34,7 @@ class _RebuildNewTopicFlag
|
||||
try
|
||||
{
|
||||
$data['count'] = \IPS\Db::i()->select( 'MAX(tid)', 'forums_topics' )->first();
|
||||
$data['realCount'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics' )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
@@ -44,6 +45,8 @@ class _RebuildNewTopicFlag
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$data['completed'] = 0;
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -56,7 +59,7 @@ class _RebuildNewTopicFlag
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( $data, $offset )
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
if ( !class_exists( 'IPS\forums\Topic' ) OR !\IPS\Application::appisEnabled( 'forums' ) )
|
||||
{
|
||||
@@ -70,7 +73,7 @@ class _RebuildNewTopicFlag
|
||||
$firstPostIds = array();
|
||||
$firstPostArchivedIds = array();
|
||||
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', array( "tid>?", $offset ), "tid ASC", array( 0, 50 ) ), 'IPS\forums\Topic' ) AS $topic )
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', array( "tid>?", $offset ), "tid ASC", array( 0, \IPS\REBUILD_SLOW ) ), 'IPS\forums\Topic' ) AS $topic )
|
||||
{
|
||||
if ( $topic->isArchived() == FALSE )
|
||||
{
|
||||
@@ -103,26 +106,27 @@ class _RebuildNewTopicFlag
|
||||
catch( \UnderflowException $e ) {}
|
||||
}
|
||||
|
||||
$data['completed']++;
|
||||
$last = $topic->tid;
|
||||
}
|
||||
|
||||
/* Reset flags as needed */
|
||||
if( count( $topicIdsToReset ) )
|
||||
if( \count( $topicIdsToReset ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'forums_posts', array( 'new_topic' => 0 ), array( 'topic_id IN(' . implode( ',', $topicIdsToReset ) . ')' ) );
|
||||
}
|
||||
|
||||
if( count( $firstPostIds ) )
|
||||
if( \count( $firstPostIds ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'forums_posts', array( 'new_topic' => 1 ), array( 'pid IN(' . implode( ',', $firstPostIds ) . ')' ) );
|
||||
}
|
||||
|
||||
if( count( $archivedTopicIdsToReset ) )
|
||||
if( \count( $archivedTopicIdsToReset ) )
|
||||
{
|
||||
\IPS\forums\Topic\ArchivedPost::db()->update( 'forums_archive_posts', array( 'archive_is_first' => 0 ), array( 'archive_topic_id IN(' . implode( ',', $archivedTopicIdsToReset ) . ')' ) );
|
||||
}
|
||||
|
||||
if( count( $firstPostArchivedIds ) )
|
||||
if( \count( $firstPostArchivedIds ) )
|
||||
{
|
||||
\IPS\forums\Topic\ArchivedPost::db()->update( 'forums_archive_posts', array( 'archive_is_first' => 1 ), array( 'archive_id IN(' . implode( ',', $firstPostArchivedIds ) . ')' ) );
|
||||
}
|
||||
@@ -145,6 +149,6 @@ class _RebuildNewTopicFlag
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('queue_rebuilding_new_topic_flag'), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $offset, 2 ) ) : 100 );
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('queue_rebuilding_new_topic_flag'), 'complete' => $data['realCount'] ? ( round( 100 / $data['realCount'] * $data['completed'], 2 ) ) : 100 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task: Rebuild Solved Index
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 20 February 2020
|
||||
*/
|
||||
|
||||
namespace IPS\forums\extensions\core\Queue;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task: Rebuild Solved Index
|
||||
*/
|
||||
class _RebuildSolvedIndex
|
||||
{
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
try
|
||||
{
|
||||
$data['count'] = \IPS\Db::i()->select( 'MAX(tid)', 'forums_topics', array( 'topic_answered_pid > 0' ) )->first();
|
||||
$data['realCount'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics', array( 'topic_answered_pid > 0' ) )->first();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
if( $data['count'] == 0 )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$data['completed'] = 0;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
if ( !class_exists( 'IPS\forums\Topic' ) OR !\IPS\Application::appisEnabled( 'forums' ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
$last = NULL;
|
||||
|
||||
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', array( "tid>? and topic_answered_pid > 0", $offset ), "tid ASC", array( 0, \IPS\REBUILD_QUICK ) ), 'IPS\forums\Topic' ) AS $topic )
|
||||
{
|
||||
/* I told him we already got one! */
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->select( '*', 'core_solved_index', array( 'comment_class=? and item_id=? and comment_id=?', 'IPS\\forums\\Topic\\Post', $topic->tid, $topic->topic_answered_pid ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
/* No? Best slap it in then */
|
||||
try
|
||||
{
|
||||
$comment = \IPS\forums\Topic\Post::load( $topic->topic_answered_pid );
|
||||
|
||||
\IPS\Db::i()->insert( 'core_solved_index', array(
|
||||
'member_id' => $comment->author()->member_id,
|
||||
'app' => 'forums',
|
||||
'comment_class' => 'IPS\\forums\\Topic\\Post',
|
||||
'comment_id' => $comment->pid,
|
||||
'item_id' => $topic->tid,
|
||||
'solved_date' => $comment->post_date // We don't have the real solve date so this will have to do
|
||||
) );
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
|
||||
$data['completed']++;
|
||||
$last = $topic->tid;
|
||||
}
|
||||
|
||||
if( $last === NULL )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('queue_rebuilding_solved_posts'), 'complete' => $data['realCount'] ? ( round( 100 / $data['realCount'] * $data['completed'], 2 ) ) : 100 );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\extensions\core\Queue;
|
||||
|
||||
/* 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,11 +23,6 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _TopicStarterIds
|
||||
{
|
||||
/**
|
||||
* @brief Number of topics to build per cycle
|
||||
*/
|
||||
public $perCycle = 500;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
@@ -50,6 +45,8 @@ class _TopicStarterIds
|
||||
return null;
|
||||
}
|
||||
|
||||
$data['completed'] = 0;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -63,17 +60,21 @@ class _TopicStarterIds
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
$count = 0;
|
||||
$last = NULL;
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', 'forums_topics', array(), 'tid ASC', array( $offset, $this->perCycle ) ) as $topic )
|
||||
foreach( \IPS\Db::i()->select( 'tid, starter_id', 'forums_topics', array( 'tid>?', $offset ), 'tid ASC', array( 0, \IPS\REBUILD_QUICK ) ) as $topic )
|
||||
{
|
||||
$count++;
|
||||
$last = $topic['tid'];
|
||||
$data['completed']++;
|
||||
|
||||
try
|
||||
{
|
||||
$firstPost = \IPS\Db::i()->select( 'author_id', 'forums_posts', array( 'new_topic=? AND topic_id=?', 1, $topic['tid'] ), 'pid ASC', array( 0, 1 ) )->first();
|
||||
|
||||
\IPS\Db::i()->update( 'forums_topics', array( 'starter_id' => $firstPost ), array( 'tid=?', $topic['tid'] ) );
|
||||
if( $firstPost != $topic['starter_id'] )
|
||||
{
|
||||
\IPS\Db::i()->update( 'forums_topics', array( 'starter_id' => $firstPost ), array( 'tid=?', $topic['tid'] ) );
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
@@ -81,12 +82,12 @@ class _TopicStarterIds
|
||||
}
|
||||
}
|
||||
|
||||
if( !$count )
|
||||
if( $last === NULL )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return ( $offset + $count );
|
||||
return $last;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,6 +100,6 @@ class _TopicStarterIds
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_starter_ids'), 'complete' => round( 100 / $data['count'] * $offset, 2 ) );
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('rebuilding_starter_ids'), 'complete' => round( 100 / $data['count'] * $data['completed'], 2 ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief RSS Import extension: RssImport
|
||||
* @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 09 Oct 2019
|
||||
*/
|
||||
|
||||
namespace IPS\forums\extensions\core\RssImport;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RSS Import extension: RssImport
|
||||
*/
|
||||
class _RssImport
|
||||
{
|
||||
/**
|
||||
* @brief RSSImport Class
|
||||
*/
|
||||
public $classes = array();
|
||||
|
||||
public $fileStorage = 'forums_Forums';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->classes = array( 'IPS\\forums\\Topic' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return available options for a Form\Select
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function availableOptions()
|
||||
{
|
||||
return array( 'IPS\\forums\\Topic' => \IPS\Member::loggedIn()->language()->addToStack('__app_forums') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show in the Admin CP?
|
||||
*
|
||||
* @param Object $class The class to check
|
||||
* @return boolean
|
||||
*/
|
||||
public function showInAdminCp( $class ): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Node selector options
|
||||
*
|
||||
* @param \IPS\core\Rss\Import|null $rss Existing RSS object if editing|NULL if not
|
||||
* @return array
|
||||
*/
|
||||
public function nodeSelectorOptions( $rss )
|
||||
{
|
||||
return array( 'class' => 'IPS\forums\Forum', 'permissionCheck' => function ( $forum )
|
||||
{
|
||||
return $forum->sub_can_post and !$forum->redirect_url;
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \IPS\core\Rss\Import $rss RSS object
|
||||
* @param array $article RSS feed article importing
|
||||
* @param \IPS\Node\Model $container Container object
|
||||
* @param string $content Post content with read more link if set
|
||||
* @return \IPS\Content
|
||||
*/
|
||||
public function create( \IPS\core\Rss\Import $rss, $article, \IPS\Node\Model $container, $content )
|
||||
{
|
||||
$settings = $rss->settings;
|
||||
$class = $rss->_class;
|
||||
$member = \IPS\Member::load( $rss->member );
|
||||
$topic = $class::createItem( $member, NULL, $article['date'], $container, $settings['topic_hide'] );
|
||||
$topic->title = $rss->topic_pre . $article['title'];
|
||||
|
||||
if ( ! $settings['topic_open'] )
|
||||
{
|
||||
$topic->state = 'closed';
|
||||
}
|
||||
|
||||
$topic->save();
|
||||
|
||||
/* Send notifications */
|
||||
if ( !$settings['topic_hide'] )
|
||||
{
|
||||
$topic->sendNotifications();
|
||||
}
|
||||
|
||||
/* Add to search index */
|
||||
\IPS\Content\Search\Index::i()->index( $topic );
|
||||
|
||||
$post = \IPS\forums\Topic\Post::create( $topic, $content, TRUE, NULL, \IPS\forums\Topic\Post::incrementPostCount( $container ), $member, $article['date'] );
|
||||
$topic->topic_firstpost = $post->pid;
|
||||
|
||||
$topic->save();
|
||||
|
||||
/* Claim any attachments */
|
||||
if ( isset( $article['attachment'] ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_attachments_map', array(
|
||||
'attachment_id' => $article['attachment']['attach_id'],
|
||||
'location_key' => 'forums_Forums',
|
||||
'id1' => $topic->tid,
|
||||
'id2' => $post->pid,
|
||||
) );
|
||||
}
|
||||
return $topic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition Form elements
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @param \IPS\core\Rss\Import|null $rss Existing RSS object if editing|NULL if not
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form, $rss=NULL )
|
||||
{
|
||||
$settings = NULL;
|
||||
|
||||
if ( $rss )
|
||||
{
|
||||
$settings = $rss->settings;
|
||||
}
|
||||
|
||||
/* Make rss_import_node_id make sense for forums */
|
||||
\IPS\Member::loggedIn()->language()->words['rss_import_node_id'] = \IPS\Member::loggedIn()->language()->addToStack('topic_container');
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_topic_open', ( $settings ? $settings['topic_open'] : 1 ), FALSE, array( 'options' => array( 1 => 'unlocked', 0 => 'locked' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'rss_import_topic_hide', ( $settings ? $settings['topic_hide'] : 0 ), FALSE, array( 'options' => array( 0 => 'unhidden', 1 => 'hidden' ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process additional fields unique to this extension
|
||||
*
|
||||
* @param array $values Values from form
|
||||
* @param \IPS\core\Rss\Import $rss Existing RSS object
|
||||
* @return array
|
||||
*/
|
||||
public function saveForm( &$values, $rss )
|
||||
{
|
||||
$return = array(
|
||||
'topic_open' => $values['rss_import_topic_open'],
|
||||
'topic_hide' => $values['rss_import_topic_hide']
|
||||
);
|
||||
|
||||
unset( $values['rss_import_topic_open'], $values['rss_import_topic_hide'] );
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100002;
|
||||
|
||||
/* 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\setup\upg_100003;
|
||||
|
||||
/* 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;
|
||||
@@ -37,7 +37,7 @@ class _Upgrade
|
||||
'query' => "ALTER TABLE " . \IPS\Db::i()->prefix . "forums_topics ADD INDEX popular_topics (popular_time, approved, forum_id, start_date)"
|
||||
) ) );
|
||||
|
||||
if ( count( $toRun ) )
|
||||
if ( \count( $toRun ) )
|
||||
{
|
||||
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 2 ) ) );
|
||||
|
||||
@@ -56,6 +56,6 @@ class _Upgrade
|
||||
*/
|
||||
public function step1CustomTitle()
|
||||
{
|
||||
return "Optimizing the topics table...";
|
||||
return "Optimizing topics";
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100011;
|
||||
|
||||
/* 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;
|
||||
@@ -33,7 +33,7 @@ class _Upgrade
|
||||
{
|
||||
$perCycle = 50;
|
||||
$did = 0;
|
||||
$limit = intval( \IPS\Request::i()->extra );
|
||||
$limit = \intval( \IPS\Request::i()->extra );
|
||||
|
||||
/* Try to prevent timeouts to the extent possible */
|
||||
$cutOff = \IPS\core\Setup\Upgrade::determineCutoff();
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100015;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100018;
|
||||
|
||||
/* 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\setup\upg_100020;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100028;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100032;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100033;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
@@ -12,7 +12,7 @@
|
||||
namespace IPS\forums\setup\upg_100035;
|
||||
|
||||
/* 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;
|
||||
|
||||
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Loaded 100 of 3791 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user