Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+110 -2
View File
@@ -3,7 +3,7 @@
* @brief Forums Application Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2014 Invision Power Services, Inc.
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 07 Jan 2014
* @version
@@ -70,7 +70,7 @@ class _Application extends \IPS\Application
}
else
{
$clause = array( 'poll_state=0' );
$clause = array( 'poll_state=0 or poll_state IS NULL' );
}
break;
@@ -127,4 +127,112 @@ class _Application extends \IPS\Application
\IPS\Content\Search\Index::i()->index( \IPS\forums\Topic::load( 1 ) );
\IPS\Content\Search\Index::i()->index( \IPS\forums\Topic\Post::load( 1 ) );
}
/**
* Default front navigation
*
* @code
// Each item...
array(
'key' => 'Example', // The extension key
'app' => 'core', // [Optional] The extension application. If ommitted, uses this application
'config' => array(...), // [Optional] The configuration for the menu item
'title' => 'SomeLangKey', // [Optional] If provided, the value of this language key will be copied to menu_item_X
'children' => array(...), // [Optional] Array of child menu items for this item. Each has the same format.
)
return array(
'rootTabs' => array(), // These go in the top row
'browseTabs' => array(), // These go under the Browse tab on a new install or when restoring the default configuraiton; or in the top row if installing the app later (when the Browse tab may not exist)
'browseTabsEnd' => array(), // These go under the Browse tab after all other items on a new install or when restoring the default configuraiton; or in the top row if installing the app later (when the Browse tab may not exist)
'activityTabs' => array(), // These go under the Activity tab on a new install or when restoring the default configuraiton; or in the top row if installing the app later (when the Activity tab may not exist)
)
* @endcode
* @return array
*/
public function defaultFrontNavigation()
{
return array(
'rootTabs' => array(),
'browseTabs' => array( array( 'key' => 'Forums' ) ),
'browseTabsEnd' => array(),
'activityTabs' => array()
);
}
/**
* Perform some legacy URL parameter conversions
*
* @return void
*/
public function convertLegacyParameters()
{
/* Convert &showtopic= @link https://community.invisionpower.com/4bugtrack/active-reports/double-redirects-in-legacyredirect-method-may-cause-seo-issues-r8934/ */
if ( isset( \IPS\Request::i()->showtopic ) and is_numeric( \IPS\Request::i()->showtopic ) )
{
$base = NULL;
$seoTemplate = NULL;
$seoTitles = array();
try
{
$topic = \IPS\forums\Topic::load( \IPS\Request::i()->showtopic );
if ( $topic->canView() )
{
$base = 'front';
$seoTemplate = 'forums_topic';
$seoTitles = array( $topic->title_seo );
}
} catch( \Exception $e ) {}
$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 ) )
{
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->p ?: \IPS\Request::i()->findpost ) );
}
elseif ( isset( \IPS\Request::i()->page ) )
{
$url = $url->setQueryString( array( '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 ) )
{
$base = NULL;
$seoTemplate = NULL;
$seoTitles = array();
try
{
$forum = \IPS\forums\Forum::load( \IPS\Request::i()->showforum );
if ( $forum->can( 'view' ) )
{
$base = 'front';
$seoTemplate = 'forums_forum';
$seoTitles = array( $forum->name_seo );
}
} catch ( \Exception $e ) {}
$url = \IPS\Http\Url::internal( 'app=forums&module=forums&controller=forums&id=' . \IPS\Request::i()->showforum, $base, $seoTemplate, $seoTitles );
\IPS\Output::i()->redirect( $url );
}
/* 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' )
{
/* We do this a little differently as the topic seo title is already known at this point */
try
{
$post = \IPS\forums\Topic\Post::loadAndCheckPerms( \IPS\Request::i()->p );
\IPS\Output::i()->redirect( $post->url() );
}
catch( \Exception $e ) {}
}
}
}
+239
View File
@@ -0,0 +1,239 @@
<?php
/**
* @brief Posts API
* @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
* @subpackage Forums
* @since 7 Dec 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\api;
/* 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 Posts API
*/
class _posts extends \IPS\Content\Api\CommentController
{
/**
* Class
*/
protected $class = 'IPS\forums\Topic\Post';
/**
* GET /forums/posts
* Get list of posts
*
* @apiparam string forums Comma-delimited list of forum IDs
* @apiparam string authors Comma-delimited list of member IDs - if provided, only posts by those members are returned
* @apiparam int hasBestAnswer If 1, only posts from topics with a best answer are returned, if 0 only without
* @apiparam int hasPoll If 1, only posts from topics with a poll are returned, if 0 only without
* @apiparam int locked If 1, only posts from topics which are locked are returned, if 0 only unlocked
* @apiparam int hidden If 1, only posts which are hidden are returned, if 0 only not hidden
* @apiparam int pinned If 1, only posts from topics which are pinned are returned, if 0 only not pinned
* @apiparam int featured If 1, only posts from topics which are featured are returned, if 0 only not featured
* @apiparam int archived If 1, only posts from 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 sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @return \IPS\Api\PaginatedResponse<IPS\forums\Topic\Post>
*/
public function GETindex()
{
/* Init */
$where = array();
/* Has best answer */
if ( isset( \IPS\Request::i()->hasBestAnswer ) )
{
if ( \IPS\Request::i()->hasBestAnswer )
{
$where[] = array( "topic_answered_pid>0" );
}
else
{
$where[] = array( "topic_answered_pid=0" );
}
}
/* Archived */
if ( isset( \IPS\Request::i()->archived ) )
{
if ( \IPS\Request::i()->archived )
{
$where[] = array( \IPS\Db::i()->in( 'topic_archive_status', array( \IPS\forums\Topic::ARCHIVE_DONE, \IPS\forums\Topic::ARCHIVE_WORKING, \IPS\forums\Topic::ARCHIVE_RESTORE ) ) );
}
else
{
$where[] = array( \IPS\Db::i()->in( 'topic_archive_status', array( \IPS\forums\Topic::ARCHIVE_NOT, \IPS\forums\Topic::ARCHIVE_EXCLUDE ) ) );
}
}
/* Return */
return $this->_list( $where, 'forums' );
}
/**
* GET /forums/posts/{id}
* View information about a specific post
*
* @param int $id ID Number
* @throws 1F295/4 INVALID_ID The post ID does not exist
* @return \IPS\forums\Topic\Post
*/
public function GETitem( $id )
{
try
{
return new \IPS\Api\Response( 200, \IPS\forums\Topic\Post::load( $id )->apiOutput() );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '1F295/4', 404 );
}
}
/**
* POST /forums/posts
* Create a post
*
* @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)
* @apiparam string author_name If author is 0, the guest name that should be used
* @reqapiparam string post The post content as HTML (e.g. "<p>This is a post.</p>")
* @apiparam datetime date The date/time that should be used for the topic/post post date. If not provided, will use the current date/time
* @apiparam string ip_address The IP address that should be stored for the topic/post. If not provided, will use the IP address from the API request
* @apiparam int hidden 0 = unhidden; 1 = hidden, pending moderator approval; -1 = hidden (as if hidden by a moderator)
* @throws 1F295/1 NO_TOPIC The forum ID does not exist
* @throws 1F295/2 NO_AUTHOR The author ID does not exist
* @throws 1F295/3 NO_POST No post was supplied
* @return \IPS\forums\Topic\Post
*/
public function POSTindex()
{
/* Get topic */
try
{
$topic = \IPS\forums\Topic::load( \IPS\Request::i()->topic );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_TOPIC', '1F295/1', 403 );
}
/* Get author */
if ( \IPS\Request::i()->author )
{
$author = \IPS\Member::load( \IPS\Request::i()->author );
if ( !$author->member_id )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1F295/2', 403 );
}
}
else
{
$author = new \IPS\Member;
$author->name = \IPS\Request::i()->author_name;
}
/* Check we have a post */
if ( !\IPS\Request::i()->post )
{
throw new \IPS\Api\Exception( 'NO_POST', '1F295/3', 403 );
}
/* Do it */
return $this->_create( $topic, $author, 'post' );
}
/**
* POST /forums/posts/{id}
* Edit a post
*
* @param int $id ID Number
* @apiparam int author The ID number of the member making the post (0 for guest)
* @apiparam string author_name If author is 0, the guest name that should be used
* @apiparam string post The post content as HTML (e.g. "<p>This is a post.</p>")
* @apiparam int hidden 1/0 indicating if the topic should be hidden
* @throws 2F295/6 INVALID_ID The post ID does not exist
* @throws 2F295/7 NO_AUTHOR The author ID does not exist
* @throws 2F295/7 NO_AUTHOR The author ID does not exist
* @throws 1F295/8 CANNOT_HIDE_FIRST_POST You cannot hide or unhide the first post in a topic. Hide/unhide the topic itself instead.
* @throws 1F295/9 CANNOT_AUTHOR_FIRST_POST You cannot change the author for the first post in a topic. Change the author on the topic itself instead.
* @return \IPS\forums\Topic\Post
*/
public function POSTitem( $id )
{
try
{
/* Load */
$post = \IPS\forums\Topic\Post::load( $id );
/* Check */
if ( $post->isFirst() )
{
if ( isset( \IPS\Request::i()->hidden ) )
{
throw new \IPS\Api\Exception( 'CANNOT_HIDE_FIRST_POST', '1F295/8', 403 );
}
if ( isset( \IPS\Request::i()->author ) )
{
throw new \IPS\Api\Exception( 'CANNOT_AUTHOR_FIRST_POST', '1F295/9', 403 );
}
}
/* Do it */
try
{
return $this->_edit( $post, 'post' );
}
catch ( \InvalidArgumentException $e )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '2F295/7', 400 );
}
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2F295/6', 404 );
}
}
/**
* DELETE /forums/posts/{id}
* Deletes a post
*
* @param int $id ID Number
* @throws 1F295/5 INVALID_ID The post ID does not exist
* @throws 1F295/B CANNOT_DELETE_FIRST_POST You cannot delete the first post in a topic. Delete the topic itself instead.
* @return void
*/
public function DELETEitem( $id )
{
try
{
$post = \IPS\forums\Topic\Post::load( $id );
if ( $post->isFirst() )
{
throw new \IPS\Api\Exception( 'CANNOT_DELETE_FIRST_POST', '1F295/B', 403 );
}
$post->delete();
return new \IPS\Api\Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '1F295/5', 404 );
}
}
}
+308
View File
@@ -0,0 +1,308 @@
<?php
/**
* @brief Topics API
* @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
* @subpackage Forums
* @since 4 Dec 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\api;
/* 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 Topics API
*/
class _topics extends \IPS\Content\Api\ItemController
{
/**
* Class
*/
protected $class = 'IPS\forums\Topic';
/**
* GET /forums/topics
* Get list of topics
*
* @apiparam string forums Comma-delimited list of forum IDs
* @apiparam string authors Comma-delimited list of member IDs - if provided, only topics started by those members are returned
* @apiparam int hasBestAnswer If 1, only topics with a best answer are returned, if 0 only without
* @apiparam int hasPoll If 1, only topics with a poll are returned, if 0 only without
* @apiparam int locked If 1, only topics which are locked are returned, if 0 only unlocked
* @apiparam int hidden If 1, only topics which are hidden are returned, if 0 only not hidden
* @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 sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @return \IPS\Api\PaginatedResponse<IPS\forums\Topic>
*/
public function GETindex()
{
/* Init */
$where = array();
/* Has best answer */
if ( isset( \IPS\Request::i()->hasBestAnswer ) )
{
if ( \IPS\Request::i()->hasBestAnswer )
{
$where[] = array( "topic_answered_pid>0" );
}
else
{
$where[] = array( "topic_answered_pid=0" );
}
}
/* Archived */
if ( isset( \IPS\Request::i()->archived ) )
{
if ( \IPS\Request::i()->archived )
{
$where[] = array( \IPS\Db::i()->in( 'topic_archive_status', array( \IPS\forums\Topic::ARCHIVE_DONE, \IPS\forums\Topic::ARCHIVE_WORKING, \IPS\forums\Topic::ARCHIVE_RESTORE ) ) );
}
else
{
$where[] = array( \IPS\Db::i()->in( 'topic_archive_status', array( \IPS\forums\Topic::ARCHIVE_NOT, \IPS\forums\Topic::ARCHIVE_EXCLUDE ) ) );
}
}
/* Return */
return $this->_list( $where, 'forums' );
}
/**
* GET /forums/topics/{id}
* Get posts in a topic
*
* @param int $id ID Number
* @apiparam int hidden If 1, only posts which are hidden are returned, if 0 only not hidden
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @throws 1F294/1 INVALID_ID The topic ID does not exist
* @return \IPS\Api\PaginatedResponse<IPS\forums\Topic\Post>
*/
public function GETitem( $id )
{
try
{
return $this->_comments( $id, 'IPS\forums\Topic\Post' );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '1F294/1', 404 );
}
}
/**
* Create or update topic
*
* @param \IPS\Content\Item $item The item
* @return \IPS\Content\Item
*/
protected function _createOrUpdate( \IPS\Content\Item $item )
{
/* Open/Close time */
if ( \IPS\Request::i()->open_time )
{
$item->topic_open_time = ( new \DateTime( \IPS\Request::i()->open_time ) )->getTimestamp();
}
if ( \IPS\Request::i()->close_time )
{
$item->topic_close_time = ( new \DateTime( \IPS\Request::i()->close_time ) )->getTimestamp();
}
/* Pass up */
return parent::_createOrUpdate( $item );
}
/**
* POST /forums/topics
* Create a topic
*
* @reqapiparam int forum The ID number of the forum the topic should be created in
* @reqapiparam int author The ID number of the member creating the topic (0 for guest)
* @apiparam string author_name If author is 0, the guest name that should be used
* @reqapiparam string title The topic title
* @reqapiparam string post The post content as HTML (e.g. "<p>This is a post.</p>")
* @apiparam string prefix Prefix tag
* @apiparam string tags Comma-separated list of tags (do not include prefix)
* @apiparam datetime date The date/time that should be used for the topic/post post date. If not provided, will use the current date/time
* @apiparam string ip_address The IP address that should be stored for the topic/post. If not provided, will use the IP address from the API request
* @apiparam int locked 1/0 indicating if the topic should be locked
* @apiparam datetime open_time When the topic should be unlocked from
* @apiparam datetime close_time When the topic should be locked from
* @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
* @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
* @return \IPS\forums\Topic
*/
public function POSTindex()
{
/* Get forum */
try
{
$forum = \IPS\forums\Forum::load( \IPS\Request::i()->forum );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_FORUM', '1F294/2', 400 );
}
/* Get author */
if ( \IPS\Request::i()->author )
{
$author = \IPS\Member::load( \IPS\Request::i()->author );
if ( !$author->member_id )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1F294/3', 400 );
}
}
else
{
$author = new \IPS\Member;
$author->name = \IPS\Request::i()->author_name;
}
/* Check we have a title and a post */
if ( !\IPS\Request::i()->title )
{
throw new \IPS\Api\Exception( 'NO_TITLE', '1F294/5', 400 );
}
if ( !\IPS\Request::i()->post )
{
throw new \IPS\Api\Exception( 'NO_POST', '1F294/4', 400 );
}
/* Do it */
return new \IPS\Api\Response( 201, $this->_create( $forum, $author )->apiOutput() );
}
/**
* POST /forums/topics/{id}
* Edit a topic
*
* @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)
* @apiparam string author_name If author is 0, the guest name that should be used
* @apiparam string title The topic title
* @apiparam string post The post content as HTML (e.g. "<p>This is a post.</p>")
* @apiparam string prefix Prefix tag
* @apiparam string tags Comma-separated list of tags (do not include prefix)
* @apiparam datetime date The date/time that should be used for the topic/post post date. If not provided, will use the current date/time
* @apiparam string ip_address The IP address that should be stored for the topic/post. If not provided, will use the IP address from the API request
* @apiparam int locked 1/0 indicating if the topic should be locked
* @apiparam datetime open_time When the topic should be unlocked from
* @apiparam datetime close_time When the topic should be locked from
* @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
* @throws 2F294/6 INVALID_ID The topic ID does not exist
* @throws 1F294/7 NO_FORUM The forum ID does not exist
* @throws 1F294/8 NO_AUTHOR The author ID does not exist
* @return \IPS\forums\Topic
*/
public function POSTitem( $id )
{
try
{
$topic = \IPS\forums\Topic::load( $id );
/* New forum */
if ( isset( \IPS\Request::i()->forum ) and \IPS\Request::i()->forum != $topic->forum_id )
{
try
{
$newForum = \IPS\forums\Forum::load( \IPS\Request::i()->forum );
$topic->move( $newForum );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_FORUM', '1F294/7', 400 );
}
}
/* New author */
if ( isset( \IPS\Request::i()->author ) )
{
/* Just renaming the guest */
if ( !$topic->starter_id and ( !isset( \IPS\Request::i()->author ) or !\IPS\Request::i()->author ) and isset( \IPS\Request::i()->author_name ) )
{
$topic->starter_name = \IPS\Request::i()->author_name;
if ( $firstPost = $this->comments( 1, 0, 'date', 'asc' ) )
{
$firstPost->author_name = \IPS\Request::i()->author_name;
}
}
/* Actually changing the author */
else
{
try
{
$member = \IPS\Member::load( \IPS\Request::i()->author );
if ( !$member->member_id )
{
throw new \OutOfRangeException;
}
$topic->changeAuthor( $member );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1F294/8', 400 );
}
}
}
/* Everything else */
$this->_createOrUpdate( $topic );
/* Save and return */
$topic->save();
return new \IPS\Api\Response( 200, $topic->apiOutput() );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2F294/6', 404 );
}
}
/**
* DELETE /forums/topics/{id}
* Delete a topic
*
* @param int $id ID Number
* @throws 1F294/5 INVALID_ID The topic ID does not exist
* @return void
*/
public function DELETEitem( $id )
{
try
{
\IPS\forums\Topic::load( $id )->delete();
return new \IPS\Api\Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '1F294/5', 404 );
}
}
}
File diff suppressed because it is too large. Load diff
+7 -7
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<emails><template><template_app>forums</template_app><template_name>digests__comment</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='{$comment->author()->photo}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
<img src='{$comment->author()->get_photo( true, true )}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
</td>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
@@ -12,16 +12,16 @@
{{endif}}
</p>
<h2 style="font-family: 'Helvetica Neue', helvetica, sans-serif; font-size: 15px; font-weight: 500 !important; margin: 0;">
<a href='{$comment->item()->url()}' style='text-decoration: none;'>{$comment->item()->mapped('title')}</a>
<a href='{$comment->url()}' style='text-decoration: none;'>{$comment->item()->mapped('title')}</a>
</h2>
<div style='font-family: "Helvetica Neue", helvetica, sans-serif; line-height: 22px; margin-top: 5px; margin-bottom: 5px; border-left: 3px solid #8c8c8c; padding-left: 15px; font-size: 14px; margin-left: 15px'>
{$email->parseTextForEmail( $comment->content() )|raw}
{$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()})
]]></template_content_plaintext></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()->photo}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
<img src='{$topic->author()->get_photo( true, true )}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
</td>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
@@ -36,7 +36,7 @@
{{if $topic->mapped('featured')}}&nbsp;&nbsp;<span style='color: #68a72f; font-weight: bold; font-size: 12px; text-transform: uppercase;'>{$email->language->addToStack("featured", FALSE)}</span>{{endif}}
</h2>
<div style="font-family: 'Helvetica Neue', helvetica, sans-serif; line-height: 22px; margin-top: 10px; margin-bottom: 10px;">
{$email->parseTextForEmail( $topic->content() )|raw}
{$email->parseTextForEmail( $topic->content(), $email->language )|raw}
</div>
<p style="font-family: 'Helvetica Neue', helvetica, sans-serif; margin: 0; font-size: 13px;">
@@ -45,7 +45,7 @@
{{endif}}
{{if $topic->container()->forum_allow_rating}}
{{foreach range( 1, 5 ) as $i}}{{if $i <= $topic->averageRating()}}<img src='{resource="email/rating_on.png" location="interface" app="core"}' width='14' height='13' style='vertical-align: middle; margin-right: 2px'>{{else}}<img src='{resource="email/rating_off.png" location="interface" app="core"}' width='14' height='13' style='vertical-align: middle; margin-right: 2px'>{{endif}}{{endforeach}}
{{foreach range( 1, 5 ) as $i}}{{if $i <= $topic->averageRating()}}<img src='{resource="email/rating_on.png" location="interface" app="core"}' width='14' height='13' style='vertical-align: middle; margin-right: 2px'>{{elseif ( $i - 0.5 ) <= $topic->averageRating()}}<img src='{resource="email/rating_half.png" location="interface" app="core"}' width='14' height='13' style='vertical-align: middle; margin-right: 2px'>{{else}}<img src='{resource="email/rating_off.png" location="interface" app="core"}' width='14' height='13' style='vertical-align: middle; margin-right: 2px'>{{endif}}{{endforeach}}
&nbsp;&nbsp;&nbsp;&nbsp;
{{endif}}
@@ -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_created_topic_in", FALSE, array( 'sprintf' => array( $topic->author()->name, $topic->container()->_title ) ) )}{{else}}{$email->language->addToStack("x_asked_new_question", 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( '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()})
]]></template_content_plaintext></template></emails>
+3 -3
View File
@@ -1,6 +1,6 @@
{
"forums_forum_1": "A Test Category",
"forums_forum_1": "Тестовая категория",
"forums_forum_1_desc": "",
"forums_forum_2": "A Test Forum",
"forums_forum_2_desc": "A test forum that may be removed at any time."
"forums_forum_2": "Тестовый форум",
"forums_forum_2_desc": "Тестовый форум может быть удалён в любое время."
}
+19 -27
View File
@@ -1,7 +1,7 @@
<?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.forumList.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumList.js" javascript_type="controller" javascript_version="101093" javascript_position="1000050"><![CDATA[/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.forum.forumList.js - Controller for a forum listing
@@ -67,8 +67,8 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumPage.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050">/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.forumPage.js" javascript_type="controller" javascript_version="101093" javascript_position="1000050">/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.forum.forumPage.js - Forum page controller
@@ -109,8 +109,8 @@
}
});
}(jQuery, _));</file>
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.hovercard.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050">/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/forum" javascript_name="ips.forum.hovercard.js" javascript_type="controller" javascript_version="101093" javascript_position="1000050">/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.forum.hovercard.js - Topic hovercard in forum view
@@ -159,8 +159,8 @@
}
});
}(jQuery, _));</file>
<file javascript_app="forums" javascript_location="admin" javascript_path="controllers/settings" javascript_name="ips.settings.archiveRules.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="admin" javascript_path="controllers/settings" javascript_name="ips.settings.archiveRules.js" javascript_type="controller" javascript_version="101093" javascript_position="1000050"><![CDATA[/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.forums.archiveRules.js - makes the progress bar increase as archive rules settings are changed
@@ -224,8 +224,8 @@
});
}(jQuery, _));
]]></file>
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.answers.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100"><![CDATA[/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.answers.js" javascript_type="controller" javascript_version="101093" javascript_position="1000100"><![CDATA[/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.topic.answers.js - Profile body controller
@@ -270,17 +270,10 @@
var newVoteCount = 0;
if( positive ){
if( currentVotes === -1 ){
newVoteCount = 1;
} else {
newVoteCount = currentVotes + 1;
}
} else {
if( currentVotes === 1 ){
newVoteCount = -1;
} else {
newVoteCount = currentVotes - 1;
}
newVoteCount = currentVotes + 1;
}
else {
newVoteCount = currentVotes - 1;
}
voteCount
@@ -329,8 +322,8 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.reply.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100">/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.reply.js" javascript_type="controller" javascript_version="101093" javascript_position="1000100">/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.topic.reply.js - Topic reply controller for &quot;Reply&quot; button
@@ -358,8 +351,8 @@
}
});
}(jQuery, _));</file>
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.view.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100">/**
* IPS Social Suite 4
<file javascript_app="forums" javascript_location="front" javascript_path="controllers/topic" javascript_name="ips.topic.view.js" javascript_type="controller" javascript_version="101093" javascript_position="1000100">/**
* IPS Community Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.topic.view.js - Topic view controller
@@ -391,6 +384,7 @@
});
}(jQuery, _));</file>
<order app="global" path="/dev/js//framework/">templates
common/ips.loader.js
common/ui
common/utils
common
@@ -404,6 +398,4 @@ app.js</order>
<order app="global" path="/dev/js//library//jquery">jquery.js
jquery.history.js
jquery.transform.js</order>
<order app="global" path="/dev/js//library//xregexp">xregexp-all.js
xregexp-lookbehind.js</order>
</javascript>
+36 -29
View File
@@ -1,13 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="forums" version="101012">
<app key="forums" version="101093">
<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>
<word key="__indefart_topic" js="0">a topic</word>
<word key="__indefart_answer" js="0">an answer to a question</word>
<word key="__indefart_question" js="0">a question</word>
<word key="__defart_post" js="0">post in a topic</word>
<word key="__defart_topic" js="0">topic</word>
<word key="__defart_answer" js="0">answer to a question</word>
<word key="__defart_question" js="0">question</word>
<word key="topic_container" js="0">Forum</word>
<word key="search_contextual_item_forums" js="0">This Forum</word>
<word key="search_contextual_item_topic" js="0">This Topic</word>
<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>
@@ -158,6 +164,7 @@
<word key="add_forum" js="0">Add Forum</word>
<word key="edit_forum" js="0">Edit Forum</word>
<word key="node_no_parentf" js="0">No Parent</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>
<word key="forums_topic_pl" js="0">Topics</word>
@@ -177,6 +184,8 @@
<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="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="archive_topics_where" js="0"><![CDATA[Archive topics when <em>all</em> of the following conditions are true...]]></word>
@@ -213,9 +222,11 @@
<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_on" js="0">Enable Archiving?</word>
<word key="task__archive" js="0">Archives posts.</word>
<word key="task__unarchive" js="0">Unarchives posts.</word>
<word key="unarchive" js="0">Unarchive</word>
<word key="unarchive_confirm" js="0">Unarchiving this topic will exclude it from being archived again in the future. After confirming, it will take about {# [1:minute][?:minutes]} until the topic is actually unarchived.</word>
<word key="uanrchive_settings_change" js="0">Some topics that are already archived no longer match your archive settings. Would you like to unarchive them?</word>
@@ -313,6 +324,7 @@
<word key="replies" js="0">Replies</word>
<word key="sort_direction" js="0">Sort Direction</word>
<word key="sort_num_replies" js="0">Most Replies</word>
<word key="sort_question_rating" js="0">Most Votes</word>
<word key="asc" js="0">Ascending (oldest first/alphabetically)</word>
<word key="desc" js="0">Descending (newest first)</word>
<word key="time_frame" js="0">Last Reply</word>
@@ -350,7 +362,7 @@
<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>
<word key="sort_by_answers" js="0">Sort by rating</word>
<word key="sort_by_answers" js="0">Sort by votes</word>
<word key="sort_by_date" js="0">Sort by date</word>
<word key="select_forum" js="0">Select Forum</word>
<word key="create_new_topic" js="0">Create New Topic</word>
@@ -362,6 +374,9 @@
<word key="topic_pl" js="0">Topics</word>
<word key="topic_pl_lc" js="0">topics</word>
<word key="post_pl" js="0">Posts</word>
<word key="post_pl_lc" js="0">posts</word>
<word key="archivedpost_pl" js="0">Archived Posts</word>
<word key="archivedpost_pl_lc" js="0">archived posts</word>
<word key="topic__comment_placeholder" js="0">Reply to this topic...</word>
<word key="question__comment_placeholder" js="0">Answer this question...</word>
<word key="moderator_actions" js="0">Moderation Actions</word>
@@ -402,6 +417,8 @@
<word key="topic_moderator_options" js="0">Moderator Options</word>
<word key="submit_question" js="0">Submit Question</word>
<word key="submit_topic" js="0">Submit Topic</word>
<word key="submit_topic_edit" js="0">Edit Topic</word>
<word key="submit_question_edit" js="0">Edit Question</word>
<word key="topic_submit_comment" js="0">Submit Reply</word>
<word key="edit_question" js="0">Edit Question</word>
<word key="edit_topic" js="0">Edit Topic</word>
@@ -424,6 +441,8 @@
<word key="go_to_new_location" js="0">Go to this topic in its new location</word>
<word key="topic_moved_to" js="0"><![CDATA[Topic was moved to forum <a href='%s'><strong>%s</strong></a>]]></word>
<word key="question_moved_to" js="0"><![CDATA[Question was moved to forum <a href='%s'><strong>%s</strong></a>]]></word>
<word key="topic_merged_to" js="0"><![CDATA[Topic was merged with <a href='%s'><strong>%s</strong></a>]]></word>
<word key="question_merged_to" js="0"><![CDATA[Question was merged with <a href='%s'><strong>%s</strong></a>]]></word>
<word key="this_topic" js="0">This Topic</word>
<word key="this_forum" js="0">This Forum</word>
<word key="forum_id" js="0">Forum</word>
@@ -432,8 +451,8 @@
<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="rate_this_topic" js="0">Rate this topic:</word>
<word key="rate_this_question" js="0">Rate this question:</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>
<word key="sign_in_rate_answer" js="0">Sign in to rate this answer</word>
<word key="no_questions_in_forum" js="0">There are no questions in this forum yet</word>
@@ -442,6 +461,7 @@
<word key="submit_first_topic" js="0">Start the first topic</word>
<word key="topic_pending_approval" js="0">This topic is not yet approved and is currently only visible to staff.</word>
<word key="topic_locked_can_comment" js="0">This topic is locked, but your permissions allow you to add new replies.</word>
<word key="topic_poll_can_comment" js="0">This is a poll-only topic, but your permissions allow you to add new replies.</word>
<word key="topic_locked_cannot_comment" js="0">This topic is now closed to further replies.</word>
<word key="ip_prefix" js="0">IP: %s</word>
<word key="popular_questions_title" js="0">Popular questions from the past month</word>
@@ -450,12 +470,18 @@
<word key="new_questions_title_no_best" js="0">Questions with no best answer</word>
<word key="no_new_questions" js="0">There are no new questions to show right now</word>
<word key="topic_delete_title" js="0">Delete this topic</word>
<word key="approve_title_topic" js="0">Approve this topic</word>
<word key="no_perm_topic_password" js="0">This topic cannot be displayed because it is in a password protected forum.</word>
<word key="no_perm_topic_min_posts" js="0">This topic cannot be displayed because it is in a forum which requires at least {# [1:post][?:posts]} to view.</word>
<word key="no_perm_post_password" js="0">This post cannot be displayed because it is in a password protected forum.</word>
<word key="no_perm_post_min_posts" js="0">This post cannot be displayed because it is in a forum which requires at least {# [1:post][?:posts]} to view.</word>
<word key="enter_password" js="0">Enter Password</word>
<word key="topic_unlocks_at" js="0">Topic will be automatically unlocked %s at %s</word>
<word key="topic_unlocks_at_short" js="0">Unlocks %s</word>
<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="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>
<word key="mm_forums" js="0">Forums</word>
<word key="topic_properties" js="0">Properties</word>
@@ -475,32 +501,11 @@
<word key="can_use_saved_actions" js="0">Can use saved actions?</word>
<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="rss_import" js="0">RSS/Atom Feed Imports</word>
<word key="rss_import_url" js="0">URL</word>
<word key="rss_import_invalid" js="0">That is not a valid RSS or Atom feed.</word>
<word key="rss_import_auth_user" js="0">HTTP Authorization Username</word>
<word key="rss_import_auth_user_desc" js="0">Most feeds do not require authorization and can leave this blank.</word>
<word key="rss_import_auth_pass" js="0">HTTP Authorization Password</word>
<word key="rss_import_auth_pass_desc" js="0">Most feeds do not require authorization and can leave this blank.</word>
<word key="rss_import_auth" js="0">The URL required authorization and the provided user details are incorrect.</word>
<word key="rss_import_preview" js="0">Preview</word>
<word key="rss_import_details" js="0">Details</word>
<word key="rss_import_forum_id" js="0">Forum</word>
<word key="rss_import_mid" js="0">Author</word>
<word key="rss_import_mid_desc" js="0">The user who will appear as the author for topics created by the feed.</word>
<word key="rss_import_showlink" js="0">Text to use for link</word>
<word key="rss_import_showlink_desc" js="0">Will appear at the bottom of the post, linking to the original article.</word>
<word key="rss_import_showlink_default" js="0">View the full article</word>
<word key="rss_import_topic_open" js="0">Topic Open/Closed?</word>
<word key="rss_import_topic_hide" js="0">Topic Hidden/Unhidden?</word>
<word key="rss_import_topic_pre" js="0">Topic Prefix</word>
<word key="rss_import_topic_pre_desc" js="0">Will be added in front of the topic title.</word>
<word key="rss_run" js="0">Check for updates</word>
<word key="rss_run_error" js="0">The feed could not be updated. Try again later.</word>
<word key="acplog__rss_ran" js="0">Ran feed import - %s</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="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>
@@ -516,8 +521,8 @@
<word key="block_topicFeed_desc" js="0">Create a feed of topics based on custom sort and order options</word>
<word key="block_postFeed" js="0">Post Feed</word>
<word key="block_postFeed_desc" js="0">Create a feed of posts based on custom sort and order options</word>
<word key="digest_area_topic" js="0">Topics</word>
<word key="digest_area_forum" js="0">Forums</word>
<word key="digest_area_forums_topic" js="0">Topics</word>
<word key="digest_area_forums_forum" js="0">Forums</word>
<word key="x_created_topic_in" js="0">%s created a topic in %s</word>
<word key="x_asked_new_question" js="0">%s asked a new question in %s</word>
<word key="x_replied_to_a_topic" js="0">%s replied to a topic</word>
@@ -541,6 +546,8 @@
<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="__api_forums_posts" js="0">Posts</word>
<word key="__api_forums_topics" js="0">Topics</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>
+556
View File
@@ -0,0 +1,556 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="forums" version="101093">
<word key_rus="Форумы" key="__app_forums" js="0">Forums</word>
<word key_rus="Форумы" key="frontnavigation_forums" js="0">Forums</word>
<word key_rus="сообщение в теме" key="__indefart_post" js="0">a post in a topic</word>
<word key_rus="тема" key="__indefart_topic" js="0">a topic</word>
<word key_rus="ответ на вопрос" key="__indefart_answer" js="0">an answer to a question</word>
<word key_rus="вопрос" key="__indefart_question" js="0">a question</word>
<word key_rus="сообщение в теме" key="__defart_post" js="0">post in a topic</word>
<word key_rus="тема" key="__defart_topic" js="0">topic</word>
<word key_rus="ответ на вопрос" key="__defart_answer" js="0">answer to a question</word>
<word key_rus="вопрос" key="__defart_question" js="0">question</word>
<word key_rus="Форум" key="topic_container" js="0">Forum</word>
<word key_rus="Этот форум" key="search_contextual_item_forums" js="0">This Forum</word>
<word key_rus="Эта тема" key="search_contextual_item_topic" js="0">This Topic</word>
<word key_rus="Форумы" key="module__forums_forums" js="0">Forums</word>
<word key_rus="Статистика" key="module__forums_stats" js="0">Statistics</word>
<word key_rus="Иконки форумов" key="filestorage__forums_Icons" js="0">Forum Icons</word>
<word key_rus="Сообщение" key="post" js="0">Post</word>
<word key_rus="Форумы и темы" key="editor__forums_Forums" js="0">Forums and Topics</word>
<word key_rus="Форумы" key="acp_search_title_forums_Forums" js="0">Forums</word>
<word key_rus="Форумы" key="menu__forums_forums" js="0">Forums</word>
<word key_rus="Форумы" key="menu__forums_forums_forums" js="0">Forums</word>
<word key_rus="Сохраненные Действия" key="menu__forums_forums_savedActions" js="0">Saved Actions</word>
<word key_rus="RSS/Atom ленты" key="menu__forums_forums_rss" js="0">RSS/Atom Feeds</word>
<word key_rus="Форумы" key="menu__forums_stats" js="0">Forums</word>
<word key_rus="Статистика новых тем" key="menu__forums_stats_topics" js="0">New Topic Statistics</word>
<word key_rus="Статистика новых сообщений" key="menu__forums_stats_posts" js="0">New Post Statistics</word>
<word key_rus="Форумы" key="r__forums" js="0">Forums</word>
<word key_rus="Можно просматривать форумы?" key="r__forums_manage" js="0">Can view forums?</word>
<word key_rus="Можно создавать форумы?" key="r__forums_add" js="0">Can create forums?</word>
<word key_rus="Можно редактировать форумы?" key="r__forums_edit" js="0">Can edit forums?</word>
<word key_rus="Можно управлять разрешениями форумов?" key="r__forums_perms" js="0">Can manage forum permissions?</word>
<word key_rus="Можно удалять форумы?" key="r__forums_delete" js="0">Can delete forums?</word>
<word key_rus="Можно управлять настройками архивирования?" key="r__archive_manage" js="0">Can manage archive settings?</word>
<word key_rus="Есть доступ к настройкам?" key="r__settings_access" js="0">Can access settings?</word>
<word key_rus="Можно управлять настройками форумов?" key="r__forum_settings" js="0">Can manage forums settings?</word>
<word key_rus="Ленты" key="r__rss" js="0">Feeds</word>
<word key_rus="Можно управлять лентой импорта?" key="r__rss_manage" js="0">Can view feed imports?</word>
<word key_rus="Можно создавать ленту импорта?" key="r__rss_add" js="0">Can create feed imports?</word>
<word key_rus="Можно редактировать ленту импорта?" key="r__rss_edit" js="0">Can edit feed imports?</word>
<word key_rus="Можно удалять ленту импорта?" key="r__rss_delete" js="0">Can delete feed imports?</word>
<word key_rus="Можно запускать ленту импорта?" key="r__rss_run" js="0">Can run feed imports?</word>
<word key_rus="Сохраненные Действия" key="r__savedActions" js="0">Saved Actions</word>
<word key_rus="Можно просматривать сохранённые действия?" key="r__savedActions_manage" js="0">Can view saved actions?</word>
<word key_rus="Можно создавать сохранённые действия?" key="r__savedActions_add" js="0">Can create saved actions?</word>
<word key_rus="Можно редактировать сохранённые действия?" key="r__savedActions_edit" js="0">Can edit saved actions?</word>
<word key_rus="Можно удалять сохранённые действия?" key="r__savedActions_delete" js="0">Can delete saved actions?</word>
<word key_rus="Статистика новых тем" key="r__topics" js="0">New Topic Statistics</word>
<word key_rus="Можно просматривать статистику новых тем" key="r__topics_manage" js="0">Can view statistics about new topics</word>
<word key_rus="Статистика новых сообщений" key="r__posts" js="0">New Post Statistics</word>
<word key_rus="Можно просматривать статистику новых сообщений" key="r__posts_manage" js="0">Can view statistics about new posts</word>
<word key_rus="Форумы" key="modperms__core_Content_forums_Topic" js="0">Forums</word>
<word key_rus="Можно прикреплять темы/вопросы?" key="can_pin_topic" js="0">Can pin topics/questions?</word>
<word key_rus="Можно откреплять темы/вопросы?" key="can_unpin_topic" js="0">Can unpin topics/questions?</word>
<word key_rus="Можно устанавливать популярными темы/вопросы?" key="can_feature_topic" js="0">Can feature topics/questions?</word>
<word key_rus="Можно устанавливать темы/вопросы непопулярными?" key="can_unfeature_topic" js="0">Can unfeature topics/questions?</word>
<word key_rus="Можно редактировать темы/вопросы?" key="can_edit_topic" js="0">Can edit topics/questions?</word>
<word key_rus="Можно скрывать темы/вопросы?" key="can_hide_topic" js="0">Can hide topics/questions?</word>
<word key_rus="Можно отображать скрытые темы/вопросы?" key="can_unhide_topic" js="0">Can unhide topics/questions?</word>
<word key_rus="Можно просматривать скрытые темы/вопросы?" key="can_view_hidden_topic" js="0">Can view hidden topics/questions?</word>
<word key_rus="Можно перемещать темы/вопросы?" key="can_move_topic" js="0">Can move topics/questions?</word>
<word key_rus="Можно закрывать темы/вопросы?" key="can_lock_topic" js="0">Can lock topics/questions?</word>
<word key_rus="Можно открывать темы/вопросы?" key="can_unlock_topic" js="0">Can unlock topics/questions?</word>
<word key_rus="Можно отвечать в заблокированных темах/вопросах?" key="can_reply_to_locked_topic" js="0">Can reply to locked topics/questions?</word>
<word key_rus="Можно удалять темы/вопросы?" key="can_delete_topic" js="0">Can delete topics/questions?</word>
<word key_rus="Можно разделять и объединять темы/вопросы?" key="can_split_merge_topic" js="0">Can split and merge topics/questions?</word>
<word key_rus="Можно редактировать сообщения/вопросы?" key="can_edit_post" js="0">Can edit posts/answers?</word>
<word key_rus="Можно скрывать сообщения/ответы?" key="can_hide_post" js="0">Can hide posts/answers?</word>
<word key_rus="Можно показывать скрытые сообщения/ответы?" key="can_unhide_post" js="0">Can unhide posts/answers?</word>
<word key_rus="Можно просматривать скрытые сообщения/ответы?" key="can_view_hidden_post" js="0">Can view hidden posts/answers?</word>
<word key_rus="Можно удалять сообщения/ответы?" key="can_delete_post" js="0">Can delete posts/answers?</word>
<word key_rus="Можно просматривать все темы/вопросы?" key="can_read_all_topics" js="0">Can view all topics/questions?</word>
<word key_rus="которые их опубликовали. Когда эта настройка включена. модераторы смогут просматривать темы/вопросы, которых они не публиковали." 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_rus="Можно устанавливать лучший ответ в вопросах?" key="can_set_best_answer" js="0">Can set best answer for questions?</word>
<word key_rus="Форумы" key="forums" js="0">Forums</word>
<word key_rus="Форум" key="forums_sg" js="0">Forum</word>
<word key_rus="Создать подфорум" key="forums_add_child" js="0">Create Subforum</word>
<word key_rus="Создать форум" key="forums_add_child_cat" js="0">Create Forum</word>
<word key_rus="Название" key="forum_name" js="0">Name</word>
<word key_rus="Описание" key="forum_description" js="0">Description</word>
<word key_rus="Добавить описание..." key="forum_description_placeholder" js="0">Add a description...</word>
<word key_rus="Тип" key="forum_type" js="0">Type</word>
<word key_rus="Обсуждения" key="forum_type_normal" js="0">Discussions</word>
<word key_rus="Пользователи могут создавать темы, в которых могут отвечать остальные пользователи. Ответы будут отображаться в порядке их размещения." key="forum_type_normal_desc" js="0">Users can start topics that other users can reply to. Replies are shown in the order they're posted.</word>
<word key_rus="Вопросы" key="forum_type_qa" js="0">Questions</word>
<word key_rus="Пользователи могут задавать вопросы, на которые другие пользователи смогут отвечать. Ответы могут быть оценены другими пользователями, ответы с высоким рейтингом будут отображаться сверху." key="forum_type_qa_desc" js="0">Users can ask questions that other users can post answers to. Answers can then be rated by other users and the highest rated answers are shown first.</word>
<word key_rus="Категория" key="forum_type_category" js="0">Category</word>
<word key_rus="Категория для других форумов. Контент в ней размещаться не будет." key="forum_type_category_desc" js="0">Container for other forums. Nothing can be posted directly within them.</word>
<word key_rus="Перенаправление" key="forum_type_redirect" js="0">Redirect</word>
<word key_rus="Перенаправление пользователей по клику на форум." key="forum_type_redirect_desc" js="0">Redirects users to another location when clicked on.</word>
<word key_rus="Защитить паролем?" key="forum_password_on" js="0">Password protected?</word>
<word key_rus="Если включено, пользователи, у которых есть доступ к форуму, должны будут указать пароль. Пользователи, у которых нет доступа, не смогут ввести пароль. Пароль применяется только к данному форуму, если у этого форума есть подфорумы, вводить пароль для них не потребуется.&lt;br&gt;Темы, опубликованные в форумах, защищённых паролем, не будут отображаться ни в одном боковом блоке, блоках хэдера или футера, и не будут отправляться уведомления о новых темах и сообщениях." key="forum_password_on_desc" js="0"><![CDATA[When enabled, users who have permission to access the forum will need to provide the password. Users who do not have permission to access the forum will not be prompted for the password. The password applies only to this forum, if this forum has subforums, the password will not be required for them.<br>Topics posted in a password protected forum will not show in any sidebar, header or footer blocks, and notifications for new topics and posts will not be sent.]]></word>
<word key_rus="Пароль" key="forum_password" js="0">Password</word>
<word key_rus="Пароль не требуется" key="forum_password_override" js="0">No Password Required</word>
<word key_rus="Настройки отображения" key="forum_display" js="0">Display Settings</word>
<word key_rus="Фильтр по умолчанию" key="forum_topicfilter" js="0">Default filter</word>
<word key_rus="Правила" key="forum_rules" js="0">Rules</word>
<word key_rus="Показывать правила?" key="forum_show_rules" js="0">Show Rules?</word>
<word key_rus="Не показывать" key="forum_show_rules_none" js="0">Do not show</word>
<word key_rus="Показывать ссылку на правила" key="forum_show_rules_link" js="0">Show link to rules</word>
<word key_rus="Правила будут показываться на отдельной странице со ссылкой, добавленной в хедер форума" key="forum_show_rules_link_desc" js="0">The rules will be shown on a separate page with a link added in the forum header</word>
<word key_rus="Показывать правила" key="forum_show_rules_full" js="0">Show rules</word>
<word key_rus="Правила будут показываются в хедере форума" key="forum_show_rules_full_desc" js="0">The rules will be shown inline in the forum header</word>
<word key_rus="Заголовок правил" key="forum_rules_title" js="0">Rules Title</word>
<word key_rus="Правила" key="forum_rules_text" js="0">Rules</word>
<word key_rus="Настройки форума" key="forum_settings" js="0">Forum Settings</word>
<word key_rus="Настройки публикации" key="posting_settings" js="0">Posting Settings</word>
<word key_rus="Разрешить опросы?" key="forum_allow_poll" js="0">Allow Polls?</word>
<word key_rus="Сообщения" key="posts" js="0">Posts</word>
<word key_rus="Сообщения должны быть одобрены?" key="forum_preview_posts" js="0">Posts must be approved?</word>
<word key_rus="Сообщения должны быть одобрены?" key="forum_preview_posts_qa" js="0">Posts must be approved?</word>
<word key_rus="Новые темы" key="forum_preview_posts_topics" js="0">New Topics</word>
<word key_rus="Новые вопросы" key="forum_preview_posts_questions" js="0">New Questions</word>
<word key_rus="Ответов" key="forum_preview_posts_posts" js="0">Replies</word>
<word key_rus="Ответы" key="forum_preview_posts_answers" js="0">Answers</word>
<word key_rus="Включить счётчик количества контента?" key="forum_inc_postcount" js="0">Increase Content Counts?</word>
<word key_rus="Если отключено, общее количество контента пользователя не будет прибавляться, когда пользователь будет делать публикации в данном форуме. Вы можете отключить это в форумах, предназначенных для публикации тестовых сообщений и в других случаях." key="forum_inc_postcount_desc" js="0">If disabled, the user's total number of content items will not increase when a user posts in this forum. You may want to disable this for forums for posting test messages, etc.</word>
<word key_rus="URL перенаправления" key="forum_redirect_url" js="0">Redirect URL</word>
<word key_rus="Количество перенаправлений" key="forum_redirect_hits" js="0">Redirect Count</word>
<word key_rus="Количество кликов по ссылке форума для перенаправления пользователей. Это число автоматически увеличивается, но вы всегда сможете настроить его здесь." key="forum_redirect_hits_desc" js="0">The number of times users have clicked on the forum and been redirected, which is shown in the list of forums. This number automatically increases, but you can manually adjust it here.</word>
<word key_rus="Ошибка отсутствия прав" key="forum_permission_custom_error" js="0">Custom No Permission Error</word>
<word key_rus="Если указано, данное сообщение будет отображаться, если пользователь попытается перейти в данный форум, но не имеет доступа к нему." key="forum_permission_custom_error_desc" js="0">If provided, this message will be displayed if a user who does not have permission to access this forum tries to access it.</word>
<word key_rus="Добавить сообщение об ошибке..." key="forum_permerror_placeholder" js="0">Add an error message...</word>
<word key_rus="Тема форума" key="forum_skin_id" js="0">Theme Override</word>
<word key_rus="При просмотре форума будет использоваться выбранная тема, независимо от предпочтений пользователя." key="forum_skin_id_desc" js="0">When viewing this forum, the selected theme will be used regardless of the user's preference.</word>
<word key_rus="-Не переопределять-" key="forum_skin_id_default" js="0">-Do not override-</word>
<word key_rus="Отображение форума" key="forum_display_forum" js="0">Forum Display</word>
<word key_rus="Отображение темы" key="forum_display_topic" js="0">Topic Display</word>
<word key_rus="Включить рейтинг звёздами" key="forum_display_question" js="0">Question Display</word>
<word key_rus="Включить рейтинг звёздами?" key="forum_forum_allow_rating" js="0">Enable Star Ratings?</word>
<word key_rus="Вы можете контролировать, какие группы могут оценивать в &lt;a href='{internal.app=core&amp;module=members&amp;controller=groups}'&gt;Настройках групп&lt;/a&gt;" key="forum_forum_allow_rating_desc" js="0"><![CDATA[You can control which groups can rate in the <a href='{internal.app=core&module=members&controller=groups}'>Group Settings</a>]]></word>
<word key_rus="Требования к публикцаии" key="posting_requirements" js="0">Posting Requirements</word>
<word key_rus="Минимальное количество контента для просмотра форума" key="forum_min_posts_view" js="0">Minimum content count to see forum</word>
<word key_rus="Минимальное количество контента для возможности публикации" key="forum_min_posts_post" js="0">Minimum content count to post</word>
<word key_rus="Пользователи могут просматривать темы, опубликованные другими пользователями?" key="forum_can_view_others" js="0">Users can see topics posted by other users?</word>
<word key_rus="Модераторы могут (если есть разрешения) просматривать все темы. Вы можете использовать эту настройку для создания форума, где пользователи смогут в частном порядке общаться с модераторами.&lt;br&gt;Темы, опубликованные в форумах, защищённых паролем, не будут отображаться ни в одном боковом блоке, блоках хэдера или футера." 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_rus="Пользователи могут просматривать вопросы других пользователей?" key="forum_can_view_others_qa" js="0">Users can see questions asked by other users?</word>
<word key_rus="Модераторы могут (если есть разрешения) просматривать все вопросы. Вы можете использовать эту настройку для создания частного форума поддержки." 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_rus="Пользователи без доступа просмотра могут открыть форум?" key="forum_permission_showtopic" js="0">Users without read permission can open forum?</word>
<word key_rus="Если у пользователя есть доступ к просмотру форума, но без просмотра тем, эта настройка определяет, действительно ли он может открыть форум и видеть заголовки тем." 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_rus="Пользователи без доступа просмотра могут открыть форум?" key="forum_permission_showtopic_qa" js="0">Users without read permission can open forum?</word>
<word key_rus="Если у пользователя есть доступ к просмотру форума, но без просмотра вопросов, эта настройка определяет, действительно ли он может открыть форум и видеть заголовки вопросов." key="forum_permission_showtopic_qa_desc" js="0">If a user does have permission to see the forum but not to read the questions, this setting controls whether or not they can open the forum and see the question titles.</word>
<word key_rus="Включить возможность поделиться?" key="forum_disable_sharelinks" js="0">Enable Sharing?</word>
<word key_rus="&lt;a href='{internal.app=core&amp;module=promotion&amp;controller=sharelinks}'&gt;Настройки возможности поделиться&lt;/a&gt;" key="forum_disable_sharelinks_desc" js="0"><![CDATA[<a href='{internal.app=core&module=promotion&controller=sharelinks}'>Sharing Settings</a>]]></word>
<word key_rus="Предустановленные теги" key="forum_tag_predefined" js="0">Defined Tags</word>
<word key_rus="По умолчанию" key="forum_tag_predefined_unlimited" js="0">Use default</word>
<word key_rus="Если вы используете закрытую систему тегирования, пользователи должны будут выбрать теги из этого списка. При использовании открытой системы, введённые здесь теги также будут показаны." key="forum_tag_predefined_desc" js="0">If using a closed system, users will have to choose from these tags. If using an open system, tags entered here will show as suggestions.</word>
<word key_rus="Приоритет карты сайта" key="forum_ipseo_priority" js="0">Sitemap Priority</word>
<word key_rus="Значение приоритета в файле карты сайта указывает ботам поисковых систем на важность страницы, по сравнению с другими страницами на сайте. &lt;a href='{internal.app=core&amp;module=promotion&amp;controller=seo&amp;tab=sitemap}'&gt;Настройки карты сайта&lt;/a&gt;" key="forum_ipseo_priority_desc" js="0"><![CDATA[The priority value in a sitemap file indicates to search engines how important a page is compared to other pages on the site. <a href='{internal.app=core&module=promotion&controller=seo&tab=sitemap}'>Sitemap Settings</a>]]></word>
<word key_rus="Включить VigLink?" key="forum_viglink" js="0">Enable VigLink?</word>
<word key_rus="Кто может оценивать вопросы?" key="forum_qa_rate_questions" js="0">Who can rate questions?</word>
<word key_rus="Вопросы, в которых был отмечен лучший ответ за последние 30 дней, будут отображаться в блоке 'Популярные вопросы' на странице форума." key="forum_qa_rate_questions_desc" js="0">Questions that have been rated the best within the last 30 days will show under 'Popular Questions' in the forum home.</word>
<word key_rus="Кто может голосовать за ответы?" key="forum_qa_rate_answers" js="0">Who can rate answers?</word>
<word key_rus="Ответы будут упорядочены с бОльшим рейтингом сверху." key="forum_qa_rate_answers_desc" js="0">Answers are ordered with the best rated answers first.</word>
<word key_rus="Пользователь, задающий вопрос, может выбрать лучший ответ?" key="bw_enable_answers_member" js="0">User who asked question can choose the best answer?</word>
<word key_rus="Лучший ответ всегда отображается выше всех остальных ответов." key="bw_enable_answers_member_desc" js="0">The best answer is always displayed above all other answers.</word>
<word key_rus="Иконка" key="forum_icon" js="0">Icon</word>
<word key_rus="Иконка отображается рядом с форумом в списке всех форумов. Она будет автоматически затухать, если в ней не будет непрочитанных тем. Если иконка не предоставлена, будет использована стандартная иконка" key="forum_icon_desc" js="0"><![CDATA[The icon displays next to the forum in the forum list. It will automatically be faded out to indicate if there are no unread topics within the forum.<br>If none is provided, the default icon will be used.]]></word>
<word key_rus="Родительский форум" key="forum_parent_id" js="0">Parent Forum</word>
<word key_rus="Только категории не могут иметь родительского раздела." key="forum_parent_id_error" js="0">Only categories can have no parent.</word>
<word key_rus="Сообщений на странице" key="forums_posts_per_page" js="0">Posts per page</word>
<word key_rus="Добавить форум" key="add_forum" js="0">Add Forum</word>
<word key_rus="Изменить форум" key="edit_forum" js="0">Edit Forum</word>
<word key_rus="Без родителя" key="node_no_parentf" js="0">No Parent</word>
<word key_rus="Перестроение номеров ID авторов тем" key="rebuilding_starter_ids" js="0">Rebuilding topic starter IDs</word>
<word key_rus="Сообщения форума" key="forums_topic_post" js="0">Forum Posts</word>
<word key_rus="Темы форума" key="forums_topic" js="0">Forum Topics</word>
<word key_rus="Темы" key="forums_topic_pl" js="0">Topics</word>
<word key_rus="Настройки" key="menu__forums_forums_settings" js="0">Settings</word>
<word key_rus="Популярно сейчас" key="forums_popular_now" js="0">Popular Now</word>
<word key_rus="Темы, которые сейчас популярны, выделяются в списке тем." key="forums_popular_now_desc" js="0">Topics which are Popular Now are highlighted in the list.</word>
<word key_rus="сообщений за последние" key="posts_in_the_last" js="0">posts in the last</word>
<word key_rus="Обновлены настройки форумов" key="acplogs__forums_settings" js="0">Updated forums settings</word>
<word key_rus="Темы" key="topics" js="0">Topics</word>
<word key_rus="Вопросы" key="questions" js="0">Questions</word>
<word key_rus="Настройки темы" key="topic_settings" js="0">Topic Settings</word>
<word key_rus="Настройки вопросов" key="question_settings" js="0">Question Settings</word>
<word key_rus="Вопросы могут оцениваться отрицательно?" key="forums_questions_downvote" js="0">Questions can be negatively rated?</word>
<word key_rus="Ответы могут оцениваться отрицательно?" key="forums_answers_downvote" js="0">Answers can be negatively rated?</word>
<word key_rus="Новые вопросы" key="forums_new_questions" js="0">New Questions</word>
<word key_rus="Новые вопросы выделены в верхней части страницы при просмотре форума." key="forums_new_questions_desc" js="0">New questions are highlighted at the top of the page when viewing a forum.</word>
<word key_rus="Вопросы, где не был выбран лучший ответ." key="forums_new_questions_best" js="0">Questions where a best answer has not been chosen.</word>
<word key_rus="Вопросы, на которые нет ответов вообще." key="forums_new_questions_any" js="0">Questions which have not received any answers.</word>
<word key_rus="Включить RSS ленты?" key="forums_rss" js="0">Enable RSS feeds?</word>
<word key_rus="Будет отображён контент, доступный для гостей. Для получения дополнительных возможностей, создайте &lt;a href='{internal.app=core&amp;module=discovery&amp;controller=rss}'&gt;Пользовательскую RSS ленту&lt;/a&gt;" 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_rus="Тем на странице" key="forums_topics_per_page" js="0">Topics per page</word>
<word key_rus="Архивирование" key="archiving" js="0">Archiving</word>
<word key_rus="Если у вас очень большой сайт, архивирование может быть выгодна для уменьшения размера таблицы, содержащей сообщения форума. Архивирование является альтернативой удаления, но позволяет им по-прежнему существовать, но в рамках отдельной таблицы базы данных. Архивированные темы не могут быть опубликованы или изменены, и не будут отображаться в результатах поиска. Вы можете разархивировать темы после их архивирования, если захотите." 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_rus="Архивировать темы, когда &lt;em&gt;все&lt;/em&gt; из следующих условий выполняются..." key="archive_topics_where" js="0"><![CDATA[Archive topics when <em>all</em> of the following conditions are true...]]></word>
<word key_rus="В форумах" key="archive_topic_forums" js="0">In forums</word>
<word key_rus="В форумах" key="archive_topic_not_forums" js="0">In forums</word>
<word key_rus="Закреплённые/Откреплённые" key="archive_topic_pinned" js="0">Pinned/Unpinned</word>
<word key_rus="Популярные/Непопулярные" key="archive_topic_featured" js="0">Featured/Unfeatured</word>
<word key_rus="Заблокированные/Разблокированнные" key="archive_topic_state" js="0">Locked/Unlocked</word>
<word key_rus="Открыто" key="unlocked" js="0">Unlocked</word>
<word key_rus="Скрыта/Отображена" key="archive_topic_approved" js="0">Hidden/Unhidden</word>
<word key_rus="Отображено" key="unhidden" js="0">Unhidden</word>
<word key_rus="Опрос" key="archive_topic_poll" js="0">Poll</word>
<word key_rus="С опросами" key="topic_has_poll" js="0">Has poll</word>
<word key_rus="Без опросов" key="topic_does_not_have_poll" js="0">Does not have poll</word>
<word key_rus="Голосов последнего опроса: %s" key="poll_with_recent_vote" js="0">Last poll vote: %s</word>
<word key_rus="Ответов" key="archive_topic_post" js="0">Replies</word>
<word key_rus="Просмотров" key="archive_topic_view" js="0">Views</word>
<word key_rus="Рейтинг" key="archive_topic_rating" js="0">Rating</word>
<word key_rus="Автор" key="archive_topic_starter" js="0">Started By</word>
<word key_rus="Автор" key="archive_topic_starter_not" js="0">Started By</word>
<word key_rus="Но не тогда, когда &lt;em&gt;любое&lt;/em&gt; из следующих условий выполняется..." key="archive_topics_not_where" js="0"><![CDATA[But not when <em>any</em> of the following conditions are true...]]></word>
<word key_rus="Сообщений" key="archive_not_topic_post" js="0">Posts</word>
<word key_rus="Просмотров" key="archive_not_topic_view" js="0">Views</word>
<word key_rus="Рейтинг" key="archive_not_topic_rating" js="0">Rating</word>
<word key_rus="Последнее сообщение" key="archive_last_post" js="0">Last Post</word>
<word key_rus="Последнее сообщение" key="archive_not_last_post" js="0">Last Post</word>
<word key_rus="Хранение архивированных сообщений" key="archive_storage" js="0">Archived Post Storage</word>
<word key_rus="Переместить архивированные сообщения в" key="archive_storage_location" js="0">Move archived posts to</word>
<word key_rus="Если вы уже запустили архивирование и хотите изменить место хранения, вам необходимо вручную переместить сообщения, которые уже заархивировались." key="archive_storage_location_desc" js="0">If you have already set up archiving and want to change the storage location, you will manually need to move the posts which have already been archived. Contact technical support for assistance.</word>
<word key_rus="Существующую базу данных" key="archive_storage_location_local" js="0">A database table within the same database as the rest of the site</word>
<word key_rus="Удалённую базу данных" key="archive_storage_location_remote" js="0">A remote database</word>
<word key_rus="Более" key="greater_than" js="0">More than</word>
<word key_rus="Менее" key="less_than" js="0">Less than</word>
<word key_rus="Всё время" key="any_time" js="0">Any time</word>
<word key_rus="Количество тем будет архивировано согласно данным настройкам" key="archive_rules_effects" js="0">Number of topics that will be archived with selected rules</word>
<word key_rus="Порядок сортировки по умолчанию" key="forum_sort_key" js="0">Default sort order</word>
<word key_rus="Стандартный порядок сортировки" key="forum_sort_key_qa" js="0">Default sort order</word>
<word key_rus="Настройки архивирования" key="archive_settings" js="0">Archiving Settings</word>
<word key_rus="Включить архивирование?" key="archive_on" js="0">Enable Archiving?</word>
<word key_rus="Архивы сообщений." key="task__archive" js="0">Archives posts.</word>
<word key_rus="Разархивированные сообщения." key="task__unarchive" js="0">Unarchives posts.</word>
<word key_rus="Разархивировать" key="unarchive" js="0">Unarchive</word>
<word key_rus="Разархивирование этой темы исключит её из будущих архивирований. После подтверждения, примерно через {# [*1:минуту][*2:минуты][*3:минуты][*4:минуты][11:минут][12:минут][13:минут][14:минут][?:минут]}, тема будет разархивирована." key="unarchive_confirm" js="0">Unarchiving this topic will exclude it from being archived again in the future. After confirming, it will take about {# [1:minute][?:minutes]} until the topic is actually unarchived.</word>
<word key_rus="Некоторые архивированные темы больше не соответствуют настройкам архивирования. Хотите разархивировать их?" key="uanrchive_settings_change" js="0">Some topics that are already archived no longer match your archive settings. Would you like to unarchive them?</word>
<word key_rus="Да, восстановить темы, которые не соответствуют новым настройкам архивирования" key="restore_unmatched_settings" js="0">Yes, restore topics that do not match the new archive settings</word>
<word key_rus="Нет, держать все текущие архивированные темы как архивированные" key="leave_archived_topics" js="0">No, keep all currently archived topics as archived</word>
<word key_rus="Хост" key="archive_remote_sql_host" js="0">Host</word>
<word key_rus="Имя пользователя" key="archive_remote_sql_user" js="0">Username</word>
<word key_rus="Пароль" key="archive_remote_sql_pass" js="0">Password</word>
<word key_rus="Имя базы данных" key="archive_remote_sql_database" js="0">Database Name</word>
<word key_rus="База данных должна быть уже создана. Если вы не уверены, как создать базу данных, обратитесь к вашему хостинг-провайдеру за помощью." key="archive_remote_sql_database_desc" js="0">The database must be already created. If you're not sure how to create a database, contact your hosting provider for assistance.</word>
<word key_rus="Порт" key="archive_sql_port" js="0">Port</word>
<word key_rus="Если не уверены, оставьте значение по умолчанию." key="archive_sql_port_desc" js="0">If you're not sure, leave at the default value.</word>
<word key_rus="Сокет" key="archive_sql_socket" js="0">Socket</word>
<word key_rus="Если не указано, будет использоваться настройка по умолчанию. Если вы не уверены, оставьте значение пустым." key="archive_sql_socket_desc" js="0">If not provided, the server's default setting will be used. If you're not sure, leave at the default value.</word>
<word key_rus="Префикс таблицы" key="archive_sql_tbl_prefix" js="0">Table Prefix</word>
<word key_rus="Если указано, таблица с архивированной информацией будет создана с этим префиксом. Рекомендуется оставить пустым." 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_rus="Возникла проблема с предоставленными данными удалённой базы данных: %s" key="archive_remote_db_error" js="0">There was a problem with the remote database details provided: %s</word>
<word key_rus="Изменены настройки архивирования" key="acplogs__archive_settings" js="0">Edited Archive Settings</word>
<word key_rus="" key="perm_forum_perm__label" js="0"></word>
<word key_rus="Просмотр форума" key="perm_forum_perm__view" js="0">See Forum</word>
<word key_rus="Просмотр форума&lt;br&gt;&lt;small&gt;(с {# [1:элементов][?:элементами]} контента)&lt;/small&gt;" key="perm_forum_perm__view_rest" js="0"><![CDATA[See Forum<br><small>(with {# [1:item][?:items]} of content)</small>]]></word>
<word key_rus="Чтение тем" key="perm_forum_perm__read" js="0">Read Topics</word>
<word key_rus="Читать темы&lt;br&gt;&lt;small&gt;(если указан пароль)&lt;/small&gt;" key="perm_forum_perm__read_pass" js="0"><![CDATA[Read Topics<br><small>(if password is provided)</small>]]></word>
<word key_rus="Чтение вопросов" key="perm_forum_perm__read_qa" js="0">Read Questions</word>
<word key_rus="Читать вопросы&lt;br&gt;&lt;small&gt;(если указан пароль)&lt;/small&gt;" key="perm_forum_perm__read_qa_pass" js="0"><![CDATA[Read Questions<br><small>(if password is provided)</small>]]></word>
<word key_rus="Чтение собственных тем" key="perm_forum_perm__read2" js="0">Read Own Topics</word>
<word key_rus="Читать собственные темы&lt;br&gt;&lt;small&gt;(если указан пароль)&lt;/small&gt;" key="perm_forum_perm__read2_pass" js="0"><![CDATA[Read Own Topics<br><small>(if password is provided)</small>]]></word>
<word key_rus="Чтение собственных вопросов" key="perm_forum_perm__read2_qa" js="0">Read Own Questions</word>
<word key_rus="Читать собственные вопросы&lt;br&gt;&lt;small&gt;(если указан пароль)&lt;/small&gt;" key="perm_forum_perm__read2_qa_pass" js="0"><![CDATA[Read Own Questions<br><small>(if password is provided)</small>]]></word>
<word key_rus="Публикация новых тем" key="perm_forum_perm__add" js="0">Post New Topics</word>
<word key_rus="Публиковать темы&lt;br&gt;&lt;small&gt;(с {# [1:элементом][?:элементами]} контента)&lt;/small&gt;" key="perm_forum_perm__add_rest" js="0"><![CDATA[Post New Topics<br><small>(with {# [1:item][?:items]} of content)</small>]]></word>
<word key_rus="Ответы в темах" key="perm_forum_perm__reply" js="0">Reply To Topics</word>
<word key_rus="Отвечать в темах&lt;br&gt;&lt;small&gt;(с {# [1:элементом][?:элементами]} контента)&lt;/small&gt;" key="perm_forum_perm__reply_rest" js="0"><![CDATA[Reply To Topics<br><small>(with {# [1:item][?:items]} of content)</small>]]></word>
<word key_rus="Публикация новых вопросов" key="perm_forum_perm__add_qa" js="0">Ask New Questions</word>
<word key_rus="Задавать вопросы&lt;br&gt;&lt;small&gt;(с {# [1:элементом][?:элементами]} контента)&lt;/small&gt;" key="perm_forum_perm__add_qa_rest" js="0"><![CDATA[Ask New Questions<br><small>(with {# [1:item][?:items]} of content)</small>]]></word>
<word key_rus="Публикация ответов" key="perm_forum_perm__reply_qa" js="0">Post Answers</word>
<word key_rus="Публиковать ответы&lt;br&gt;&lt;small&gt;(с {# [1:элементом][?:элементами]} контента)&lt;/small&gt;" key="perm_forum_perm__reply_qa_rest" js="0"><![CDATA[Post Answers<br><small>(with {# [1:item][?:items]} of content)</small>]]></word>
<word key_rus="Скачивание вложений" key="perm_forum_perm__attachments" js="0">Download Attachments</word>
<word key_rus="{# [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}" key="posts_number" js="0">{# [1:post][?:posts]}</word>
<word key_rus="{!# [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}" key="posts_no_number" js="0">{!# [1:post][?:posts]}</word>
<word key_rus="{# [*1:ответ][*2:ответа][*3:ответа][*4:ответа][*1:ответ][11:ответов][12:ответов][13:ответов][14:ответов][?:ответов]}" key="replies_number" js="0">{# [1:reply][?:replies]}</word>
<word key_rus="{!# [*1:ответ][*2:ответа][*3:ответа][*4:ответа][*1:ответ][11:ответов][12:ответов][13:ответов][14:ответов][?:ответов]}" key="replies_no_number" js="0">{!# [1:reply][?:replies]}</word>
<word key_rus="{# [*1:посещение][*2:посещения][*3:посещения][*4:посещения][11:посещений][12:посещений][13:посещений][14:посещений][?:посещений]} по этой ссылке" key="redirect_hits" js="0">{# [1:visit][?:visits]} to this link</word>
<word key_rus="{# [*1:ответ][*2:ответа][*3:ответа][*4:ответа][*1:ответ][11:ответов][12:ответов][13:ответов][14:ответов][?:ответов]}" key="answers_number" js="0">{# [1:answer][?:answers]}</word>
<word key_rus="{!# [*1:ответ][*2:ответа][*3:ответа][*4:ответа][*1:ответ][11:ответов][12:ответов][13:ответов][14:ответов][?:ответов]}" key="answers_no_number" js="0">{!# [1:answer][?:answers]}</word>
<word key_rus="{# [-*1:голос][-*2:голоса][-*3:голоса][-*4:голоса][*1:голос][*2:голоса][*3:голоса][*4:голоса][-11:голосов][-12:голосов][-13:голосов][-14:голосов][11:голосов][12:голосов][13:голосов][14:голосов][?:голосов]}" key="votes_number" js="0">{# [-1:vote][1:vote][?:votes]}</word>
<word key_rus="{!# [-*1:голос][-*2:голоса][-*3:голоса][-*4:голоса][*1:голос][*2:голоса][*3:голоса][*4:голоса][-11:голосов][-12:голосов][-13:голосов][-14:голосов][11:голосов][12:голосов][13:голосов][14:голосов][?:голосов]}" key="votes_no_number" js="0">{!# [-1:vote][1:vote][?:votes]}</word>
<word key_rus="{# в очереди [*1:тема][*2:темы][*3:темы][*4:темы][11:тем][12:тем][13:тем][14:тем][?:тем]}" key="queued_topics_badge" js="0">{# queued [1:topic][?:topics]}</word>
<word key_rus="{# в очереди [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}" key="queued_posts_badge" js="0">{# queued [1:post][?:posts]}</word>
<word key_rus="Неодобренные темы" key="queued_topics" js="0">Unapproved topics</word>
<word key_rus="Темы с неодобренными сообщениями" key="queued_posts" js="0">Topics with unapproved posts</word>
<word key_rus="Создать новую тему" key="start_new_topic" js="0">Start new topic</word>
<word key_rus="создать новую тему" key="start_new_topic_lc" js="0">start new topic</word>
<word key_rus="Создать новую тему в этом форуме" key="start_new_topic_desc" js="0">Start a new topic in this forum</word>
<word key_rus="Задать вопрос" key="ask_a_question" js="0">Ask a question</word>
<word key_rus="задать вопрос" key="ask_a_question_lc" js="0">ask a question</word>
<word key_rus="Задать вопрос в этом форуме" key="ask_a_question_desc" js="0">Ask a question in this forum</word>
<word key_rus="Ответить на вопрос" key="answer_this_question" js="0">Answer this question</word>
<word key_rus="Ответить" key="reply_to_this_topic" js="0">Reply to this topic</word>
<word key_rus="Отметить форум прочитанным" key="mark_forum_read" js="0">Mark forum as read</word>
<word key_rus="Отметить все темы в этом форуме прочитанными" key="mark_forum_read_title" js="0">Mark all topics in this forum as read</word>
<word key_rus="Неверный пароль." key="forum_password_bad" js="0">Password Incorrect.</word>
<word key_rus="Детали темы" key="topic_details" js="0">Topic Details</word>
<word key_rus="Контент" key="topic_mainTab" js="0">Content</word>
<word key_rus="Контент" key="question_mainTab" js="0">Content</word>
<word key_rus="Вопросы" key="question_title" js="0">Question</word>
<word key_rus="Заголовок" key="topic_title" js="0">Title</word>
<word key_rus="Теги" key="topic_tags" js="0">Tags</word>
<word key_rus="" key="topic_content" js="0"></word>
<word key_rus="" key="topic_auto_follow" js="0"></word>
<word key_rus="Уведомлять меня об ответах" key="topic_auto_follow_suffix" js="0">Notify me of replies</word>
<word key_rus="Опрос" key="topic_pollTab" js="0">Poll</word>
<word key_rus="" key="topic_poll" js="0"></word>
<word key_rus="Время открытия" key="topic_open_time" js="0">Unlock time</word>
<word key_rus="Время закрытия" key="topic_close_time" js="0">Lock time</word>
<word key_rus="Фильтр" key="topic_type" js="0">Filter</word>
<word key_rus="Все" key="all_topics" js="0">All</word>
<word key_rus="Разблокировано" key="open_topics" js="0">Unlocked</word>
<word key_rus="Сейчас популярно" key="popular_now" js="0">Popular now</word>
<word key_rus="Заблокировано" key="locked_topics" js="0">Locked</word>
<word key_rus="Опрос" key="poll" js="0">Poll</word>
<word key_rus="Перемещено" key="moved_topics" js="0">Moved</word>
<word key_rus="Темы, которые я начал" key="topics_i_started" js="0">Topics I started</word>
<word key_rus="Темы, в которых я отвечал" key="topics_i_posted_in" js="0">Topics I've posted in</word>
<word key_rus="Вопросы, которые я задал" key="questions_i_asked" js="0">Questions I asked</word>
<word key_rus="Вопросы, на которые я ответил" key="questions_i_posted_in" js="0">Questions I've posted an answer to</word>
<word key_rus="Вопросы с Лучшими ответами" key="question_answered" js="0">Questions with Best Answers</word>
<word key_rus="Вопросы без Лучших Ответов" key="question_not_answered" js="0">Questions without Best Answers</word>
<word key_rus="Дата последнего сообщения" key="last_post" js="0">Last post date</word>
<word key_rus="Имя последнего автора" key="last_poster" js="0">Name of last poster</word>
<word key_rus="Имя автора темы" key="topic_starter" js="0">Name of topic starter</word>
<word key_rus="Имя пользователя, задавшего вопрос" key="question_asker" js="0">Name of user who asked question</word>
<word key_rus="Дата начала" key="topic_started" js="0">Start Date</word>
<word key_rus="Создано %s" key="topic_started_date" js="0">Started %s</word>
<word key_rus="Ответов" key="replies" js="0">Replies</word>
<word key_rus="Сортировка" key="sort_direction" js="0">Sort Direction</word>
<word key_rus="Больше ответов" key="sort_num_replies" js="0">Most Replies</word>
<word key_rus="Больше голосов" key="sort_question_rating" js="0">Most Votes</word>
<word key_rus="По возрастанию (сначала старые/по алфавиту)" key="asc" js="0">Ascending (oldest first/alphabetically)</word>
<word key_rus="По убыванию (сначала новые)" key="desc" js="0">Descending (newest first)</word>
<word key_rus="Последний ответ" key="time_frame" js="0">Last Reply</word>
<word key_rus="Всегда" key="show_all" js="0">Anytime</word>
<word key_rus="Сегодня" key="today" js="0">Today</word>
<word key_rus="Мой последний вход (%s)" key="since_last_visit" js="0">My Last Login (%s)</word>
<word key_rus="Главная страница форума" key="forum_home" js="0">Forum Home</word>
<word key_rus="Все вопросы в этом форуме" key="all_questions" js="0">All questions in this forum</word>
<word key_rus="Популярные вопросы" key="featured_question" js="0">Featured Question</word>
<word key_rus="Самые популярные вопросы" key="most_popular_questions" js="0">Most Popular Questions</word>
<word key_rus="За последние 30 дней" key="from_the_past_30_days" js="0">From the past 30 days</word>
<word key_rus="Просмотр вопросов" key="explore_questions_title" js="0">Explore Questions</word>
<word key_rus="Новые вопросы" key="new_questions" js="0">New Questions</word>
<word key_rus="В ожидании ответа" key="awaiting_an_answer" js="0">Awaiting an answer</word>
<word key_rus="Лучший ответ от %s, %s" key="best_answer_by" js="0">Best answer by %s, %s</word>
<word key_rus="Ответ от %s, %s" key="ask_byline" js="0">Asked by %s, %s</word>
<word key_rus="Ответ от &lt;span itemprop='name'&gt;%s&lt;/span&gt;, %s" key="ask_byline_itemprop" js="0"><![CDATA[Asked by <span itemprop='name'>%s</span>, %s]]></word>
<word key_rus="Ответ от %s" key="ask_byline_no_date" js="0">Asked by %s</word>
<word key_rus="%s последних тем" key="forum_rss_title_topics" js="0">%s Latest Topics</word>
<word key_rus="%s последних вопросов" key="forum_rss_title_questions" js="0">%s Latest Questions</word>
<word key_rus="Первое сообщение" key="first_post" js="0">First post</word>
<word key_rus="Последнее сообщение" key="latest_post" js="0">Latest post</word>
<word key_rus="Последний ответ" key="latest_answer" js="0">Latest answer</word>
<word key_rus="Первое непрочитанное" key="first_unread_post_hover" js="0">First unread</word>
<word key_rus="Лучший ответ" key="best_answer_post" js="0">Best answer</word>
<word key_rus="Опубликовал %s" key="topic_started_by" js="0">Started by %s</word>
<word key_rus="Тему" key="topic" js="0">Topic</word>
<word key_rus="{# [*1:ответ][*2:ответа][*3:ответа][*4:ответа][11:ответов][12:ответов][13:ответов][14:ответов][?:ответов]} на этот вопрос" key="answer_count" js="0">{# [1:answer][?:answers]} to this question</word>
<word key_rus="В теме {# [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}" key="reply_count" js="0">{# [1:post][?:posts]} in this topic</word>
<word key_rus="Лучший ответ на вопрос" key="best_answer_tooltip" js="0">Best answer to this question</word>
<word key_rus="Проголосовать за повышение ответа" key="vote_answer_up" js="0">Vote this answer up</word>
<word key_rus="Проголосовать за понижение ответа" key="vote_answer_down" js="0">Vote this answer down</word>
<word key_rus="Проголосовать за повышение вопроса" key="vote_question_up" js="0">Vote this question up</word>
<word key_rus="Проголосовать за понижение вопроса" key="vote_question_down" js="0">Vote this question down</word>
<word key_rus="Лучшие ответы" key="best_answers" js="0">Best Answers</word>
<word key_rus="Пометить как лучший ответ" key="set_as_best_answer" js="0">Mark this as a best answer</word>
<word key_rus="Убрать статус лучшего ответа" key="unset_as_best_answer" js="0">Unset as best answer</word>
<word key_rus="Сортировать по голосам" key="sort_by_answers" js="0">Sort by votes</word>
<word key_rus="Сортировать по дате" key="sort_by_date" js="0">Sort by date</word>
<word key_rus="Выбор форума" key="select_forum" js="0">Select Forum</word>
<word key_rus="Создать новую тему" key="create_new_topic" js="0">Create New Topic</word>
<word key_rus="Задать новый вопрос" key="ask_new_question" js="0">Ask New Question</word>
<word key_rus="Ответы на этот вопрос пока отсутствуют" key="no_answers" js="0">There have been no answers to this question yet</word>
<word key_rus="Сообщений пока нет" key="no_forum_posts" js="0">No posts here yet</word>
<word key_rus="Сообщений для отображения нет" key="no_forum_posts_password" js="0">No posts to show</word>
<word key_rus="Сообщений для отображения нет" key="no_posts_returned" js="0">There are no posts to show</word>
<word key_rus="Темы" key="topic_pl" js="0">Topics</word>
<word key_rus="темы" key="topic_pl_lc" js="0">topics</word>
<word key_rus="Сообщения" key="post_pl" js="0">Posts</word>
<word key_rus="сообщения" key="post_pl_lc" js="0">posts</word>
<word key_rus="Архивированные сообщения" key="archivedpost_pl" js="0">Archived Posts</word>
<word key_rus="архивированные сообщения" key="archivedpost_pl_lc" js="0">archived posts</word>
<word key_rus="Ответить в этой теме..." key="topic__comment_placeholder" js="0">Reply to this topic...</word>
<word key_rus="Ответить на вопрос..." key="question__comment_placeholder" js="0">Answer this question...</word>
<word key_rus="Действия модератора" key="moderator_actions" js="0">Moderation Actions</word>
<word key_rus="Свернуть категорию" key="toggle_this_category" js="0">Toggle this category</word>
<word key_rus="Эта тема заблокирована" key="topic_locked" js="0">This topic is locked</word>
<word key_rus="Эта тема закреплена" key="topic_pinned" js="0">This topic is pinned</word>
<word key_rus="Эта тема скрыта" key="topic_hidden" js="0">This topic is hidden</word>
<word key_rus="Эта тема популярна" key="topic_featured" js="0">This topic is featured</word>
<word key_rus="Заблокировать тему" key="create_topic_locked" js="0">Lock topic</word>
<word key_rus="Закрепить тему" key="create_topic_pinned" js="0">Pin topic</word>
<word key_rus="Скрыть тему" key="create_topic_hidden" js="0">Hide topic</word>
<word key_rus="Сделать популярной" key="create_topic_featured" js="0">Feature topic</word>
<word key_rus="Отметить тему прочитанной" key="mark_topic_read" js="0">Mark this topic read</word>
<word key_rus="Имеет лучший ответ" key="answered" js="0">Has best answer</word>
<word key_rus="В ожидании лучшего ответа" key="awaiting_answer" js="0">Awaiting best answer</word>
<word key_rus="Введите пароль" key="forum_requires_password" js="0">Enter password</word>
<word key_rus="Вход на форум" key="enter_forum" js="0">Enter forum</word>
<word key_rus="Для просмотра этого форума необходимо ввести пароль. Если вы знаете пароль, введите его ниже." key="enter_forum_password_1" js="0">Viewing this forum requires a password. If you know it, enter it below.</word>
<word key_rus="{!# [*1:ответ][*2:ответа][*3:ответа][*4:ответа][11:ответов][12:ответов][13:ответов][14:ответов][?:ответов]}" key="forums_comments" js="0">{!# [1:reply][?:replies]}</word>
<word key_rus="{!# [*1:просмотр][*2:просмотра][*3:просмотра][*4:просмотра][11:просмотров][12:просмотров][13:просмотров][14:просмотров][?:просмотров]}" key="forums_num_views" js="0">{!# [1:view][?:views]}</word>
<word key_rus="Поделиться сообщением" key="share_this_post" js="0">Share this post</word>
<word key_rus="Подфорумы:" key="subforums" js="0">Subforums:</word>
<word key_rus="Подфорумы" key="subforums_header" js="0">Subforums</word>
<word key_rus="Форумы" key="subforums_header_category" js="0">Forums</word>
<word key_rus="Ответить в тему" key="reply_to_topic" js="0">Reply to this topic</word>
<word key_rus="Ссылка на сообщение" key="link_to_post" js="0">Link to post</word>
<word key_rus="Поделиться на другие сайты" key="share_externally" js="0">Share on other sites</word>
<word key_rus="Популярные темы" key="featured_topics" js="0">Featured Topics</word>
<word key_rus="В этой теме нет новых сообщений" key="no_new_posts" js="0">No new posts in this topic</word>
<word key_rus="Новые сообщения в этой теме" key="new_posts" js="0">New posts in this topic</word>
<word key_rus="Популярная тема" key="featured_topic" js="0">Featured Topic</word>
<word key_rus="Следующий вопрос" key="next_question" js="0">Next question</word>
<word key_rus="Следующая тема" key="next_topic" js="0">Next topic</word>
<word key_rus="Предыдущий вопрос" key="prev_question" js="0">Previous question</word>
<word key_rus="Предыдущая тема" key="prev_topic" js="0">Previous topic</word>
<word key_rus="После публикации..." key="topic_create_state" js="0">After posting...</word>
<word key_rus="Информация о теме" key="topic_information" js="0">Topic Information</word>
<word key_rus="Опции модератора" key="topic_moderator_options" js="0">Moderator Options</word>
<word key_rus="Отправить вопрос" key="submit_question" js="0">Submit Question</word>
<word key_rus="Отправить тему" key="submit_topic" js="0">Submit Topic</word>
<word key_rus="Изменить тему" key="submit_topic_edit" js="0">Edit Topic</word>
<word key_rus="Изменить вопрос" key="submit_question_edit" js="0">Edit Question</word>
<word key_rus="Отправить" key="topic_submit_comment" js="0">Submit Reply</word>
<word key_rus="Изменить вопрос" key="edit_question" js="0">Edit Question</word>
<word key_rus="Изменить тему" key="edit_topic" js="0">Edit Topic</word>
<word key_rus="Изменить сообщение" key="edit_reply" js="0">Edit Post</word>
<word key_rus="Перейти к %s" key="go_to_forum" js="0">Go to %s</word>
<word key_rus="Перейти к списку тем" key="go_back_to_forum" js="0">Go To Topic Listing</word>
<word key_rus="Перейти к списку вопросов" key="go_back_to_qa_forum" js="0">Go To Question Listing</word>
<word key_rus="Перейти к первому непрочитанному сообщению" key="first_unread_post" js="0">Go to first unread post</word>
<word key_rus="Перейти к последнему сообщению" key="get_last_post" js="0">Go to last post</word>
<word key_rus="Заархивировано" key="topic_is_archived" js="0">Archived</word>
<word key_rus="Эта тема находится в архиве и закрыта для дальнейших ответов." key="topic_archived_desc" js="0">This topic is now archived and is closed to further replies.</word>
<word key_rus="В форуме {# [*1:тема][*2:темы][*3:темы][*4:темы][11:тем][12:тем][13:тем][14:тем][?:тем]}" key="count_topics_in_forum" js="0">{# [1:topic][?:topics] in this forum}</word>
<word key_rus="В форуме {# [*1:вопрос][*2:вопроса][*3:вопроса][*4:вопроса][11:вопросов][12:вопросов][13:вопросов][14:вопросов][?:вопросов]}" key="count_questions_in_forum" js="0">{# [1:question][?:questions] in this forum}</word>
<word key_rus="Следующая непрочитанная тема" key="view_next_unread" js="0">Next unread topic</word>
<word key_rus="Следующий непрочитанный вопрос" key="view_next_unread_question" js="0">Next unread question</word>
<word key_rus="Перейти к следующей теме, содержащей новый контент" key="view_next_unread_title" js="0">Go to the next topic that has new content</word>
<word key_rus="Перейти к следующему вопросу, который имеет новые ответы" key="view_next_unread_question_title" js="0">Go to the next question that has new answers</word>
<word key_rus="Скрыть все подписи" key="hide_all_signatures" js="0">Hide all signatures</word>
<word key_rus="Скрыть подпись %s" key="hide_members_signature" js="0">Hide %s's signature</word>
<word key_rus="Перейти в тему по новому местонахождению" key="go_to_new_location" js="0">Go to this topic in its new location</word>
<word key_rus="Тема была перемещена в форум &lt;a href='%s'&gt;&lt;strong&gt;%s&lt;/strong&gt;&lt;/a&gt;" key="topic_moved_to" js="0"><![CDATA[Topic was moved to forum <a href='%s'><strong>%s</strong></a>]]></word>
<word key_rus="Вопрос был перемещён в форум &lt;a href='%s'&gt;&lt;strong&gt;%s&lt;/strong&gt;&lt;/a&gt;" key="question_moved_to" js="0"><![CDATA[Question was moved to forum <a href='%s'><strong>%s</strong></a>]]></word>
<word key_rus="Тема была объединена с &lt;a href='%s'&gt;&lt;strong&gt;%s&lt;/strong&gt;&lt;/a&gt;" key="topic_merged_to" js="0"><![CDATA[Topic was merged with <a href='%s'><strong>%s</strong></a>]]></word>
<word key_rus="Вопрос был объединенён с &lt;a href='%s'&gt;&lt;strong&gt;%s&lt;/strong&gt;&lt;/a&gt;" key="question_merged_to" js="0"><![CDATA[Question was merged with <a href='%s'><strong>%s</strong></a>]]></word>
<word key_rus="Эта тема" key="this_topic" js="0">This Topic</word>
<word key_rus="Этот форум" key="this_forum" js="0">This Forum</word>
<word key_rus="Форум" key="forum_id" js="0">Forum</word>
<word key_rus="Форумы" key="announce_forums" js="0">Forums</word>
<word key_rus="Тема форума" key="embed_topic" js="0">Forum Topic</word>
<word key_rus="Вопросы с лучшими Ответами" key="questions_with_best_answers" js="0">Questions With Best Answers</word>
<word key_rus="Вопросы без лучших Ответов" key="questions_without_best_answers" js="0">Questions Without Best Answers</word>
<word key_rus="Это популярное сообщение." key="this_is_a_popular_post" js="0">This is a popular post.</word>
<word key_rus="Оценить эту тему:" key="rate_this_topic" js="0">Rate this topic</word>
<word key_rus="Оценить этот вопрос:" key="rate_this_question" js="0">Rate this question</word>
<word key_rus="Войти, чтобы оценить этот вопрос" key="sign_in_rate_question" js="0">Sign in to rate this question</word>
<word key_rus="Войти, чтобы оценить этот ответ" key="sign_in_rate_answer" js="0">Sign in to rate this answer</word>
<word key_rus="В этом форуме ещё нет вопросов" key="no_questions_in_forum" js="0">There are no questions in this forum yet</word>
<word key_rus="В этом форуме ещё нет тем" key="no_topics_in_forum" js="0">There are no topics in this forum yet</word>
<word key_rus="Задать первый вопрос" key="submit_first_question" js="0">Ask the first question</word>
<word key_rus="Создать новую тему" key="submit_first_topic" js="0">Start the first topic</word>
<word key_rus="Эта тема ещё не одобрена и доступна только для модераторов." key="topic_pending_approval" js="0">This topic is not yet approved and is currently only visible to staff.</word>
<word key_rus="Тема закрыта, но вам разрешено добавлять в неё новые ответы." key="topic_locked_can_comment" js="0">This topic is locked, but your permissions allow you to add new replies.</word>
<word key_rus="Тема предназначена только для опросов, но вы можете публиковать в ней сообщения." key="topic_poll_can_comment" js="0">This is a poll-only topic, but your permissions allow you to add new replies.</word>
<word key_rus="Эта тема закрыта для публикации ответов." key="topic_locked_cannot_comment" js="0">This topic is now closed to further replies.</word>
<word key_rus="IP: %s" key="ip_prefix" js="0">IP: %s</word>
<word key_rus="Популярные вопросы за последний месяц" key="popular_questions_title" js="0">Popular questions from the past month</word>
<word key_rus="Популярных вопросов для отображения нет" key="no_popular_questions" js="0">There are no popular questions to show right now</word>
<word key_rus="Вопросы без ответов" key="new_questions_title_no_answer" js="0">Questions with no answers</word>
<word key_rus="Вопросы без лучшего ответа" key="new_questions_title_no_best" js="0">Questions with no best answer</word>
<word key_rus="Новых вопросов нет" key="no_new_questions" js="0">There are no new questions to show right now</word>
<word key_rus="Удалить тему" key="topic_delete_title" js="0">Delete this topic</word>
<word key_rus="Одобрить эту тему" key="approve_title_topic" js="0">Approve this topic</word>
<word key_rus="Тема не может быть отображена, т.к. форум защищён паролем." key="no_perm_topic_password" js="0">This topic cannot be displayed because it is in a password protected forum.</word>
<word key_rus="Тема не может быть отображена, т.к. она находится в форуме, для просмотра которого необходимо набрать {# [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}." key="no_perm_topic_min_posts" js="0">This topic cannot be displayed because it is in a forum which requires at least {# [1:post][?:posts]} to view.</word>
<word key_rus="Сообщение не может быть отображено, т.к. оно находится в защищённом паролем форуме." key="no_perm_post_password" js="0">This post cannot be displayed because it is in a password protected forum.</word>
<word key_rus="Сообщение не может быть отображено, т.к. оно находится в форуме, для просмотра которого необходимо набрать {# [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}." key="no_perm_post_min_posts" js="0">This post cannot be displayed because it is in a forum which requires at least {# [1:post][?:posts]} to view.</word>
<word key_rus="Введите пароль" key="enter_password" js="0">Enter Password</word>
<word key_rus="Тема будет автоматически открыта %s в %s" key="topic_unlocks_at" js="0">Topic will be automatically unlocked %s at %s</word>
<word key_rus="Открытие %s" key="topic_unlocks_at_short" js="0">Unlocks %s</word>
<word key_rus="Тема будет автоматически закрыта %s в %s" key="topic_locks_at" js="0">Topic will be automatically locked %s at %s</word>
<word key_rus="Закрытие %s" key="topic_locks_at_short" js="0">Locks %s</word>
<word key_rus="Сохраненные Действия" key="saved_actions" js="0">Saved Actions</word>
<word key_rus="Сохранённое действие" key="saved_actions_sg" js="0">Saved Action</word>
<word key_rus="Название" key="mm_title" js="0">Name</word>
<word key_rus="Форумы" key="mm_forums" js="0">Forums</word>
<word key_rus="Свойства" key="topic_properties" js="0">Properties</word>
<word key_rus="Не изменять" key="mm_leave" js="0">Do not change</word>
<word key_rus="Закрыть/Открыть" key="topic_state" js="0">Lock/Unlock</word>
<word key_rus="Закрепить/Открепить" key="topic_pin" js="0">Pin/Unpin</word>
<word key_rus="Скрыть/Показать" key="topic_approve" js="0">Hide/Unhide</word>
<word key_rus="Переместить в" key="topic_move" js="0">Move To</word>
<word key_rus="Не перемещать" key="topic_move_none" js="0">Do not move</word>
<word key_rus="Оставить ссылку на новое месторасположение?" key="topic_move_link" js="0">Leave a link to the new location?</word>
<word key_rus="Добавить в начало заголовка" key="topic_title_st" js="0">Add to the start of the title</word>
<word key_rus="Добавить в конец заголовка" key="topic_title_end" js="0">Add to the end of the title</word>
<word key_rus="Добавить ответ" key="add_reply" js="0">Add Reply</word>
<word key_rus="Добавить ответ?" key="topic_reply" js="0">Add reply?</word>
<word key_rus="Содержание ответа" key="topic_reply_content" js="0">Reply</word>
<word key_rus="Прибавить количество ответов?" key="topic_reply_postcount" js="0">Increment post count?</word>
<word key_rus="Можно использовать сохранённые действия?" key="can_use_saved_actions" js="0">Can use saved actions?</word>
<word key_rus="Запущено '%s' сохранённое действие на тему: &lt;a href='%s'&gt;%s&lt;/a&gt;" key="modlog__saved_action" js="0"><![CDATA[Ran "%s" saved action on topic: <a href='%s'>%s</a>]]></word>
<word key_rus="Разархивированная тема: &lt;a href='%s'&gt;%s&lt;/a&gt;" key="modlog__unarchived_topic" js="0"><![CDATA[Unarchived topic: <a href='%s'>%s</a>]]></word>
<word key_rus="Проверка RSS/Atom лент на наличие новых статей и импорт в Форумы." key="task__rssimport" js="0">Checks RSS/Atom feeds for new articles and imports into Forums.</word>
<word key_rus="Удаление устаревших данных тем" key="queue_deleting_legacy_topics" js="0">Deleting legacy topic data</word>
<word key_rus="Удаление устаревших данных сообщений" key="queue_deleting_legacy_posts" js="0">Deleting legacy post data</word>
<word key_rus="Обновление неверно скрытых тем" key="queue_fixing_hidden_first_post" js="0">Updating incorrectly hidden topics</word>
<word key_rus="Перестроение отметок новых тем в постах" key="queue_rebuilding_new_topic_flag" js="0">Rebuilding new topic flag in posts</word>
<word key_rus="Статистика форума" key="block_forumStatistics" js="0">Forum Statistics</word>
<word key_rus="Отображает основную статистику форума" key="block_forumStatistics_desc" js="0">Shows general forum statistics</word>
<word key_rus="Всего тем" key="total_topics" js="0">Total Topics</word>
<word key_rus="Всего сообщений" key="total_posts" js="0">Total Posts</word>
<word key_rus="Последние темы" key="block_latestTopics" js="0">Latest Topics</word>
<word key_rus="Отображение последних опубликованных тем" key="block_latestTopics_desc" js="0">Show the latest topics posted</word>
<word key_rus="Просмотр темы %s" key="view_this_topic" js="0">View the topic %s</word>
<word key_rus="Популярное сейчас" key="block_hotTopics" js="0">Popular Now</word>
<word key_rus="Показать популярные темы" key="block_hotTopics_desc" js="0">Show topics that are currently popular</word>
<word key_rus="Популярные темы" key="block_featuredTopics" js="0">Featured Topics</word>
<word key_rus="Показать популярные в настоящее время темы" key="block_featuredTopics_desc" js="0">Show topics that are currently featured</word>
<word key_rus="Лента тем" key="block_topicFeed" js="0">Topic Feed</word>
<word key_rus="Создание ленты тем, основанной на пользовательских сортировке и порядке отображения" key="block_topicFeed_desc" js="0">Create a feed of topics based on custom sort and order options</word>
<word key_rus="Лента сообщений" key="block_postFeed" js="0">Post Feed</word>
<word key_rus="Создать ленту сообщений на основе настроенной сортировки" key="block_postFeed_desc" js="0">Create a feed of posts based on custom sort and order options</word>
<word key_rus="Темы" key="digest_area_forums_topic" js="0">Topics</word>
<word key_rus="Форумы" key="digest_area_forums_forum" js="0">Forums</word>
<word key_rus="%s создал тему в %s" key="x_created_topic_in" js="0">%s created a topic in %s</word>
<word key_rus="%s задал новый вопрос в %s" key="x_asked_new_question" js="0">%s asked a new question in %s</word>
<word key_rus="%s ответил в теме" key="x_replied_to_a_topic" js="0">%s replied to a topic</word>
<word key_rus="%s ответил на вопрос" key="x_answered_a_question" js="0">%s answered a question</word>
<word key_rus="Просмотр темы: %s" key="loc_forums_viewing_topic" js="0">Viewing Topic: %s</word>
<word key_rus="Просмотр форума: %s" key="loc_forums_viewing_forum" js="0">Viewing Forum: %s</word>
<word key_rus="Создание темы в: %s" key="loc_forums_creating_topic" js="0">Creating Topic in: %s</word>
<word key_rus="Просмотр форумов" key="loc_forums_index" js="0">Viewing Forums Index</word>
<word key_rus="После первой темы в каждом форуме" key="ad_forum_listing" js="0">After the first topic in each forum</word>
<word key_rus="После первого сообщения в каждой теме" key="ad_topic_view" js="0">After the first post in each topic</word>
<word key_rus="Новые темы" key="stats_new_topics" js="0">New Topics</word>
<word key_rus="Новые сообщения" key="stats_new_posts" js="0">New Posts</word>
<word key_rus="Новые темы за период времени" key="stats_topics_title" js="0">New topics by time period</word>
<word key_rus="Новые сообщения за период времени" key="stats_posts_title" js="0">New posts by time period</word>
<word key_rus="Форумы" key="widget_feed_container_topic" js="0">Forums</word>
<word key_rus="Темы" key="block_topicFeed_title" js="0">Topics</word>
<word key_rus="Сообщения" key="block_postFeed_title" js="0">Posts</word>
<word key_rus="Попытка импорта ленты завершилась ошибкой с сообщением: %s" key="rssimport_task_error" js="0">Attempting to import the feed failed with the following message: %s</word>
<word key_rus="Опрос" key="block_poll" js="0">Poll</word>
<word key_rus="Создание блока с опросом из темы" key="block_poll_desc" js="0">Create a block with a poll from a topic</word>
<word key_rus="Тема" key="widget_poll_tid" js="0">Topic</word>
<word key_rus="Начните вводить название темы" key="widget_poll_tid_desc" js="0">Start typing the name of the topic</word>
<word key_rus="Просмотр темы" key="poll_view_topic" js="0">View topic</word>
<word key_rus="Сообщения" key="__api_forums_posts" js="0">Posts</word>
<word key_rus="Темы" key="__api_forums_topics" js="0">Topics</word>
<word key_rus="Форум отмечен прочитанным" key="forumMarkedRead" js="1">Forum marked as read</word>
<word key_rus="Тема отмечена прочитанной" key="topicMarkedRead" js="1">Topic marked as read</word>
<word key_rus="В теме {# [*1:сообщение][*2:сообщения][*3:сообщения][*4:сообщения][11:сообщений][12:сообщений][13:сообщений][14:сообщений][?:сообщений]}" key="js_num_topic_posts" js="1">{# [1:post][?:posts]} in this topic</word>
<word key_rus="{!# [-*1:голос][-*2:голоса][-*3:голоса][-*4:голоса][*1:голос][*2:голоса][*3:голоса][*4:голоса][11:голосов][12:голосов][13:голосов][14:голосов][-11:голосов][-12:голосов][-13:голосов][-14:голосов][?:голосов]}" key="votes_no_number" js="1">{!# [-1:vote][1:vote][?:votes]}</word>
</app>
</language>
+86 -40
View File
@@ -65,10 +65,10 @@
"comment": "",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "last_poster_id",
"type": "MEDIUMINT",
"unsigned": false,
"type": "BIGINT",
"unsigned": true,
"values": [],
"zerofill": false
},
@@ -640,7 +640,7 @@
"position": 1,
"password": null,
"password_override": "",
"last_title": "Welcome!",
"last_title": "Добро пожаловать!",
"last_id": 1,
"sort_key": "last_post",
"show_rules": 0,
@@ -660,8 +660,8 @@
"min_posts_post": 0,
"min_posts_view": 0,
"can_view_others": 1,
"name_seo": "a-test-category",
"seo_last_title": "welcome",
"name_seo": "testovaya-kategoriya",
"seo_last_title": "dobro-pozhalovat",
"seo_last_name": "<%ADMIN_NAME%>",
"last_x_topic_ids": null,
"forums_bitoptions": 0,
@@ -685,7 +685,7 @@
"position": 1,
"password": null,
"password_override": "",
"last_title": "Welcome!",
"last_title": "Добро пожаловать!",
"last_id": 1,
"sort_key": "last_post",
"show_rules": 0,
@@ -705,8 +705,8 @@
"min_posts_post": 0,
"min_posts_view": 0,
"can_view_others": 1,
"name_seo": "a-test-forum",
"seo_last_title": "welcome",
"name_seo": "testovyj-forum",
"seo_last_title": "dobro-pozhalovat",
"seo_last_name": "<%ADMIN_NAME%>",
"last_x_topic_ids": null,
"forums_bitoptions": 0,
@@ -788,10 +788,10 @@
"comment": "",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "starter_id",
"type": "MEDIUMINT",
"unsigned": false,
"type": "BIGINT",
"unsigned": true,
"values": [],
"zerofill": false
},
@@ -816,26 +816,26 @@
"comment": "",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "last_poster_id",
"type": "MEDIUMINT",
"unsigned": false,
"type": "BIGINT",
"unsigned": true,
"values": [],
"zerofill": false
},
"last_post": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 10,
"name": "last_post",
"type": "INT",
"unsigned": false,
"length": 10,
"decimals": null,
"values": [],
"zerofill": false
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
},
"starter_name": {
"allow_null": true,
@@ -1356,14 +1356,27 @@
null,
null
]
},
"last_true_post": {
"type": "key",
"name": "last_true_post",
"columns": [
"forum_id",
"pinned",
"last_post"
],
"length": [
null,
null,
null
]
}
},
"collation": "utf8mb4_unicode_ci",
"engine": "InnoDB",
"inserts": [
{
"tid": "1",
"title": "Welcome!",
"title": "Добро пожаловать!",
"state": "open",
"posts": "1",
"starter_id": "1",
@@ -1386,7 +1399,7 @@
"topic_close_time": "0",
"topic_rating_total": "0",
"topic_rating_hits": "0",
"title_seo": "welcome",
"title_seo": "dobro-pozhalovat",
"moved_on": "0",
"topic_archive_status": "0",
"last_real_post": "<%TIME%>",
@@ -1449,10 +1462,10 @@
"comment": "",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "author_id",
"type": "MEDIUMINT",
"unsigned": false,
"type": "BIGINT",
"unsigned": true,
"values": [],
"zerofill": false
},
@@ -1698,9 +1711,11 @@
"columns": [
"topic_id",
"queued",
"post_date"
"post_date",
"author_id"
],
"length": [
null,
null,
null,
null
@@ -1776,7 +1791,6 @@
}
},
"collation": "utf8mb4_unicode_ci",
"engine": "InnoDB",
"inserts": [
{
"pid": "1",
@@ -1786,7 +1800,7 @@
"author_name": "<%ADMIN_NAME%>",
"ip_address": "<%IP_ADDRESS%>",
"post_date": "<%TIME%>",
"post": "<p>Welcome to your new IPS Community Suite!<\/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='http:\/\/remoteservices.invisionpower.com\/docs\/getting-started' rel='external'>Go to the documentation now...<\/a>",
"post": "<p>Добро пожаловать на Ваш новый Invision Power Board!<\/p> <br \/><p> Поздравляем Вас с приобретением нашего программного обеспечения и установкой Вашего сообщества. Пожалуйста, потратьте немного времени и прочтите Руководство по началу работы и Документацию администратора.<\/p> <br \/><p> Вы можете удалить это сообщение, тему, форум и категорию в любой момент.<\/p> <br \/><p><a href='http:\/\/license.invisionpower.com\/4\/getting-started?v=40000' rel='external'>Перейти к документации...<\/a><br \/><a href='http:\/\/ipbmafia.ru\/' rel='external'>Русскоязычная поддержка!<\/a><br \/><p>Nulled by IPBMafia.ru<\/p>",
"queued": "0",
"topic_id": "1",
"new_topic": "1",
@@ -1840,9 +1854,9 @@
"comment": "The member giving the rating",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "member",
"type": "MEDIUMINT",
"type": "BIGINT",
"unsigned": true,
"values": [],
"zerofill": false
@@ -1982,8 +1996,8 @@
},
"member": {
"name": "member",
"type": "MEDIUMINT",
"length": 8,
"type": "BIGINT",
"length": 20,
"decimals": null,
"values": [],
"allow_null": true,
@@ -2543,6 +2557,38 @@
"archive_content_date",
"archive_topic_id"
]
},
"archive_forum_id": {
"type": "key",
"name": "archive_forum_id",
"columns": [
"archive_forum_id"
],
"length": [
null
]
},
"archive_ip_address": {
"type": "key",
"name": "archive_ip_address",
"columns": [
"archive_ip_address"
],
"length": [
null
]
},
"archive_queued": {
"type": "key",
"name": "archive_queued",
"columns": [
"archive_queued",
"archive_content_date"
],
"length": [
null,
null
]
}
}
},
@@ -2825,10 +2871,10 @@
"comment": "",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "rss_import_mid",
"type": "MEDIUMINT",
"unsigned": false,
"type": "BIGINT",
"unsigned": true,
"values": [],
"zerofill": false
},
+4
View File
@@ -54,5 +54,9 @@
{
"key": "forums_rss",
"default": "1"
},
{
"key": "forums_topics_per_page",
"default": "25"
}
]
+1 -1
View File
@@ -1 +1 @@
{"archive":"P0Y0M0DT0H5M0S","rssimport":"P0Y0M0DT0H30M0S"}
{"archive":"P0Y0M0DT0H5M0S","rssimport":"P0Y0M0DT0H15M0S","unarchive":"P0Y0M0DT0H5M0S"}
+305 -216
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<theme name="Default" author_name="Invision Power Services, Inc" author_url="http://www.invisionpower.com">
<field sc_key="forum_layout" sc_type="Select" sc_multiple="0" sc_updated="1435569147" sc_app="forums" sc_default="traditional" sc_tab_key="custom" sc_show_in_vse="1" sc_title="themesetting_forum_layout" sc_order="5">[{&quot;key&quot;:&quot;grid&quot;,&quot;value&quot;:&quot;Grid View&quot;},{&quot;key&quot;:&quot;traditional&quot;,&quot;value&quot;:&quot;Traditional List&quot;}]</field>
<field sc_key="forum_layout" sc_type="Select" sc_multiple="0" sc_updated="1481280193" sc_app="forums" sc_default="traditional" sc_tab_key="custom" sc_show_in_vse="1" sc_title="themesetting_forum_layout" sc_order="5" sc_condition="">[{&quot;key&quot;:&quot;grid&quot;,&quot;value&quot;:&quot;Grid View&quot;},{&quot;key&quot;:&quot;traditional&quot;,&quot;value&quot;:&quot;Traditional List&quot;}]</field>
<template template_group="feeds" template_name="importPreview" template_data="$feed" template_location="admin" template_app="forums"><![CDATA[<form method="post">
<input type="hidden" name="continue" value="1">
<ol class='ipsDataList ipsClear'>
@@ -86,13 +86,10 @@
{{endif}}
{{endif}}
<div data-controller='forums.front.forum.forumPage'>
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_hidePhone">
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both">
{template="forumButtons" group="forums" params="$forum"}
</ul>
{$table|raw}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_showPhone ipsResponsive_block">
{template="forumButtons" group="forums" params="$forum"}
</ul>
</div>
{{if !\IPS\Request::i()->advancedSearchForm && $forum->sub_can_post and !$forum->password}}
<div class='ipsResponsive_showPhone ipsResponsive_block ipsSpacer ipsSpacer_both'>
@@ -241,7 +238,7 @@
<ul class="ipsMenu ipsMenu_auto ipsMenu_withStem ipsMenu_selectable ipsHide" id="elSortByMenu_{$table->uniqueId}_menu">
{{$custom = TRUE;}}
{{foreach $table->sortOptions as $k => $col}}
<li class="ipsMenu_item {{if $col === $table->sortBy}}{{$custom = FALSE;}}ipsMenu_itemChecked{{endif}}" data-ipsMenuValue="{$col}" data-sortDirection='{{if $col == 'title'}}asc{{else}}desc{{endif}}'><a href="{$table->baseUrl->setQueryString( array( 'filter' => $table->filter, 'sortby' => $col, 'sortdirection' => ( $col == 'title' ) ? 'asc' : 'desc', 'page' => '1' ) )}">{lang="{$table->langPrefix}sort_{$k}"}</a></li>
<li class="ipsMenu_item {{if $col === $table->getSortByColumn()}}{{$custom = FALSE;}}ipsMenu_itemChecked{{endif}}" data-ipsMenuValue="{$col}" data-sortDirection='{{if $col == 'title'}}asc{{else}}desc{{endif}}'><a href="{$table->baseUrl->setQueryString( array( 'filter' => $table->filter, 'sortby' => $col, 'sortdirection' => ( $col == 'title' ) ? 'asc' : 'desc', 'page' => '1' ) )}">{lang="{$table->langPrefix}sort_{$k}"}</a></li>
{{endforeach}}
{{if $table->advancedSearch}}
<li class="ipsMenu_item {{if $custom}}ipsMenu_itemChecked{{endif}}" data-noSelect="true">
@@ -276,7 +273,7 @@
</div>
{{endif}}
{{if $table->canModerate()}}
<form action="{$table->baseUrl}" method="post" data-role='moderationTools' data-ipsPageAction>
<form action="{$table->baseUrl->csrf()}" method="post" data-role='moderationTools' data-ipsPageAction>
{{endif}}
{{if count( $rows )}}
<ol class='ipsDataList ipsDataList_zebra ipsClear cForumTopicTable {{if $table->container()->forums_bitoptions['bw_enable_answers']}}cForumQuestions{{endif}} {{foreach $table->classes as $class}}{$class} {{endforeach}}' id='elTable_{$table->uniqueId}' data-role="tableRows" itemscope itemtype="http://schema.org/ItemList">
@@ -390,41 +387,42 @@
{{endif}}
</div>
<div class='ipsDataItem_main'>
{{if $question->mapped('pinned') || $question->mapped('featured') || $question->hidden() === -1 || $question->hidden() === 1}}
<span class='ipsPos_right'>
{{if $question->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$question->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $question->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $question->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $question->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{endif}}
<h4 class='ipsDataItem_title ipsType_break'>
{{if $question->locked()}}
<i class='fa fa-lock' data-ipsTooltip title='{lang="topic_locked"}'></i>
{{endif}}
{{if $question->unread()}}
<a href='{$question->url( 'getNewComment' )}' title='{lang="first_unread_post"}' data-ipsTooltip>
<span class='ipsItemStatus'><i class="fa {{if in_array( $question->tid, $iposted )}}fa-star{{else}}fa-circle{{endif}}"></i></span>
</a>
{{else}}
{{if in_array( $question->tid, $iposted )}}
<span class='ipsItemStatus ipsItemStatus_read ipsItemStatus_posted'><i class="fa fa-star"></i></span>
<div class='ipsType_break ipsContained'>
{{if $question->locked()}}
<i class='fa fa-lock' data-ipsTooltip title='{lang="topic_locked"}'></i>
{{endif}}
{{endif}}
{{if $question->prefix()}}
{template="prefix" group="global" app="core" params="$question->prefix( TRUE ), $question->prefix()"}
{{endif}}
<a href='{$question->url()}'>
{{if $question->mapped('title')}}{wordbreak="$question->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
{{if $question->unread()}}
<a href='{$question->url( 'getNewComment' )}' title='{lang="first_unread_post"}' data-ipsTooltip>
<span class='ipsItemStatus'><i class="fa {{if in_array( $question->tid, $iposted )}}fa-star{{else}}fa-circle{{endif}}"></i></span>
</a>
{{else}}
{{if in_array( $question->tid, $iposted )}}
<span class='ipsItemStatus ipsItemStatus_read ipsItemStatus_posted'><i class="fa fa-star"></i></span>
{{endif}}
{{endif}}
{{if $question->mapped('pinned') || $question->mapped('featured') || $question->hidden() === -1 || $question->hidden() === 1}}
<span>
{{if $question->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$question->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $question->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $question->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $question->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{endif}}
{{if $question->prefix()}}
{template="prefix" group="global" app="core" params="$question->prefix( TRUE ), $question->prefix()"}
{{endif}}
<a href='{$question->url()}'>
{{if $question->mapped('title')}}{$question->mapped('title')}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
</div>
</h4>
<div class='ipsDataItem_meta'>
<p class='ipsType_reset ipsType_normal ipsType_light'>
@@ -549,10 +547,21 @@
</div>
<div class='ipsDataItem_main'>
<h4 class='ipsDataItem_title ipsType_break'>
<em><a href='{$movedTo->url()}' title='{lang="go_to_new_location"}'>{wordbreak="$row->mapped('title')"}</a></em>
<div class='ipsType_break ipsContained'>
<em><a href='{$movedTo->url()}' title='{lang="go_to_new_location"}'>{$row->mapped('title')}</a></em>
</div>
</h4>
<div class='ipsDataItem_meta'>
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="question_moved_to" sprintf="$movedTo->container()->url(), $movedTo->container()->_title"}</p>
{{if isset( $row::$databaseColumnMap['status'] )}}
{{$statusField = $row::$databaseColumnMap['status'];}}
{{if $row->$statusField == 'merged'}}
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="question_merged_to" sprintf="$movedTo->url(), $movedTo->mapped('title')"}</p>
{{else}}
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="question_moved_to" sprintf="$movedTo->container()->url(), $movedTo->container()->_title"}</p>
{{endif}}
{{else}}
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="question_moved_to" sprintf="$movedTo->container()->url(), $movedTo->container()->_title"}</p>
{{endif}}
</div>
</div>
{{if $table->canModerate()}}
@@ -579,44 +588,49 @@
{{endif}}
</div>
<div class='ipsDataItem_main'>
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span class='ipsPos_right'>
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
<h4 class='ipsDataItem_title ipsContained_container'>
<div class='ipsType_break ipsContained'>
{{if $row->locked()}}
<span><i class='fa fa-lock' data-ipsTooltip title='{lang="topic_locked"}'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{if $row->unread()}}
<span>
<a href='{$row->url( 'getNewComment' )}' title='{lang="first_unread_post"}' data-ipsTooltip>
<span class='ipsItemStatus'><i class="fa {{if in_array( $row->$idField, $iposted )}}fa-star{{else}}fa-circle{{endif}}"></i></span>
</a>
</span>
{{else}}
{{if in_array( $row->$idField, $iposted )}}
<span><span class='ipsItemStatus ipsItemStatus_read ipsItemStatus_posted'><i class="fa fa-star"></i></span></span>
{{endif}}
{{endif}}
</span>
{{endif}}
<h4 class='ipsDataItem_title ipsType_break'>
{{if $row->locked()}}
<i class='fa fa-lock' data-ipsTooltip title='{lang="topic_locked"}'></i>
{{endif}}
{{if $row->unread()}}
<a href='{$row->url( 'getNewComment' )}' title='{lang="first_unread_post"}' data-ipsTooltip>
<span class='ipsItemStatus'><i class="fa {{if in_array( $row->$idField, $iposted )}}fa-star{{else}}fa-circle{{endif}}"></i></span>
</a>
{{else}}
{{if in_array( $row->$idField, $iposted )}}
<span class='ipsItemStatus ipsItemStatus_read ipsItemStatus_posted'><i class="fa fa-star"></i></span>
{{endif}}
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}' {{if $row->tableHoverUrl and $row->canView()}}data-ipsHover data-ipsHover-target='{$row->url()->setQueryString('preview', 1)}' data-ipsHover-timeout='1.5'{{endif}} itemprop="url" {{if $row->canEdit()}} data-role="editableTitle"{{endif}}>
<span itemprop="name">
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span>
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
</a>
{{endif}}
{{if $row->prefix()}}
<span>{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}</span>
{{endif}}
<a href='{$row->url()}' title='{{if $row->mapped('title')}}{$row->mapped('title')}{{else}}{lang="content_deleted"}{{endif}} {{if $row->canEdit()}}{lang="click_hold_edit"}{{endif}}' {{if $row->tableHoverUrl and $row->canView()}}data-ipsHover data-ipsHover-target='{$row->url()->setQueryString('preview', 1)}' data-ipsHover-timeout='1.5'{{endif}} itemprop="url" {{if $row->canEdit()}} data-role="editableTitle"{{endif}}>
<span itemprop="name">
{{if $row->mapped('title')}}{$row->mapped('title')}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</span>
</a>
</div>
</h4>
<div class='ipsDataItem_meta'>
<p class='ipsDataItem_meta ipsType_reset ipsType_light ipsType_blendLinks'>
@@ -641,7 +655,12 @@
{{foreach $row->stats(FALSE) AS $k => $v}}
{{if $k == 'forums_comments' OR $k == 'answers_no_number'}}
<span itemprop="answerCount">{number="$v"}</span>
<span class='ipsType_light'>{lang="answers_no_number" pluralize="$v"}</span>
<span class='ipsType_light'>
{lang="answers_no_number" pluralize="$v"}
{{if \IPS\forums\Topic::modPermission( 'unhide', NULL, $row->container() ) AND $unapprovedComments = $row->mapped('unapproved_comments')}}
&nbsp;<a href='{$row->url()->setQueryString( 'queued_posts', 1 )}' class='ipsType_warning ipsType_small ipsResponsive_noFloat' data-ipsTooltip title='{lang="queued_posts_badge" pluralize="$row->topic_queuedposts"}'><i class='fa fa-warning'></i> <strong>{$unapprovedComments}</strong></a>
{{endif}}
</span>
{{endif}}
{{endforeach}}
</div>
@@ -722,17 +741,28 @@
{{$rowCount++;}}
{{$idField = $row::$databaseColumnId;}}
{{if $row->mapped('moved_to')}}
{{if $movedTo = $row->movedTo()}}
{{if $movedTo = $row->movedTo() AND $movedTo->container()->can('view')}}
<li class="ipsDataItem">
<div class='ipsDataItem_icon ipsType_center ipsType_noBreak'>
<i class="fa fa-arrow-left ipsType_large"></i>
</div>
<div class='ipsDataItem_main'>
<h4 class='ipsDataItem_title ipsType_break'>
<em><a href='{$movedTo->url()}' title='{lang="go_to_new_location"}'>{wordbreak="$row->mapped('title')"}</a></em>
<h4 class='ipsDataItem_title ipsContained_container'>
<div class='ipsType_break ipsContained'>
<em><a href='{$movedTo->url()}' title='{lang="go_to_new_location"}'>{$row->mapped('title')}</a></em>
</div>
</h4>
<div class='ipsDataItem_meta'>
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="topic_moved_to" sprintf="$movedTo->container()->url(), $movedTo->container()->_title"}</p>
{{if isset( $row::$databaseColumnMap['status'] )}}
{{$statusField = $row::$databaseColumnMap['status'];}}
{{if $row->$statusField == 'merged'}}
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="topic_merged_to" sprintf="$movedTo->url(), $movedTo->mapped('title')"}</p>
{{else}}
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="topic_moved_to" sprintf="$movedTo->container()->url(), $movedTo->container()->_title"}</p>
{{endif}}
{{else}}
<p class='ipsType_reset ipsType_light ipsType_blendLinks'>{lang="topic_moved_to" sprintf="$movedTo->container()->url(), $movedTo->container()->_title"}</p>
{{endif}}
</div>
</div>
{{if $table->canModerate()}}
@@ -763,41 +793,49 @@
</div>
{{endif}}
<div class='ipsDataItem_main'>
<h4 class='ipsDataItem_title ipsType_break'>
<h4 class='ipsDataItem_title ipsContained_container'>
{{if $row->locked()}}
<i class='fa fa-lock' data-ipsTooltip title='{lang="topic_locked"}'></i>
<span>
<i class='ipsType_medium fa fa-lock' data-ipsTooltip title='{lang="topic_locked"}'></i>
</span>
{{if $row->topic_open_time && $row->topic_open_time > time()}}
<span><strong class='ipsType_small ipsType_noBreak' data-ipsTooltip title='{lang="topic_unlocks_at" sprintf="\IPS\DateTime::ts( $row->topic_open_time )->relative(), \IPS\DateTime::ts( $row->topic_open_time )->localeTime( FALSE )"}'>{lang="topic_unlocks_at_short" sprintf="\IPS\DateTime::ts($row->topic_open_time)->relative(1)"}</strong>&nbsp;&nbsp;</span>
{{endif}}
{{elseif !$row->locked() && $row->topic_close_time && $row->topic_close_time > time()}}
<span><strong class='ipsType_small ipsType_noBreak' data-ipsTooltip title='{lang="topic_locks_at" sprintf="\IPS\DateTime::ts( $row->topic_close_time )->relative(), \IPS\DateTime::ts( $row->topic_close_time )->localeTime( FALSE )"}'><i class='fa fa-clock-o'></i> {lang="topic_locks_at_short" sprintf="\IPS\DateTime::ts($row->topic_close_time)->relative(1)"}</strong>&nbsp;&nbsp;</span>
{{endif}}
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span>
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{if $row->hidden() === -1}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span></span>
{{elseif $row->hidden() === 1}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span></span>
{{endif}}
{{if $row->mapped('featured')}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span></span>
{{endif}}
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<span>{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}</span>
{{endif}}
<a href='{$row->url()}' itemprop="url"{{if $row->tableHoverUrl and $row->canView()}} data-ipsHover data-ipsHover-target='{$row->url()->setQueryString('preview', 1)}' data-ipsHover-timeout='1.5'{{endif}}{{if $row->canEdit()}} data-role="editableTitle"{{endif}}>
<span itemprop="name headline">
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</span>
</a>
<div class='ipsType_break ipsContained'>
<a href='{$row->url()}' class='' title='{{if $row->mapped('title')}}{$row->mapped('title')}{{else}}{lang="content_deleted"}{{endif}} {{if $row->canEdit()}}{lang="click_hold_edit"}{{endif}}' itemprop="url"{{if $row->tableHoverUrl and $row->canView()}} data-ipsHover data-ipsHover-target='{$row->url()->setQueryString('preview', 1)}' data-ipsHover-timeout='1.5'{{endif}}{{if $row->canEdit()}} data-role="editableTitle"{{endif}}>
<span itemprop="name headline">
{{if $row->mapped('title') or $row->mapped('title') == 0}}{$row->mapped('title')}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</span>
</a>
{{if $row->commentPageCount() > 1}}
{$row->commentPagination( array(), 'miniPagination' )|raw}
{{endif}}
</div>
<meta itemprop="position" content="{$row->tid}">
</h4>
{{if $row->commentPageCount() > 1}}
{$row->commentPagination( array(), 'miniPagination' )|raw}
{{endif}}
<div class='ipsDataItem_meta ipsType_reset ipsType_light ipsType_blendLinks'>
<span itemprop="author" itemscope itemtype="http://schema.org/Person">
{lang="byline_itemprop" htmlsprintf="$row->author()->link()"}
@@ -808,7 +846,7 @@
{{endif}}
{{if count( $row->tags() )}}
&nbsp;&nbsp;
{template="tags" group="global" app="core" params="$row->tags(), true, true"}
{template="tags" group="global" app="core" params="$row->tags(), true"}
{{endif}}
</div>
</div>
@@ -859,17 +897,21 @@
<template template_group="global" template_name="commentTableHeader" template_data="$comment, $topic" template_location="front" template_app="forums"><![CDATA[{{$iposted = $topic->container()->contentPostedIn();}}
{{$idField = $topic::$databaseColumnId;}}
<div>
<h3 class='ipsType_sectionHead ipsType_break'>
<h3 class='ipsType_sectionHead ipsContained_container'>
{{if $topic->unread()}}
<a href='{$topic->url( 'getNewComment' )}' title='{lang="first_unread_post"}' data-ipsTooltip>
<span class='ipsItemStatus'><i class="fa {{if in_array( $topic->$idField, $iposted )}}fa-star{{else}}fa-circle{{endif}}"></i></span>
</a>
<span>
<a href='{$topic->url( 'getNewComment' )}' title='{lang="first_unread_post"}' data-ipsTooltip>
<span class='ipsItemStatus'><i class="fa {{if in_array( $topic->$idField, $iposted )}}fa-star{{else}}fa-circle{{endif}}"></i></span>
</a>
</span>
{{else}}
{{if in_array( $topic->$idField, $iposted )}}
<span class='ipsItemStatus ipsItemStatus_read ipsItemStatus_posted'><i class="fa fa-star"></i></span>
<span><span class='ipsItemStatus ipsItemStatus_read ipsItemStatus_posted'><i class="fa fa-star"></i></span></span>
{{endif}}
{{endif}}
<a href='{$comment->url()}' title='{lang="view_this_topic" sprintf="$topic->title"}'>{wordbreak="$topic->title"}</a>
<div class='ipsType_break ipsContained'>
<a href='{$comment->url()}' title='{lang="view_this_topic" sprintf="$topic->title"}' class='ipsTruncate ipsTruncate_line'>{$topic->title}</a>
</div>
{{if $topic->container()->allow_rating}}
{template="rating" group="global" location="front" app="core" params="'large', $topic->rating_hits ? ( $topic->rating_total / $topic->rating_hits ) : 0"}
{{endif}}
@@ -890,7 +932,8 @@
</a>
</h4>
<ul class='ipsList_inline ipsType_light'>
<li>{lang="posts_number" pluralize="$row->_comments + $row->_items"}</li>
{{$count = \IPS\forums\Topic::contentCount( $row, TRUE );}}
<li>{lang="posts_number" pluralize="$count"}</li>
</ul>
</div>
@@ -946,33 +989,35 @@
{{endif}}
{{endif}}
<div class='ipsDataItem_main'>
<h4 class='ipsDataItem_title ipsType_break'>
<h4 class='ipsDataItem_title ipsContained_container'>
{{if $topic->mapped('pinned') || $topic->mapped('featured') || $topic->hidden() === -1 || $topic->hidden() === 1}}
<span>
{{if $topic->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $topic->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $topic->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $topic->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{if $topic->hidden() === -1}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span></span>
{{elseif $topic->hidden() === 1}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span></span>
{{endif}}
{{if $topic->mapped('pinned')}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span></span>
{{endif}}
{{if $topic->mapped('featured')}}
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span></span>
{{endif}}
{{endif}}
<a href='{$topic->url()}' {{if $topic->canView()}}data-ipsHover data-ipsHover-target='{$topic->url()->setQueryString('preview', 1)}' data-ipsHover-timeout='1.5' {{endif}}>
{{if $topic->isQuestion()}}
<strong class='ipsType_light'>{lang="question_title"}:</strong>
<div class='ipsType_break ipsContained'>
<a href='{$topic->url()}' {{if $topic->canView()}}data-ipsHover data-ipsHover-target='{$topic->url()->setQueryString('preview', 1)}' data-ipsHover-timeout='1.5' {{endif}}>
{{if $topic->isQuestion()}}
<strong class='ipsType_light'>{lang="question_title"}:</strong>
{{endif}}
{$topic->mapped('title')}
</a>
{{if $topic->commentPageCount() > 1}}
{$topic->commentPagination( array(), 'miniPagination' )|raw}
{{endif}}
{wordbreak="$topic->mapped('title')"}
</a>
</div>
</h4>
{{if $topic->commentPageCount() > 1}}
{$topic->commentPagination( array(), 'miniPagination' )|raw}
{{endif}}
<p class='ipsType_reset ipsType_medium ipsType_light'>
{lang="byline" htmlsprintf="$topic->author()->link()"} {datetime="$topic->mapped('date')"}
{{if \IPS\Request::i()->controller != 'forums'}}
@@ -1173,7 +1218,7 @@
{{endif}}]]></template>
<template template_group="index" template_name="forumRow" template_data="$forum, $isSubForum=FALSE, $table=NULL" template_location="front" template_app="forums"><![CDATA[{{if $forum->can('view')}}
{{$lastPost = $forum->lastPost();}}
<li class="ipsDataItem ipsDataItem_responsivePhoto {{if \IPS\forums\Topic::containerUnread( $forum ) && !$forum->redirect_on}}ipsDataItem_unread{{endif}} ipsClearfix" data-forumID="{$forum->_id}">
<li class="cForumRow ipsDataItem ipsDataItem_responsivePhoto {{if \IPS\forums\Topic::containerUnread( $forum ) && !$forum->redirect_on}}ipsDataItem_unread{{endif}} ipsClearfix" data-forumID="{$forum->_id}">
<div class="ipsDataItem_icon ipsDataItem_category">
{{if !$forum->redirect_on}}
{{if \IPS\forums\Topic::containerUnread( $forum ) AND \IPS\Member::loggedIn()->member_id}}<a href="{{if $isSubForum}}{$forum->url()->setQueryString( array( 'do' => 'markRead', 'return' => $forum->parent_id ) )->csrf()}{{else}}{$forum->url()->setQueryString( 'do', 'markRead' )->csrf()}{{endif}}" data-action='markAsRead' title='{lang="mark_forum_read"}' data-ipsTooltip>{{endif}}
@@ -1228,7 +1273,7 @@
</ul>
{{endif}}
{{if $forum->description}}
<div class="ipsDataItem_meta ipsType_richText">{$forum->description|raw}</div>
<div class="ipsDataItem_meta ipsType_richText ipsContained">{$forum->description|raw}</div>
{{endif}}
</div>
{{if !$forum->redirect_on}}
@@ -1260,9 +1305,13 @@
<ul class="ipsDataItem_lastPoster ipsDataItem_withPhoto">
{{if $lastPost}}
<li>{template="userPhoto" app="core" group="global" params="$lastPost['author'], 'tiny'"}</li>
<li><a href="{$lastPost['topic_url']->setQueryString( 'do', 'getNewComment' )}" class='ipsType_break ipsContained' title='{$lastPost['topic_title']}'>{truncate="$lastPost['topic_title']" length="26"}</a></li>
{{if $lastPost['topic_title']}}<li><a href="{$lastPost['topic_url']->setQueryString( 'do', 'getNewComment' )}" title='{$lastPost['topic_title']}'>{truncate="$lastPost['topic_title']" length="26"}</a></li>{{endif}}
<li class='ipsType_blendLinks'>{lang="byline_nodate" htmlsprintf="$lastPost['author']->link()"}</li>
<li class="ipsType_light"><a href='{$lastPost['topic_url']->setQueryString( 'do', 'getLastComment' )}' title='{lang="get_last_post"}' class='ipsType_blendLinks'>{datetime="$lastPost['date']"}</a></li>
{{if $lastPost['topic_title']}}
<li class="ipsType_light"><a href='{$lastPost['topic_url']->setQueryString( 'do', 'getLastComment' )}' title='{lang="get_last_post"}' class='ipsType_blendLinks'>{datetime="$lastPost['date']"}</a></li>
{{else}}
<li class="ipsType_light">{datetime="$lastPost['date']"}</li>
{{endif}}
{{else}}
<li class='ipsType_light ipsResponsive_showDesktop'>{{if $forum->password}}{lang="no_forum_posts_password"}{{else}}{lang="no_forum_posts"}{{endif}}</li>
{{endif}}
@@ -1456,7 +1505,11 @@
<div class='ipsAreaBackground ipsPad ipsType_center'>
<a href="{{if !is_null($topic)}}{$topic->url()}{{else}}{$forum->url()}{{endif}}" class="ipsButton ipsButton_link ipsButton ipsButton_link">{lang="cancel"}</a>
<button type='submit' class='ipsButton ipsButton_medium ipsButton_primary' accesskey="s" role="button">{{if $forum->forums_bitoptions['bw_enable_answers']}}{lang="submit_question"}{{else}}{lang="submit_topic"}{{endif}}</button>
{{if $topic}}
<button type='submit' class='ipsButton ipsButton_medium ipsButton_primary' tabindex="1" accesskey="s" role="button">{{if $forum->forums_bitoptions['bw_enable_answers']}}{lang="submit_question_edit"}{{else}}{lang="submit_topic_edit"}{{endif}}</button>
{{else}}
<button type='submit' class='ipsButton ipsButton_medium ipsButton_primary' tabindex="1" accesskey="s" role="button">{{if $forum->forums_bitoptions['bw_enable_answers']}}{lang="submit_question"}{{else}}{lang="submit_topic"}{{endif}}</button>
{{endif}}
</div>
</div>
</form>]]></template>
@@ -1473,11 +1526,11 @@
<ul class='ipsFieldRow_content ipsList_reset cCreateTopic_date'>
<li>
<i class='fa fa-calendar'></i>
<input type="date" name="{$input->name}" class="ipsField_short" data-control="date" placeholder='{expression="mb_strtoupper( str_replace( 'y', 'yy', \IPS\Member::loggedIn()->language()->preferredDateFormat() ) )"}' value="{{if $input->value instanceof \IPS\DateTime}}{$input->value->format('Y-m-d')}{{else}}{$input->value}{{endif}}" data-preferredFormat="{{if $input->value instanceof \IPS\DateTime}}{$input->value->localeDate()}{{else}}{$input->value}{{endif}}">
<input type="date" name="{$input->name}" class="ipsField_short" data-control="date" placeholder='{expression="str_replace( array( 'YYYY', 'MM', 'DD' ), array( \IPS\Member::loggedIn()->language()->addToStack('_date_format_yyyy'), \IPS\Member::loggedIn()->language()->addToStack('_date_format_mm'), \IPS\Member::loggedIn()->language()->addToStack('_date_format_dd') ), str_replace( 'Y', 'YY', \IPS\Member::loggedIn()->language()->preferredDateFormat() ) )"}' value="{{if $input->value instanceof \IPS\DateTime}}{$input->value->format('Y-m-d')}{{else}}{$input->value}{{endif}}" data-preferredFormat="{{if $input->value instanceof \IPS\DateTime}}{$input->value->localeDate()}{{else}}{$input->value}{{endif}}">
</li>
<li>
<i class='fa fa-clock-o'></i>
<input name="{$input->name}_time" type="time" size="12" class="ipsField_short" placeholder="HH:MM" step="60" min="00:00" value="{{if $input->value instanceof \IPS\DateTime}}{$input->value->format('H:i')}{{endif}}">
<input name="{$input->name}_time" type="time" size="12" class="ipsField_short" placeholder="{lang="_time_format_hhmm"}" step="60" min="00:00" value="{{if $input->value instanceof \IPS\DateTime}}{$input->value->format('H:i')}{{endif}}">
</li>
</ul>
</li>
@@ -1491,7 +1544,7 @@
</div>]]></template>
<template template_group="topics" template_name="post" template_data="$item, $comment, $editorName, $app, $type, $class=''" template_location="front" template_app="forums"><![CDATA[{{$idField = $comment::$databaseColumnId;}}
<div id='comment-{$comment->$idField}_wrap' data-controller='core.front.core.comment' data-commentApp='{$app}' data-commentType='{$type}' data-commentID="{$comment->$idField}" data-quoteData='{expression="json_encode( array('userid' => $comment->author()->member_id, 'username' => $comment->author()->name, 'timestamp' => $comment->mapped('date'), 'contentapp' => $comment::$application, 'contenttype' => $type, 'contentid' => $item->tid, 'contentclass' => $class, 'contentcommentid' => $comment->$idField) )"}' class='ipsComment_content ipsType_medium {{if $comment->hidden()}}ipsModerated{{endif}} ipsFaded_withHover'>
{{if settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight}}
{{if settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight and settings.reputation_enabled}}
<strong class='ipsComment_popularFlag' data-ipsTooltip title='{lang="this_is_a_popular_post"}'><i class='fa fa-heart'></i></strong>
{{endif}}
@@ -1500,7 +1553,11 @@
{{if \IPS\Member::loggedIn()->modPermission('can_use_ip_tools') and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'modcp' ) )}}
<span class='ipsResponsive_hidePhone'>(<a href="{url="app=core&module=modcp&controller=modcp&tab=ip_tools&ip=$comment->ip_address" seoTemplate="modcp_ip_tools"}">{lang="ip_prefix" sprintf="$comment->ip_address"}</a>) &middot;</span>
{{endif}}
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->$idField ) )}' data-ipsTooltip title='{lang="share_this_post"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elSharePost_{$comment->$idField}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
{{if $comment->mapped('first') }}
<a href='{$comment->item()->url()}' data-ipsTooltip title='{lang="share_this_post"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elSharePost_{$comment->$idField}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
{{else}}
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->$idField ) )}' data-ipsTooltip title='{lang="share_this_post"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elSharePost_{$comment->$idField}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
{{endif}}
{{if count( $item->commentMultimodActions() ) and !$comment->mapped('first')}}
&middot;
<span class='ipsCustomInput'>
@@ -1511,7 +1568,7 @@
</p>
<p class='ipsType_reset'>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->$idField ) )}' class='ipsType_blendLinks' title='{lang="share_this_comment"}'>{$comment->dateLine()|raw}</a>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->$idField ) )}' class='ipsType_blendLinks'>{$comment->dateLine()|raw}</a>
{{if $comment->editLine()}}
({lang="edited_lc"})
{{endif}}
@@ -1550,9 +1607,9 @@
<li><a href='{$comment->url('unhide')->csrf()}' class='ipsButton ipsButton_verySmall ipsButton_positive' data-action='approveComment'><i class='fa fa-check'></i> {lang="approve"}</a></li>
{{endif}}
{{if $comment->canDelete()}}
<li><a href='{$comment->url('delete')->csrf()}' data-action='deleteComment' data-updateOnDelete="#commentCount" class='ipsButton ipsButton_verySmall ipsButton_negative'><i class='fa fa-times'></i> {lang="delete"}</a></li>
<li><a href='{$comment->url('delete')->csrf()->setQueryString('page',\IPS\Request::i()->page)}' data-action='deleteComment' data-updateOnDelete="#commentCount" class='ipsButton ipsButton_verySmall ipsButton_negative'><i class='fa fa-times'></i> {lang="delete"}</a></li>
{{endif}}
{{if $comment->canEdit() || $comment->canSplit()}}
{{if $comment->canEdit() || $comment->canSplit() || $comment->canHide()}}
<li>
<a href='#elControls_{$comment->$idField}_menu' id='elControls_{$comment->$idField}' data-ipsMenu data-ipsMenu-appendTo='#comment-{$comment->$idField}_wrap'>{lang="options"} &nbsp;<i class='fa fa-caret-down'></i></a>
<ul id='elControls_{$comment->$idField}_menu' class='ipsMenu ipsMenu_narrow ipsHide'>
@@ -1566,6 +1623,9 @@
{{if $comment->canSplit()}}
<li class='ipsMenu_item'><a href='{$comment->url('split')}' data-action='splitComment' data-ipsDialog data-ipsDialog-title="{lang="split_to_new" sprintf="\IPS\Member::loggedIn()->language()->addToStack( $item::$title )"}">{lang="split"}</a></li>
{{endif}}
{{if $comment instanceof \IPS\Content\Hideable and $comment->canHide()}}
<li class='ipsMenu_item'><a href='{$comment->url('hide')->csrf()}' data-ipsDialog data-ipsDialog-title="{lang="hide"}">{lang="hide"}</a></li>
{{endif}}
</ul>
</li>
{{endif}}
@@ -1600,7 +1660,7 @@
<li class='ipsMenu_item'><a href='{$comment->url('split')}' data-action='splitComment' data-ipsDialog data-ipsDialog-title="{lang="split_to_new" sprintf="\IPS\Member::loggedIn()->language()->addToStack( $item::$title )"}">{lang="split"}</a></li>
{{endif}}
{{if $comment->canDelete()}}
<li class='ipsMenu_item'><a href='{$comment->url('delete')->csrf()}' data-action='deleteComment' data-updateOnDelete="#commentCount">{lang="delete"}</a></li>
<li class='ipsMenu_item'><a href='{$comment->url('delete')->csrf()->setQueryString('page',\IPS\Request::i()->page)}' data-action='deleteComment' data-updateOnDelete="#commentCount">{lang="delete"}</a></li>
{{endif}}
</ul>
</li>
@@ -1615,12 +1675,17 @@
{{endif}}
</div>
<div class='ipsMenu ipsMenu_wide ipsHide cPostShareMenu' id='elSharePost_{$comment->pid}_menu'>
<div class='ipsMenu ipsMenu_wide ipsHide cPostShareMenu' id='elSharePost_{$comment->$idField}_menu'>
<div class='ipsPad'>
<h4 class='ipsType_sectionHead'>{lang="share_this_post"}</h4>
<hr class='ipsHr'>
<h5 class='ipsType_normal ipsType_reset'>{lang="link_to_post"}</h5>
{{if $comment->mapped('first') }}
<input type='text' value='{$comment->item()->url()}' class='ipsField_fullWidth'>
{{else}}
<input type='text' value='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->$idField ) )}' class='ipsField_fullWidth'>
{{endif}}
{{if !$comment->item()->container()->disable_sharelinks and count( $comment->sharelinks() )}}
<h5 class='ipsType_normal ipsType_reset ipsSpacer_top'>{lang="share_externally"}</h5>
{template="sharelinks" group="global" app="core" params="$comment"}
@@ -1637,13 +1702,13 @@
<li class='ipsMenu_item ipsJS_show' data-ipsMenuValue='showPost'><a href='#'>{lang="show_this_post"}</a></li>
<li class='ipsMenu_sep ipsJS_show'><hr></li>
<li class='ipsMenu_item' data-ipsMenuValue='stopIgnoring'><a href='{url="app=core&module=system&controller=ignore&do=remove&id={$comment->author()->member_id}" seoTemplate="ignore"}'>{lang="stop_ignoring_posts_by" sprintf="$comment->author()->name"}</a></li>
<li class='ipsMenu_item'><a href='{url="app=core&module=members&controller=ignore" seoTemplate="ignore"}'>{lang="change_ignore_preferences"}</a></li>
<li class='ipsMenu_item'><a href='{url="app=core&module=system&controller=ignore" seoTemplate="ignore"}'>{lang="change_ignore_preferences"}</a></li>
</ul>
</div>
{{endif}}
<a id='comment-{$comment->$idField}'></a>
<article itemscope {{if $item->isQuestion() && !$comment->new_topic}}itemprop="suggestedAnswer {{if $comment->post_bwoptions['best_answer']}}acceptedAnswer{{endif}}" itemtype="http://schema.org/Answer"{{else}}itemtype="http://schema.org/Comment"{{endif}} id='elComment_{$comment->$idField}' class='cPost ipsBox {{if $otherClasses}}{$otherClasses}{{endif}} ipsComment {{if settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight}}ipsComment_popular{{endif}} ipsComment_parent ipsClearfix ipsClear ipsColumns ipsColumns_noSpacing ipsColumns_collapsePhone {{if $comment->isIgnored()}}ipsHide{{endif}} {{if $comment->hidden()}}ipsModerated{{endif}}'>
<article itemscope {{if $comment->author()->hasHighlightedReplies()}}data-memberGroup="{$comment->author()->member_group_id}" {{endif}}{{if $item->isQuestion() && !$comment->new_topic}}itemprop="suggestedAnswer {{if $comment->post_bwoptions['best_answer']}}acceptedAnswer{{endif}}" itemtype="http://schema.org/Answer"{{else}}itemtype="http://schema.org/Comment"{{endif}} id='elComment_{$comment->$idField}' class='cPost ipsBox {{if $otherClasses}}{$otherClasses}{{endif}} ipsComment {{if settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight and settings.reputation_enabled}}ipsComment_popular{{endif}} ipsComment_parent ipsClearfix ipsClear ipsColumns ipsColumns_noSpacing ipsColumns_collapsePhone {{if $comment->author()->hasHighlightedReplies()}}ipsComment_highlighted{{endif}}{{if $comment->isIgnored()}}ipsHide{{endif}} {{if $comment->hidden()}}ipsModerated{{endif}}'>
{{if $item->isQuestion() and !$comment->new_topic}}
{template="postRating" group="topics" app="forums" params="$item, $comment, $votes"}
{{endif}}
@@ -1651,9 +1716,9 @@
<h3 class='ipsType_sectionHead cAuthorPane_author ipsType_blendLinks ipsType_break' itemprop="creator" itemscope itemtype="http://schema.org/Person"><strong itemprop="name">{$comment->author()->link( $comment->warningRef() )|raw}</strong> <span class='ipsResponsive_showPhone ipsResponsive_inline'>&nbsp;&nbsp;{template="reputationBadge" group="global" app="core" params="$comment->author()"}</span></h3>
<ul class='cAuthorPane_info ipsList_reset'>
{{if $comment->author()->member_title && $comment->author()->member_id}}
<li class='ipsResponsive_hidePhone'>{$comment->author()->member_title}</li>
<li class='ipsResponsive_hidePhone ipsType_break'>{$comment->author()->member_title}</li>
{{elseif $comment->author()->rank['title'] && $comment->author()->member_id}}
<li class='ipsResponsive_hidePhone'>{$comment->author()->rank['title']}</li>
<li class='ipsResponsive_hidePhone ipsType_break'>{$comment->author()->rank['title']}</li>
{{endif}}
{{if $comment->author()->rank['image'] && $comment->author()->member_id}}
<li class='ipsResponsive_hidePhone'>{$comment->author()->rank['image']|raw}</li>
@@ -1792,35 +1857,46 @@
<div class='ipsPhotoPanel ipsPhotoPanel_small ipsPhotoPanel_notPhone ipsClearfix'>
{template="userPhoto" group="global" app="core" params="$topic->author(), 'small', $topic->warningRef()"}
<div>
<h1 class='ipsType_pageTitle'>
<h1 class='ipsType_pageTitle ipsContained_container'>
{{if $topic->mapped('pinned') || $topic->mapped('featured') || $topic->hidden() === -1 || $topic->hidden() === 1}}
{{if $topic->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span></span>
{{elseif $topic->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span></span>
{{endif}}
{{if $topic->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span></span>
{{endif}}
{{if $topic->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span></span>
{{endif}}
{{endif}}
{{if $topic->prefix()}}
{template="prefix" group="global" app="core" params="$topic->prefix( TRUE ), $topic->prefix()"}
{{endif}}
{{if $topic->isQuestion()}}
<span itemprop="name">{wordbreak="$topic->title"}</span>
{{if $topic->prefix() OR ( $topic->canEdit() AND $topic::canTag( NULL, $topic->container() ) AND $topic::canPrefix( NULL, $topic->container() ) )}}
<span {{if !$topic->prefix()}}class='ipsHide'{{endif}} {{if ( $topic->canEdit() AND $topic::canTag( NULL, $topic->container() ) AND $topic::canPrefix( NULL, $topic->container() ) )}}data-editablePrefix{{endif}}>
{template="prefix" group="global" app="core" params="$topic->prefix( TRUE ), $topic->prefix()"}
</span>
{{endif}}
{{if $topic->canEdit()}}
<div class='ipsType_break ipsContained' data-controller="core.front.core.moderation">
<span {{if $topic->isQuestion()}} itemprop="name"{{endif}} data-role="editableTitle" title='{lang="click_hold_edit"}'>{$topic->title}</span>
</div>
{{else}}
{wordbreak="$topic->title"}
<div class='ipsType_break ipsContained'>
<span {{if $topic->isQuestion()}} itemprop="name"{{endif}}>{$topic->title}</span>
</div>
{{endif}}
</h1>
<p class='ipsType_reset ipsType_blendLinks {{if count( $topic->tags() )}}ipsSpacer_bottom ipsSpacer_half{{endif}}'>
{{if $topic->locked() && $topic->topic_open_time && $topic->topic_open_time > time()}}
<p class='ipsType_reset ipsType_medium'><strong><i class='fa fa-clock-o'></i> {lang="topic_unlocks_at" htmlsprintf="\IPS\DateTime::ts( $topic->topic_open_time )->html(), \IPS\DateTime::ts( $topic->topic_open_time )->localeTime( FALSE )"}</strong></p>
{{elseif !$topic->locked() && $topic->topic_close_time && $topic->topic_close_time > time()}}
<p class='ipsType_reset ipsType_medium'><strong><i class='fa fa-clock-o'></i> {lang="topic_locks_at" htmlsprintf="\IPS\DateTime::ts( $topic->topic_close_time )->html(), \IPS\DateTime::ts( $topic->topic_close_time )->localeTime( FALSE )"}</strong></p>
{{endif}}
<p class='ipsType_reset ipsType_blendLinks {{if count( $topic->tags() ) OR ( $topic->canEdit() AND $topic::canTag( NULL, $topic->container() ) )}}ipsSpacer_bottom ipsSpacer_half{{endif}}'>
<span class='ipsType_normal'>{{if $topic->isQuestion()}}{lang="ask_byline_no_date" htmlsprintf="$topic->author()->link( $topic->warningRef() )"}{{else}}{lang="topic_started_by" htmlsprintf="$topic->author()->link( $topic->warningRef() )"}{{endif}}</span>, <span class='ipsType_light ipsType_noBreak'>{datetime="$topic->start_date"}</span><br>
</p>
{{if count( $topic->tags() )}}
{template="tags" group="global" app="core" params="$topic->tags()"}
{{if count( $topic->tags() ) OR ( $topic->canEdit() AND $topic::canTag( NULL, $topic->container() ) )}}
{template="tags" group="global" app="core" params="$topic->tags(), FALSE, FALSE, ( $topic->canEdit() AND $topic::canTag( NULL, $topic->container() ) ) ? $topic->url() : NULL"}
{{endif}}
</div>
</div>
@@ -1835,7 +1911,7 @@
<div class="ipsMessage ipsMessage_warning ipsSpacer_top">
<p class="ipsType_reset">{lang="topic_pending_approval"}</p>
<ul class='ipsList_inline ipsSpacer_top'>
<li><a href="{$topic->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' => 'unhide' ) )}" class="ipsButton ipsButton_positive ipsButton_verySmall" title='{lang="approve_title"}'><i class="fa fa-check"></i> {lang="approve"}</a></li>
<li><a href="{$topic->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' => 'unhide' ) )}" class="ipsButton ipsButton_positive ipsButton_verySmall" title='{lang="approve_title_topic"}'><i class="fa fa-check"></i> {lang="approve"}</a></li>
{{if $topic->canDelete()}}
<li><a href='{$topic->url()->csrf()->setQueryString( array( 'do' => 'moderate', 'action' => 'delete' ) )}' data-confirm title='{lang="topic_delete_title"}' class='ipsButton ipsButton_negative ipsButton_verySmall'><i class='fa fa-times'></i> {lang="delete"}</a></li>
{{endif}}
@@ -1847,7 +1923,7 @@
{{if $topic->container()->forum_allow_rating}}
<div class='ipsPad_half ipsPos_left ipsType_light ipsResponsive_hidePhone'>
{{if $topic->canRate()}}
<p class='ipsType_reset ipsType_center ipsType_small'>
<p class='ipsType_reset ipsType_small'>
{{if $topic->isQuestion()}}{lang="rate_this_question"}{{else}}{lang="rate_this_topic"}{{endif}}
</p>
{{endif}}
@@ -1855,9 +1931,9 @@
</div>
{{endif}}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both {{if !( $topic->canPin() or $topic->canUnpin() or $topic->canFeature() or $topic->canUnfeature() or $topic->canHide() or $topic->canUnhide() or $topic->canMove() or $topic->canLock() or $topic->canUnlock() or $topic->canDelete() or $topic->availableSavedActions() )}}ipsResponsive_hidePhone{{endif}}">
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both {{if !$topic->canComment() and !( $topic->canPin() or $topic->canUnpin() or $topic->canFeature() or $topic->canUnfeature() or $topic->canHide() or $topic->canUnhide() or $topic->canMove() or $topic->canLock() or $topic->canUnlock() or $topic->canDelete() or $topic->availableSavedActions() )}}ipsResponsive_hidePhone{{endif}}">
{{if $topic->canComment()}}
<li class='ipsToolList_primaryAction ipsResponsive_hidePhone'>
<li class='ipsToolList_primaryAction'>
<span data-controller='forums.front.topic.reply'>
{{if $topic->container()->forums_bitoptions['bw_enable_answers']}}
<a href='#replyForm' class='ipsButton {{if $topic->locked()}}ipsButton_negative{{else}}ipsButton_important{{endif}} ipsButton_medium ipsButton_fullWidth' data-action='replyToTopic'>{lang="answer_this_question"}{{if $topic->locked()}} ({lang="locked"}){{endif}}</a>
@@ -1935,7 +2011,7 @@
{$poll|raw}
<br>
{{endif}}
<div data-controller='core.front.core.commentFeed,forums.front.topic.view' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$topic->url()}' {{if $topic->isLastPage() and !$topic->isQuestion()}}data-lastPage{{endif}} data-feedID='topic-{$topic->tid}' class='cTopic ipsClear ipsSpacer_top'>
<div data-controller='core.front.core.commentFeed,forums.front.topic.view, core.front.core.ignoredComments' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$topic->url()}' {{if $topic->isLastPage() and !$topic->isQuestion()}}data-lastPage{{endif}} data-feedID='topic-{$topic->tid}' class='cTopic ipsClear ipsSpacer_top'>
{{if $topic->isQuestion() && $question}}
<h2 class='ipsType_sectionTitle ipsType_reset'>{lang="question_title"}</h2>
<div class='ipsAreaBackground_light ipsPad'>
@@ -2008,6 +2084,8 @@
{{if $topic->commentForm()}}
{{if $topic->locked()}}
<p class='ipsType_reset ipsType_warning ipsComposeArea_warning ipsSpacer_bottom ipsSpacer_half'><i class='fa fa-info-circle'></i> {lang="topic_locked_can_comment"}</p>
{{elseif ( $topic->getPoll() and $topic->getPoll()->poll_only )}}
<p class='ipsType_reset ipsType_warning ipsComposeArea_warning ipsSpacer_bottom ipsSpacer_half'><i class='fa fa-info-circle'></i> {lang="topic_poll_can_comment"}</p>
{{endif}}
{$topic->commentForm()|raw}
{{else}}
@@ -2091,16 +2169,16 @@
<div class='ipsGrid ipsGrid_collapsePhone ipsPager ipsClearfix ipsSpacer_top'>
<div class="ipsGrid_span6 ipsType_left ipsPager_prev">
<a href="{$topic->container()->url()}" title="{lang="go_to_forum" sprintf="$topic->container()->_title"}" rel="up">
<a href="{$topic->container()->url()}" title="{lang="go_to_forum" sprintf="$topic->container()->metaTitle()"}" rel="up">
<span class="ipsPager_type">{{if $topic->isQuestion() }}{lang="go_back_to_qa_forum"}{{else}}{lang="go_back_to_forum"}{{endif}}</span>
<span class="ipsPager_title ipsType_light ipsType_break">{lang="$topic->container()->_title" wordbreak="true"}</span>
<span class="ipsPager_title ipsType_light ipsTruncate ipsTruncate_line">{lang="$topic->container()->_title"}</span>
</a>
</div>
{{if $nextUnread !== NULL}}
<div class='ipsGrid_span6 ipsType_right ipsPager_next'>
<a href="{$nextUnread->url()->setQueryString( array( 'do' => 'getNewComment' ) )}" title='{{if $topic->isQuestion()}}{lang="view_next_unread_question_title"}{{else}}{lang="view_next_unread_title"}{{endif}}' rel='next'>
<a href="{$nextUnread->url()->setQueryString( array( 'do' => 'getNewComment' ) )}" title='{{if $topic->isQuestion()}}{lang="view_next_unread_question_title"}{{else}}{lang="view_next_unread_title"}{{endif}}'>
<span class="ipsPager_type">{{if $topic->isQuestion()}}{lang="view_next_unread_question"}{{else}}{lang="view_next_unread"}{{endif}}</span>
<span class="ipsPager_title ipsType_light ipsType_break">{$nextUnread->mapped('title')}</span>
<span class="ipsPager_title ipsType_light ipsTruncate ipsTruncate_line">{$nextUnread->mapped('title')}</span>
</a>
</div>
{{endif}}
@@ -2157,23 +2235,26 @@
<div class='ipsDataItem_icon ipsPos_top'>
{template="userPhoto" group="global" app="core" params="$topic->author(), 'tiny'"}
</div>
<div class='ipsDataItem_main'>
<div class="ipsCommentCount ipsPos_right {{if ( $topic->posts - 1 ) === 0}}ipsFaded{{endif}}" data-ipsTooltip title='{lang="replies_number" pluralize="$topic->posts - 1"}'>{expression="$topic->posts - 1"}</div>
<a href="{$topic->url()->setQueryString( 'do', 'getNewComment' )}" title='{lang="view_this_topic" sprintf="$topic->title"}' class='ipsDataItem_title ipsType_break'>{wordbreak="$topic->title"}</a>
{{if $topic->mapped('featured') || $topic->hidden() === -1 || $topic->hidden() === 1}}
<span>
<div class='ipsDataItem_main cWidgetComments'>
<div class="ipsCommentCount ipsPos_right {{if ( $topic->posts - 1 ) === 0}}ipsFaded{{endif}}" data-ipsTooltip title='{lang="replies_number" pluralize="$topic->posts - 1"}'>{expression="\IPS\Member::loggedIn()->language()->formatNumber( $topic->posts - 1 )"}</div>
<div class='ipsType_break ipsContained'>
{{if $topic->mapped('featured') || $topic->hidden() === -1 || $topic->hidden() === 1}}
{{if $topic->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span></span>
{{elseif $topic->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span></span>
{{endif}}
{{if $topic->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span></span>
{{endif}}
</span>
{{endif}}
<br>
<span class='ipsType_light ipsType_small'>{lang="byline_nodate" htmlsprintf="$topic->author()->link()"} &middot; {datetime="$topic->mapped('date')"}</span>
{{endif}}
<a href="{$topic->url()->setQueryString( 'do', 'getNewComment' )}" title='{lang="view_this_topic" sprintf="$topic->title"}' class='ipsDataItem_title'>{$topic->title}</a>
</div>
<p class='ipsType_reset ipsType_medium ipsType_blendLinks ipsContained'>
<span>{lang="byline_nodate" htmlsprintf="$topic->author()->link()"}</span><br>
<span class='ipsType_light'>{lang="topic_started_date" htmlsprintf="\IPS\DateTime::ts( $topic->mapped('date') )->html()"}</span>
</p>
</div>
</li>
{{endforeach}}
@@ -2200,7 +2281,7 @@
<ol class='ipsList_reset cPollList cPollList_questions'>
{{foreach $collection as $idx => $input}}
<li class='ipsFieldRow ipsFieldRow_noLabel'>
<h4 class='ipsType_normal ipsType_reset'>{$idx}. {wordbreak="$input->label"}</h4>
<h4 class='ipsType_normal ipsType_reset'><div class='ipsType_break ipsContained'>{$idx}. {$input->label}</div></h4>
{{if !$input->options['multiple']}}
{template="radio" app="core" location="global" group="forms" params="$input->name, $input->value, $input->required, $input->options['options'], $input->options['disabled'], '', $input->options['disabled']"}
{{else}}
@@ -2230,22 +2311,26 @@
{{endif}}
{{if $poll->canVote() and request._poll != 'results' and ( !$poll->getVote() or request._poll == 'form') and $pollForm = $poll->buildForm()}}
<h3 class='ipsWidget_title ipsType_reset'>
{wordbreak="$poll->poll_question"}&nbsp;&nbsp;
<span class='ipsType_small ipsType_light'>{lang="poll_num_votes" pluralize="$poll->votes"}</span>
</h2>
<div class='ipsType_break ipsContained'>
{$poll->poll_question}&nbsp;&nbsp;
<span class='ipsType_small ipsType_light'>{lang="poll_num_votes" pluralize="$poll->votes"}</span>
</div>
</h3>
<div class='ipsPad_half ipsWidget_inner ipsClearfix' data-role='pollContents'>
{$pollForm->customTemplate( array( \IPS\Theme::i()->getTemplate( 'widgets', 'forums', 'front' ), 'pollFormWidget' ), $url )|raw}
</div>
{{elseif !$poll->canVote() or $poll->getVote() or ( request._poll == 'results' and settings.allow_result_view )}}
<h3 class='ipsWidget_title ipsType_reset'>
{wordbreak="$poll->poll_question"}&nbsp;&nbsp;
<span class='ipsType_small ipsType_light'>{lang="poll_num_votes" pluralize="$poll->votes"}</span>
<div class='ipsType_break ipsContained'>
{$poll->poll_question}&nbsp;&nbsp;
<span class='ipsType_small ipsType_light'>{lang="poll_num_votes" pluralize="$poll->votes"}</span>
</div>
</h3>
<div class='ipsPad_half ipsWidget_inner ipsClearfix' data-role='pollContents'>
<ol class='ipsList_reset cPollList'>
{{foreach $poll->choices as $questionId => $question}}
<li>
<h3 class='ipsType_normal ipsType_reset'>{$questionId}. {wordbreak="$question['question']"}</h3>
<h3 class='ipsType_normal ipsType_reset'><div class='ipsType_break ipsContained'>{$questionId}. {$question['question']}</div></h3>
<br>
<ul class='ipsList_reset cPollList_choices'>
{{foreach $question['choice'] as $k => $choice}}
@@ -2255,7 +2340,7 @@
</div>
<div class='ipsGrid_span7'>
<span class='cPollVoteBar'>
<span style='width: {{if $poll->votes}}{expression="intval( ( $question['votes'][ $k ] / $poll->votes ) * 100 )"}{{else}}0{{endif}}%' data-votes='{{if $poll->votes}}{expression="round( ( $question['votes'][ $k ] / $poll->votes ) * 100, 2 )"}{{else}}0{{endif}}%' {{if $poll->votes && intval( ( $question['votes'][ $k ] / $poll->votes ) * 100 ) > 30}}class='cPollVoteBar_inside'{{endif}}></span>
<span style='width: {{if array_sum( $question['votes'] ) > 0 }}{expression="intval( ( $question['votes'][ $k ] / array_sum( $question['votes'] ) ) * 100 )"}{{else}}0{{endif}}%' data-votes='{{if array_sum( $question['votes'] ) > 0}}{expression="round( ( $question['votes'][ $k ] / array_sum( $question['votes'] ) ) * 100, 2 )"}{{else}}0{{endif}}%' {{if array_sum( $question['votes'] ) && intval( ( $question['votes'][ $k ] / array_sum( $question['votes'] ) ) * 100 ) > 30}}class='cPollVoteBar_inside'{{endif}}></span>
</span>
</div>
</li>
@@ -2267,7 +2352,7 @@
{{if $poll->canVote() || !member.member_id}}
<hr class='ipsHr'>
{{if $poll->canVote()}}<a href="{$url->setQueryString( '_poll', 'form' )}" title='{lang="show_vote_options"}' class='ipsButton ipsButton_verySmall ipsButton_light' data-action='viewResults'><i class='fa fa-caret-left'></i> {lang="show_vote_options"}</a>{{endif}}
{{if !member.member_id}}{lang="poll_guest" htmlsprintf="\IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login' ), \IPS\Http\Url::internal( 'app=core&module=system&controller=register', 'front', 'register' )"}{{endif}}
{{if !member.member_id}}{lang="poll_guest" htmlsprintf="\IPS\Http\Url::internal( 'app=core&module=system&controller=login', 'front', 'login', NULL, \IPS\Settings::i()->logins_over_https ), \IPS\Http\Url::internal( 'app=core&module=system&controller=register', 'front', 'register', NULL, \IPS\Settings::i()->logins_over_https )"}{{endif}}
{{endif}}
<a class='ipsPos_right ipsType_light ipsType_small ipsType_break' href="{$url}">{lang="poll_view_topic"}</a>
</div>
@@ -2286,9 +2371,9 @@
{template="userPhoto" group="global" app="core" params="$comment->author(), 'tiny'"}
</div>
<div class='ipsDataItem_main'>
<a href="{$comment->url()}" title='{lang="view_this_topic" sprintf="$comment->item()->title"}' class='ipsType_medium ipsType_break'>{wordbreak="$comment->item()->title"}</a><br>
<p class='ipsType_reset ipsType_light ipsType_medium ipsType_blendLinks'>{lang="byline_nodate" htmlsprintf="$comment->author()->link()"} &middot; <a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' class='ipsType_blendLinks' title='{lang="share_this_comment"}'>{$comment->dateLine()|raw}</a></p>
<div class='ipsType_medium ipsType_textBlock ipsType_richText ipsType_break ipsContained ipsSpacer_top ipsSpacer_half' data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='{{if $orientation == 'vertical'}}6 lines{{else}}2 lines{{endif}}'>
<div class='ipsType_break ipsContained'><a href="{$comment->url()}" title='{lang="view_this_topic" sprintf="$comment->item()->title"}' class='ipsType_medium ipsTruncate ipsTruncate_line'>{$comment->item()->title}</a></div>
<p class='ipsType_reset ipsType_light ipsType_medium ipsType_blendLinks'>{lang="byline_nodate" htmlsprintf="$comment->author()->link()"} &middot; <a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->pid ) )}' class='ipsType_blendLinks'>{$comment->dateLine()|raw}</a></p>
<div class='ipsType_medium ipsType_textBlock ipsType_richText ipsType_break ipsContained ipsSpacer_top ipsSpacer_half' data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='{{if $orientation == 'vertical'}}6 lines{{else}}2 lines{{endif}}' data-ipsTruncate-watch='false'>
{$comment->truncated( true )|raw}
</div>
</div>
@@ -2305,14 +2390,14 @@
{template="userPhoto" app="core" group="global" params="$comment->author(), 'mini', $comment->warningRef()"}
<div>
<p class='ipsPos_right ipsType_reset ipsType_blendLinks'>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' data-ipsTooltip title='{lang="share_this_comment"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$comment->id}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->pid ) )}' data-ipsTooltip title='{lang="share_this_comment"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$comment->pid}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
</p>
<h3 class='ipsComment_author ipsType_blendLinks'>
<strong class='ipsType_normal'>{template="userLink" app="core" group="global" params="$comment->author(), $comment->warningRef()"}</strong>
{template="reputationBadge" group="global" app="core" params="$comment->author()"}
</h3>
<p class='ipsComment_meta ipsType_light ipsType_medium'>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' class='ipsType_blendLinks' title='{lang="share_this_comment"}'>{$comment->dateLine()|raw}</a>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->pid ) )}' class='ipsType_blendLinks'>{$comment->dateLine()|raw}</a>
{{if $comment->editLine()}}
({lang="edited_lc"})
{{endif}}
@@ -2331,7 +2416,7 @@
</div>
<div class='ipsPad ipsClearfix'>
<a href="{$comment->url()}" title='{lang="view_this_topic" sprintf="$comment->item()->title"}' class='ipsDataItem_title ipsType_break'>{wordbreak="$comment->item()->title"}</a><br>
<div class='ipsType_break ipsContained'><a href="{$comment->url()}" title='{lang="view_this_topic" sprintf="$comment->item()->title"}' class='ipsDataItem_title ipsTruncate ipsTruncate_line'>{wordbreak="$comment->item()->title"}</a></div>
<div data-role='commentContent' class='ipsType_normal ipsType_richText ipsType_break ipsContained' data-controller='core.front.core.lightboxedImages'>
{{if $comment->hidden() === 1 && $comment->author()->member_id == \IPS\Member::loggedIn()->member_id}}
<strong class='ipsType_medium ipsType_warning'><i class='fa fa-info-circle'></i> {lang="comment_awaiting_approval"}</strong>
@@ -2365,23 +2450,23 @@
<div class='ipsDataItem_icon ipsPos_top'>
{template="userPhoto" group="global" app="core" params="$topic->author(), 'tiny'"}
</div>
<div class='ipsDataItem_main'>
<div class="ipsCommentCount ipsPos_right {{if ( $topic->posts - 1 ) === 0}}ipsFaded{{endif}}" data-ipsTooltip title='{lang="replies_number" pluralize="$topic->posts - 1"}'>{expression="$topic->posts - 1"}</div>
{{if $topic->mapped('featured') || $topic->hidden() === -1 || $topic->hidden() === 1}}
<span>
<div class='ipsDataItem_main cWidgetComments'>
<div class="ipsCommentCount ipsPos_right {{if ( $topic->posts - 1 ) === 0}}ipsFaded{{endif}}" data-ipsTooltip title='{lang="replies_number" pluralize="$topic->posts - 1"}'>{expression="\IPS\Member::loggedIn()->language()->formatNumber( $topic->posts - 1 )"}</div>
<div class='ipsType_break ipsContained'>
{{if $topic->mapped('featured') || $topic->hidden() === -1 || $topic->hidden() === 1}}
{{if $topic->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$topic->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span></span>
{{elseif $topic->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span></span>
{{endif}}
{{if $topic->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
<span><span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span></span>
{{endif}}
</span>
{{endif}}
<a href="{$topic->url()->setQueryString( 'do', 'getNewComment' )}" title='{lang="view_this_topic" sprintf="$topic->title"}' class='ipsDataItem_title ipsType_break'>{wordbreak="$topic->title"}</a>
<br>
<p class='ipsType_reset ipsType_medium ipsType_blendLinks'>
{{endif}}
<a href="{$topic->url()->setQueryString( 'do', 'getNewComment' )}" title='{lang="view_this_topic" sprintf="$topic->title"}' class='ipsDataItem_title'>{$topic->title}</a>
</div>
<p class='ipsType_reset ipsType_medium ipsType_blendLinks ipsContained'>
<span>{lang="byline_nodate" htmlsprintf="$topic->author()->link()"}</span><br>
<span class='ipsType_light'>{lang="topic_started_date" htmlsprintf="\IPS\DateTime::ts( $topic->mapped('date') )->html()"}</span>
</p>
@@ -2426,6 +2511,10 @@
html[dir=&quot;rtl&quot;] .cTopicList .ipsDataItem_icon + .ipsDataItem_main + .ipsDataItem_stats {
margin-right: 30px !important;
}
.cTopicList .ipsDataItem_main {
padding: 0;
}
}
/* TABLETS */
+2 -1
View File
@@ -9,6 +9,7 @@
"sc_tab_key": "custom",
"sc_show_in_vse": 1,
"sc_title": "themesetting_forum_layout",
"sc_order": 5
"sc_order": 5,
"sc_condition": null
}
]
+75 -1
View File
@@ -58,5 +58,79 @@
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2"
"101012": "4.1.2",
"101013": "4.1.3",
"101014": "4.1.3.1",
"101015": "4.1.3.2",
"101016": "4.1.4",
"101017": "4.1.4.1",
"101018": "4.1.5",
"101019": "4.1.5.1",
"101020": "4.1.5.2",
"101021": "4.1.6",
"101022": "4.1.6.1",
"101023": "4.1.7",
"101024": "4.1.8",
"101025": "4.1.8.1",
"101026": "4.1.9",
"101027": "4.1.10",
"101028": "4.1.11",
"101029": "4.1.11.1",
"101030": "4.1.12",
"101031": "4.1.12.1",
"101032": "4.1.12.2",
"101033": "4.1.12.3",
"101034": "4.1.13 Beta 1",
"101035": "4.1.13 Beta 2",
"101036": "4.1.13",
"101037": "4.1.13",
"101038": "4.1.13.1",
"101040": "4.1.13.2",
"101041": "4.1.13.2",
"101042": "4.1.14 Beta 1",
"101043": "4.1.14 Beta 2",
"101044": "4.1.14 Beta 3",
"101045": "4.1.14 Beta 4",
"101046": "4.1.14 Beta 5",
"101049": "4.1.14 Beta 6",
"101050": "4.1.14 Beta 7",
"101051": "4.1.14 RC",
"101052": "4.1.14",
"101053": "4.1.14.1",
"101054": "4.1.14.2",
"101055": "4.1.14.3",
"101056": "4.1.15",
"101057": "4.1.15 Beta 1",
"101058": "4.1.15 Beta 2",
"101059": "4.1.15 Beta 2a",
"101060": "4.1.15 Beta 3",
"101061": "4.1.15",
"101062": "4.1.15",
"101063": "4.1.15",
"101064": "4.1.16 Beta 1",
"101065": "4.1.16 Beta 2",
"101066": "4.1.16 Beta 3",
"101067": "4.1.16 Beta 4",
"101068": "4.1.16 Beta 5",
"101069": "4.1.16",
"101070": "4.1.16.1",
"101071": "4.1.17 Beta 1",
"101072": "4.1.17 Beta 1a",
"101073": "4.1.17 Beta 1b",
"101074": "4.1.17 Beta 2",
"101075": "4.1.17 Beta 3",
"101076": "4.1.17 Beta 3",
"101077": "4.1.17",
"101078": "4.1.17.1",
"101079": "4.1.18 Beta 1",
"101082": "4.1.18 Beta 1b",
"101083": "4.1.18 Beta 2",
"101084": "4.1.18 Beta 3",
"101085": "4.1.18",
"101088": "4.1.18.1",
"101089": "4.1.18.2",
"101090": "4.1.19 Beta 1",
"101091": "4.1.19 Beta 2",
"101092": "4.1.19 Beta 3",
"101093": "4.1.19"
}
@@ -2,9 +2,9 @@
/**
* @brief Advertisement locations extension
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 16 Jul 2014
* @version SVN_VERSION_NUMBER
@@ -2,10 +2,10 @@
/**
* @brief Advertisement locations extension
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Forums
* @since 16 Jul 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Announcements Extension : Forums
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 28 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -0,0 +1,72 @@
<?php
/**
* @brief BBCode Tag
* @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
* @subpackage Forums
* @since 08 Feb 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\extensions\core\BBCode;
/* 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;
}
/**
* BBCode Tag
*/
class _post
{
/**
* Permission Check
*
* @param \IPS\Member $member The member
* @param string $area The Editor area
* @return bool
*/
public function permissionCheck( \IPS\Member $member, $area )
{
return \IPS\Text\Parser::canUse( $member, 'ipsLink', $area );
}
/**
* Get Configuration
*
* @code
return array(
'tag' => 'span', // The HTML tag to use
'attributes' => array( ... ) // Key/Value pairs of attributes to use (optional) - can use {option} to get the [tag=option] value
'callback' => function( $node, $matches, $document ) // A callback to modify the DOMNode object
{
...
},
'block' => FALSE, // If this is a block-level tag (optional, default false)
'single' => FALSE, // If this is a single tag, with no content (optional, default false)
)
* @endcode
* @return array
*/
public function getConfiguration()
{
return array(
'tag' => 'a',
'callback' => function( \DOMElement $node, $matches, \DOMDocument $document )
{
try
{
$node->setAttribute( 'href', (string) \IPS\forums\Topic\Post::load( intval( $matches[2] ) )->url() );
}
catch ( \Exception $e ) {}
return $node;
},
);
}
}
@@ -0,0 +1,74 @@
<?php
/**
* @brief BBCode Tag
* @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
* @subpackage Forums
* @since 08 Feb 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\extensions\core\BBCode;
/* 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;
}
/**
* BBCode Tag
*/
class _snapback
{
/**
* Permission Check
*
* @param \IPS\Member $member The member
* @param string $area The Editor area
* @return bool
*/
public function permissionCheck( \IPS\Member $member, $area )
{
return \IPS\Text\Parser::canUse( $member, 'ipsLink', $area );
}
/**
* Get Configuration
*
* @code
return array(
'tag' => 'span', // The HTML tag to use
'attributes' => array( ... ) // Key/Value pairs of attributes to use (optional) - can use {option} to get the [tag=option] value
'callback' => function( $node, $matches, $document ) // A callback to modify the DOMNode object
{
...
},
'block' => FALSE, // If this is a block-level tag (optional, default false)
'single' => FALSE, // If this is a single tag, with no content (optional, default false)
)
* @endcode
* @return array
*/
public function getConfiguration()
{
return array(
'tag' => 'a',
'callback' => function( \DOMElement $node, $matches, \DOMDocument $document )
{
try
{
$node->setAttribute( 'href', (string) \IPS\forums\Topic\Post::load( intval( $matches[2] ) )->url() );
$node->appendChild( $document->createEntityReference( 'larr' ) );
}
catch ( \Exception $e ) {}
return $node;
},
'single' => TRUE,
);
}
}
@@ -0,0 +1,72 @@
<?php
/**
* @brief BBCode Tag
* @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
* @subpackage Forums
* @since 08 Feb 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\extensions\core\BBCode;
/* 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;
}
/**
* BBCode Tag
*/
class _topic
{
/**
* Permission Check
*
* @param \IPS\Member $member The member
* @param string $area The Editor area
* @return bool
*/
public function permissionCheck( \IPS\Member $member, $area )
{
return \IPS\Text\Parser::canUse( $member, 'ipsLink', $area );
}
/**
* Get Configuration
*
* @code
return array(
'tag' => 'span', // The HTML tag to use
'attributes' => array( ... ) // Key/Value pairs of attributes to use (optional) - can use {option} to get the [tag=option] value
'callback' => function( $node, $matches, $document ) // A callback to modify the DOMNode object
{
...
},
'block' => FALSE, // If this is a block-level tag (optional, default false)
'single' => FALSE, // If this is a single tag, with no content (optional, default false)
)
* @endcode
* @return array
*/
public function getConfiguration()
{
return array(
'tag' => 'a',
'callback' => function( \DOMElement $node, $matches, \DOMDocument $document )
{
try
{
$node->setAttribute( 'href', (string) \IPS\forums\Topic::load( intval( $matches[2] ) )->url() );
}
catch ( \Exception $e ) {}
return $node;
},
);
}
}
@@ -2,9 +2,10 @@
/**
* @brief Moderator Permissions: Topics
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 16 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Content Router extension: Topics
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 15 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Create Menu Extension : Topic
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 14 Feb 2014
* @version SVN_VERSION_NUMBER
@@ -2,10 +2,10 @@
/**
* @brief Editor Extension: Forums
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 08 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -46,7 +46,7 @@ class _Forums
{
return NULL;
}
/**
* Permission check for attachments
*
@@ -54,9 +54,10 @@ class _Forums
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3 )
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment )
{
try
{
@@ -66,7 +67,16 @@ class _Forums
}
elseif ( $id2 )
{
$post = \IPS\forums\Topic\Post::load( $id2 );
$topic = \IPS\forums\Topic::load( $id1 );
if( $topic->isArchived() )
{
$post = \IPS\forums\Topic\ArchivedPost::load( $id2 );
}
else
{
$post = \IPS\forums\Topic\Post::load( $id2 );
}
/* Check forums attachments permission */
if ( $post->container()->can( 'attachments', $member ) )
@@ -114,7 +124,16 @@ class _Forums
}
elseif ( $id2 )
{
return \IPS\forums\Topic\Post::load( $id2 );
$topic = \IPS\forums\Topic::load( $id1 );
if( $topic->isArchived() )
{
return \IPS\forums\Topic\ArchivedPost::load( $id2 );
}
else
{
return \IPS\forums\Topic\Post::load( $id2 );
}
}
else
{
@@ -2,10 +2,10 @@
/**
* @brief File Storage Extension: Icons
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 06 Feb 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Front Navigation Extension: Forums
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 08 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -35,13 +35,13 @@ class _Forums extends \IPS\core\FrontNavigation\FrontNavigationAbstract
}
/**
* Can access?
* Can the currently logged in user access the content this item links to?
*
* @return bool
*/
public function canView()
public function canAccessContent()
{
return parent::canView() and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'forums', 'forums' ) );
return \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'forums', 'forums' ) );
}
/**
@@ -2,9 +2,9 @@
/**
* @brief ACP Live Search Extension
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 08 Apr 2014
* @version SVN_VERSION_NUMBER
@@ -73,4 +73,14 @@ class _Forums
return $results;
}
/**
* Is default for current page?
*
* @return bool
*/
public function isDefault()
{
return \IPS\Dispatcher::i()->application->directory == 'forums';
}
}
@@ -2,10 +2,10 @@
/**
* @brief Member Sync
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Forums
* @since 14 Jul 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Permissions
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Forums
* @since 16 Apr 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Background Task
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 18 Mar 2015
* @version SVN_VERSION_NUMBER
@@ -40,17 +40,17 @@ class _DeleteLegacyPosts
/**
* Run Background Task
*
* @param mixed $data Data as it was passed to \IPS\Task::queue()
* @param int $offset Offset
* @return int|null New offset or NULL if complete
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
* @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 )
{
$select = \IPS\Db::i()->select( '*', 'forums_posts', 'queued > 2', 'pid ASC', array( 0, 5 ) );
if ( !count( $select ) )
{
throw new \OutOfRangeException;
throw new \IPS\Task\Queue\OutOfRangeException;
}
$done = 0;
@@ -68,11 +68,11 @@ class _DeleteLegacyPosts
*
* @param mixed $data Data as it was passed to \IPS\Task::queue()
* @param int $offset Offset
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaning task and percentage complete
* @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_deleting_legacy_posts'), 'complete' => 100 / ( $data['count'] ?: 1 + $offset ) * $offset );
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('queue_deleting_legacy_posts'), 'complete' => round( 100 / ( $data['count'] ?: 1 + $offset ) * $offset, 2 ) );
}
}
@@ -2,9 +2,9 @@
/**
* @brief Background Task
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 18 Mar 2015
* @version SVN_VERSION_NUMBER
@@ -40,17 +40,17 @@ class _DeleteLegacyTopics
/**
* Run Background Task
*
* @param mixed $data Data as it was passed to \IPS\Task::queue()
* @param int $offset Offset
* @return int|null New offset or NULL if complete
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
* @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 )
{
$select = \IPS\Db::i()->select( '*', 'forums_topics', 'approved > 1', 'tid ASC', array( 0, 5 ) );
if ( !count( $select ) )
{
throw new \OutOfRangeException;
throw new \IPS\Task\Queue\OutOfRangeException;
}
$done = 0;
@@ -68,11 +68,11 @@ class _DeleteLegacyTopics
*
* @param mixed $data Data as it was passed to \IPS\Task::queue()
* @param int $offset Offset
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaning task and percentage complete
* @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_deleting_legacy_topics'), 'complete' => 100 / ( $data['count'] ?: 1 + $offset ) * $offset );
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('queue_deleting_legacy_topics'), 'complete' => round( 100 / ( $data['count'] ?: 1 + $offset ) * $offset, 2 ) );
}
}
@@ -0,0 +1,80 @@
<?php
/**
* @brief Background Task
* @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
* @subpackage Forums
* @since 18 Mar 2015
* @version SVN_VERSION_NUMBER
*/
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 to fix an issue where topics are not hidden, but the first post is hidden with -1.
*/
class _HiddenFirstPost
{
/**
* Parse data before queuing
*
* @param array $data
* @return array
*/
public function preQueueData( $data )
{
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', 'new_topic = 1 and queued = -1' )->first();
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 )
{
$select = \IPS\Db::i()->select( '*', 'forums_posts', 'new_topic = 1 and queued = -1', 'topic_id ASC', array( 0, 50 ) );
if ( !count( $select ) )
{
throw new \IPS\Task\Queue\OutOfRangeException;
}
$done = 0;
foreach( new \IPS\Patterns\ActiveRecordIterator( $select, 'IPS\forums\Topic\Post' ) as $post )
{
\IPS\Db::i()->update( 'forums_posts', array( 'queued' => 2 ), array( 'topic_id=?', $post->topic_id ) );
$item = $post->item();
$item->hide( NULL );
$done++;
}
return $offset + $done;
}
/**
* 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_fixing_hidden_first_post'), 'complete' => round( 100 / ( $data['count'] ?: 1 + $offset ) * $offset, 2 ) );
}
}
@@ -0,0 +1,151 @@
<?php
/**
* @brief Background Task
* @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
* @subpackage Converter
* @since 26 Feb 2016
* @version SVN_VERSION_NUMBER
*/
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
*/
class _RebuildNewTopicFlag
{
/**
* Parse data before queuing
*
* @param array $data
* @return array
*/
public function preQueueData( $data )
{
try
{
$data['count'] = \IPS\Db::i()->select( 'MAX(tid)', 'forums_topics' )->first();
}
catch( \Exception $e )
{
throw new \OutOfRangeException;
}
if( $data['count'] == 0 )
{
return NULL;
}
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;
$topicIdsToReset = array();
$archivedTopicIdsToReset = array();
$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 )
{
if ( $topic->isArchived() == FALSE )
{
try
{
/* Set first post */
$topic->topic_firstpost = \IPS\Db::i()->select( 'pid', 'forums_posts', array( 'topic_id=?', $topic->tid ), 'post_date ASC', 1 )->first();
$topic->save();
/* Reset new_topic value for topic */
$topicIdsToReset[] = $topic->tid;
$firstPostIds[] = $topic->topic_firstpost;
}
/* Underflow exception may occur if the topic doesn't have any posts for an unknown reason */
catch( \UnderflowException $e ) {}
}
else
{
try
{
/* Set first post */
$topic->topic_firstpost = \IPS\forums\Topic\ArchivedPost::db()->select( 'archive_id', 'forums_archive_posts', array( "archive_topic_id=?", $topic->tid ), "archive_content_date ASC", 1 )->first();
$topic->save();
/* Reset new_topic value for topic */
$archivedTopicIdsToReset[] = $topic->tid;
$firstPostArchivedIds[] = $topic->topic_firstpost;
}
/* Underflow exception may occur if the topic doesn't have any posts for an unknown reason */
catch( \UnderflowException $e ) {}
}
$last = $topic->tid;
}
/* Reset flags as needed */
if( count( $topicIdsToReset ) )
{
\IPS\Db::i()->update( 'forums_posts', array( 'new_topic' => 0 ), array( 'topic_id IN(' . implode( ',', $topicIdsToReset ) . ')' ) );
}
if( count( $firstPostIds ) )
{
\IPS\Db::i()->update( 'forums_posts', array( 'new_topic' => 1 ), array( 'pid IN(' . implode( ',', $firstPostIds ) . ')' ) );
}
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 ) )
{
\IPS\forums\Topic\ArchivedPost::db()->update( 'forums_archive_posts', array( 'archive_is_first' => 1 ), array( 'archive_id IN(' . implode( ',', $firstPostArchivedIds ) . ')' ) );
}
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_new_topic_flag'), 'complete' => $data['count'] ? ( round( 100 / $data['count'] * $offset, 2 ) ) : 100 );
}
}
@@ -0,0 +1,105 @@
<?php
/**
* @brief Background Task
* @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
* @subpackage Forums
* @since 04 Jan 2016
* @version SVN_VERSION_NUMBER
*/
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
*/
class _TopicStarterIds
{
/**
* @brief Number of topics to build per cycle
*/
public $perCycle = 500;
/**
* Parse data before queuing
*
* @param array $data
* @return array
*/
public function preQueueData( $data )
{
try
{
$data['count'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics' )->first();
}
catch( \Exception $ex )
{
throw new \OutOfRangeException;
}
if( $data['count'] == 0 )
{
return null;
}
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 )
{
$count = 0;
foreach( \IPS\Db::i()->select( '*', 'forums_topics', array(), 'tid ASC', array( $offset, $this->perCycle ) ) as $topic )
{
$count++;
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'] ) );
}
catch( \UnderflowException $e )
{
continue;
}
}
if( !$count )
{
throw new \IPS\Task\Queue\OutOfRangeException;
}
return ( $offset + $count );
}
/**
* 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('rebuilding_starter_ids'), 'complete' => round( 100 / $data['count'] * $offset, 2 ) );
}
}
@@ -2,10 +2,10 @@
/**
* @brief forums
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 07 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Feeds
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 04 Feb 2014
* @version SVN_VERSION_NUMBER
*/
@@ -70,7 +70,7 @@ class _rss extends \IPS\Node\Controller
\IPS\Output::i()->output = new \IPS\Helpers\Wizard( array(
'rss_import_url' => function( $data )
{
$form = new \IPS\Helpers\Form;
$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' ) );
@@ -142,7 +142,32 @@ class _rss extends \IPS\Node\Controller
{
return $forum->sub_can_post and !$forum->redirect_url;
} ) ) );
$form->add( new \IPS\Helpers\Form\Member( 'rss_import_mid', \IPS\Member::loggedIn(), TRUE ) );
$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' ) ) ) );
@@ -2,10 +2,10 @@
/**
* @brief savedActions
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 30 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Settings
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 20 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -34,11 +34,11 @@ class _settings extends \IPS\Dispatcher\Controller
\IPS\Dispatcher::i()->checkAcpPermission( 'settings_access' );
$tabs = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction('forum_settings') )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'forums', 'forums', 'forum_settings' ) )
{
$tabs['settings'] = 'forum_settings';
}
if ( \IPS\Member::loggedIn()->hasAcpRestriction('archive_manage') )
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'forums', 'forums', 'archive_manage' ) )
{
$tabs['archiving'] = 'archiving';
}
@@ -128,20 +128,20 @@ class _settings extends \IPS\Dispatcher\Controller
$members = array();
foreach( explode( ',', $rule['archive_text'] ) AS $v )
{
$members[] = \IPS\Member::load( $v )->name;
$members[] = \IPS\Member::load( $v );
}
$existingValues['archive_topic_starter'] = implode( ',', $members );
$existingValues['archive_topic_starter'] = $members;
}
else
{
$members = array();
foreach( explode( ',', $rule['archive_text'] ) AS $v )
{
$members[] = \IPS\Member::load( $v )->name;
$members[] = \IPS\Member::load( $v );
}
$existingValues['archive_topic_starter_not'] = implode( ',', $members );
$existingValues['archive_topic_starter_not'] = $members;
}
break;
}
@@ -224,7 +224,7 @@ class _settings extends \IPS\Dispatcher\Controller
{
if ( in_array( $k, array( 'archive_last_post' ) ) )
{
if ( !isset( $v[3] ) or !$v[3] )
if ( ( !isset( $v[3] ) or !$v[3] ) and $v[1] )
{
$rules[] = array(
'archive_key' => md5( "forums_{$k}" ),
@@ -239,7 +239,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
elseif ( in_array( $k, array( 'archive_not_last_post' ) ) )
{
if ( !isset( $v[3] ) or !$v[3] )
if ( ( !isset( $v[3] ) or !$v[3] ) and $v[1] )
{
$rules[] = array(
'archive_key' => md5( "forums_{$k}" ),
@@ -299,7 +299,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
elseif( in_array( $k, array( 'archive_topic_post', 'archive_topic_view', 'archive_topic_rating' ) ) )
{
if ( !isset( $v[2] ) )
if ( !isset( $v[2] ) and $v[1] )
{
$rules[] = array(
'archive_key' => md5( "forums_{$k}" ),
@@ -314,7 +314,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
elseif( in_array( $k, array( 'archive_not_topic_post', 'archive_not_topic_view', 'archive_not_topic_rating' ) ) )
{
if ( !isset( $v[2] ) )
if ( !isset( $v[2] ) and $v[1] )
{
$rules[] = array(
'archive_key' => md5( "forums_{$k}" ),
@@ -329,7 +329,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
elseif( in_array( $k, array( 'archive_topic_starter' ) ) )
{
if ( is_array( $v ) )
if ( is_array( $v ) and count( $v ) )
{
$ids = array();
foreach( $v AS $member )
@@ -350,7 +350,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
elseif( in_array( $k, array( 'archive_topic_starter_not' ) ) )
{
if ( is_array( $v ) )
if ( is_array( $v ) AND count( $v ) )
{
$ids = array();
foreach( $v AS $member )
@@ -446,10 +446,19 @@ class _settings extends \IPS\Dispatcher\Controller
$_whereClause[] = $bind;
}
if( $values['archive_on'] )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => (int)$values['archive_on'] ), array( '`key`=?', 'archive' ) );
}
/* Make sure the unarchive task is enabled - it will disable itself if there is no work to do */
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( '`key`=?', 'unarchive' ) );
/* And disable the archive task if archiving is disabled */
if( !$values['archive_on'] )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'archive' ) );
}
/* Or enable it if archiving is enabled */
else
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( '`key`=?', 'archive' ) );
}
/* Log and redirect */
\IPS\Session::i()->log( 'acplogs__archive_settings' );
@@ -563,6 +572,7 @@ class _settings extends \IPS\Dispatcher\Controller
}
) ) );
$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 ) );
@@ -2,10 +2,10 @@
/**
* @brief posts
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Forums
* @since 18 Aug 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief topics
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Forums
* @since 18 Aug 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Legacy 3.x findpost
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 09 Jul 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Forum Index
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 08 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -30,9 +30,7 @@ class _forums extends \IPS\Dispatcher\Controller
* @return void
*/
protected function manage()
{
\IPS\forums\Forum::loadIntoMemory();
{
$forum = NULL;
try
{
@@ -55,7 +53,7 @@ class _forums extends \IPS\Dispatcher\Controller
/* Password protected */
if ( $form = $forum->passwordForm() )
{
\IPS\Output::i()->title = $forum->_title;
\IPS\Output::i()->title = $forum->_stripTagsTitle;
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forums', 'forums', 'front' ), 'forumPasswordPopup' ) );
return;
}
@@ -77,9 +75,10 @@ class _forums extends \IPS\Dispatcher\Controller
}
/* 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, NULL, 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 );
$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'] )
{
@@ -148,6 +147,8 @@ class _forums extends \IPS\Dispatcher\Controller
'questions_with_best_answers' => 'topic_answered_pid>0',
'questions_without_best_answers' => 'topic_answered_pid=0',
);
$table->sortOptions['question_rating'] = 'forums_topics.question_rating';
}
/* Are we a moderator? */
@@ -188,7 +189,7 @@ class _forums extends \IPS\Dispatcher\Controller
$table->where[] = array( 'popular_time IS NOT NULL AND popular_time>?', time() );
break;
case 'poll':
$table->where[] = 'poll_state<>0';
$table->where[] = array( 'poll_state<>0' );
break;
case 'locked':
$table->where[] = array( 'state=?', 'closed' );
@@ -204,30 +205,36 @@ class _forums extends \IPS\Dispatcher\Controller
$table->where[] = array( 'forums_posts.author_id=?', \IPS\Member::loggedIn()->member_id );
break;
case 'answered':
$table->where[] = 'topic_answered_pid<>0';
$table->where[] = array( 'topic_answered_pid<>0' );
break;
case 'unanswered':
$table->where[] = 'topic_answered_pid=0';
$table->where[] = array( 'topic_answered_pid=0' );
break;
case 'queued_topics':
$table->where[] = 'approved=0';
$table->where[] = array( 'approved=0' );
break;
case 'queued_posts':
$table->where[] = 'topic_queuedposts>0';
$table->where[] = array( 'topic_queuedposts>0' );
break;
}
if ( ! isset( $values['sort_by'] ) )
{
$values['sort_by'] = 'forums_topics.last_post';
}
/* Sort */
switch ( $values['sort_by'] )
{
case 'last_post':
case 'views':
$table->sortBy = $values['sort_by'];
$table->sortBy = 'forums_topics.' . $values['sort_by'];
break;
case 'replies':
$table->sortBy = 'posts';
break;
case 'topic_title':
case 'title':
$table->sortBy = 'title';
break;
case 'last_poster':
@@ -244,45 +251,50 @@ class _forums extends \IPS\Dispatcher\Controller
/* Cutoff */
$days = NULL;
switch ( $values['time_frame'] )
if ( isset( $values['time_frame'] ) )
{
case 'today':
$days = 1;
break;
case 'last_5_days':
$days = 5;
break;
case 'last_7_days':
$days = 7;
break;
case 'last_10_days':
$days = 10;
break;
case 'last_15_days':
$days = 15;
break;
case 'last_20_days':
$days = 20;
break;
case 'last_25_days':
$days = 25;
break;
case 'last_30_days':
$days = 30;
break;
case 'last_60_days':
$days = 60;
break;
case 'last_90_days':
$days = 90;
break;
case 'since_last_visit':
$table->where[] = array( 'forums_topics.last_post>?', \IPS\Member::loggedIn()->last_visit );
break;
switch ( $values['time_frame'] )
{
case 'today':
$days = 1;
break;
case 'last_5_days':
$days = 5;
break;
case 'last_7_days':
$days = 7;
break;
case 'last_10_days':
$days = 10;
break;
case 'last_15_days':
$days = 15;
break;
case 'last_20_days':
$days = 20;
break;
case 'last_25_days':
$days = 25;
break;
case 'last_30_days':
$days = 30;
break;
case 'last_60_days':
$days = 60;
break;
case 'last_90_days':
$days = 90;
break;
case 'since_last_visit':
$table->where[] = array( 'forums_topics.last_post>?', \IPS\Member::loggedIn()->last_visit );
break;
}
}
if ( $days !== NULL )
{
$table->where[] = array( 'forums_topics.last_post>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $days . 'D' ) ) );
$table->where[] = array( 'forums_topics.last_post>?', \IPS\DateTime::create()->sub( new \DateInterval( 'P' . $days . 'D' ) )->getTimestamp() );
}
};
\IPS\Request::i()->sort_direction = \IPS\Request::i()->sort_direction ?: mb_strtolower( $table->sortDirection );
@@ -300,11 +312,11 @@ class _forums extends \IPS\Dispatcher\Controller
$rssUrl = \IPS\Http\Url::internal( "app=forums&module=forums&controller=forums&id={$forum->_id}&rss=1", 'front', 'forums_rss', array( $forum->name_seo ) );
if ( $forum->forums_bitoptions['bw_enable_answers'] )
{
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_questions', FALSE, array( 'sprintf' => array( $forum->_title ) ) );
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_questions', FALSE, array( 'sprintf' => array( $forum->_stripTagsTitle ) ) );
}
else
{
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_topics', FALSE, array( 'sprintf' => array( $forum->_title ) ) );
$rssTitle = \IPS\Member::loggedIn()->language()->addToStack( 'forum_rss_title_topics', FALSE, array( 'sprintf' => array( $forum->_stripTagsTitle ) ) );
}
\IPS\Output::i()->rssFeeds[ $rssTitle ] = $rssUrl;
@@ -333,7 +345,11 @@ class _forums extends \IPS\Dispatcher\Controller
{
if ( !$topic->hidden() )
{
$document->addItem( $topic->title, $topic->url(), $canViewContent ? $topic->content() : NULL, \IPS\DateTime::ts( $topic->start_date ), $topic->tid );
try
{
$document->addItem( $topic->title, $topic->url(), $canViewContent ? $topic->content() : NULL, \IPS\DateTime::ts( $topic->start_date ), $topic->tid );
}
catch ( \Exception $e ) { }
}
}
@@ -352,7 +368,7 @@ class _forums extends \IPS\Dispatcher\Controller
\IPS\Output::i()->output = (string) $table;
return;
}
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'forums_sg' ) ) ) ) ] = array( 'type' => 'forums_topic', 'nodes' => $forum->_id );
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_forums' ) ] = array( 'type' => 'forums_topic', 'nodes' => $forum->_id );
$forumOutput = '';
@@ -531,7 +547,7 @@ class _forums extends \IPS\Dispatcher\Controller
}
return NULL;
},
}
) ) );
if ( $values = $form->values() )
@@ -2,10 +2,10 @@
/**
* @brief index
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage
* @package IPS Community Suite
* @subpackage Forums
* @since 28 Jul 2014
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief Topic View
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 08 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -48,7 +48,6 @@ class _topic extends \IPS\Content\Controller
protected function manage()
{
/* Load topic */
\IPS\forums\Forum::loadIntoMemory();
$topic = parent::manage();
\IPS\Member::loggedIn()->language()->words['submit_comment'] = \IPS\Member::loggedIn()->language()->addToStack( 'submit_reply', FALSE );
@@ -75,7 +74,15 @@ class _topic extends \IPS\Content\Controller
if ( !$topic->canView() )
{
\IPS\Output::i()->error( $forum ? $forum->errorMessage() : 'node_error_no_perm', '2F173/H', 403, '' );
if ( $topic instanceof \IPS\Content\Hideable and $topic->hidden() )
{
/* If the item is hidden we don't want to show the custom no permission error as the conditions may not apply */
\IPS\Output::i()->error( 'node_error', '2F173/O', 404, '' );
}
else
{
\IPS\Output::i()->error( $forum ? $forum->errorMessage() : 'node_error_no_perm', '2F173/H', 403, '' );
}
}
}
catch ( \OutOfRangeException $e )
@@ -94,16 +101,36 @@ class _topic extends \IPS\Content\Controller
{
\IPS\Output::i()->redirect( $topic->url()->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->p ) ), NULL, 301 );
}
elseif ( \IPS\Request::i()->pid )
{
\IPS\Output::i()->redirect( $topic->url()->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->pid ) ), NULL, 301 );
}
if ( \IPS\Request::i()->view )
{
$this->_doViewCheck();
}
/* 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. */
if ( \IPS\Request::i()->isAjax() and ( !isset( \IPS\Request::i()->preview ) OR !\IPS\Request::i()->preview ) )
{
$topic->commentForm();
}
/* AJAX hover preview? */
if ( \IPS\Request::i()->isAjax() and \IPS\Request::i()->preview )
{
$firstPost = $topic->comments( 1 );
$postClass = '\IPS\forums\Topic\Post';
if( $topic->isArchived() )
{
$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 )
@@ -138,13 +165,7 @@ class _topic extends \IPS\Content\Controller
{
$poll->attach( $topic );
}
/* One for the brits */
if ( mb_strpos( $topic->title, base64_decode( 'c3BhbmlzaA==' ) ) !== FALSE and $topic->isQuestion() )
{
\IPS\Output::i()->output .= base64_decode( 'PCEtLSBOTyBPTkUgRVhQRUNUUyBUSEUgU1BBTklTSCBJTlFVSVNJVElPTiAtLT4=' );
}
/* How are we sorting posts? */
$question = NULL;
$offset = NULL;
@@ -153,9 +174,22 @@ class _topic extends \IPS\Content\Controller
$where = NULL;
if( \IPS\forums\Topic::modPermission( 'unhide', NULL, $topic->container() ) AND \IPS\Request::i()->queued_posts )
{
$where = 'queued=1';
if ( $topic->isArchived() )
{
$where = 'archive_queued=1';
}
else
{
$where = 'queued=1';
}
$queuedPagesCount = ceil( \IPS\Db::i()->select( 'COUNT(*)', 'forums_posts', array( 'topic_id=? AND queued=1', $topic->id ) )->first() / $topic->getCommentsPerPage() );
$pagination = ( $queuedPagesCount > 1 ) ? $topic->commentPagination( array( 'queued_posts', 'sortby' ), 'pagination', $queuedPagesCount ) : NULL;
if ( $topic->isQuestion() )
{
$question = $topic->comments( 1, 0 );
}
}
else
{
@@ -193,7 +227,7 @@ class _topic extends \IPS\Content\Controller
}
$pagination = ( $topic->commentPageCount() > 1 ) ? $topic->commentPagination( array( 'sortby' ) ) : NULL;
}
$comments = $topic->comments( NUll, $offset, $order, $orderDirection, NULL, NULL, NULL, $where );
$comments = $topic->comments( NULL, $offset, $order, $orderDirection, NULL, NULL, NULL, $where );
$current = current( $comments );
reset( $comments );
@@ -203,9 +237,8 @@ class _topic extends \IPS\Content\Controller
}
/* 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 = strip_tags( $topic->isQuestion() ? $question->post : $current->post );
\IPS\Output::i()->metaTags['description'] = \IPS\Output::i()->metaTags['og:description'] = ( mb_strlen( $metaDescription ) > 160 ? ( mb_substr( $metaDescription, 0, 157 ) . '...' ) : $metaDescription );
$metaDescription = $topic->isQuestion() ? $question->post : $current->post;
/* Did we request a specific post? If so, reset descriptions. */
if( isset( $_SESSION['_findComment'] ) )
{
@@ -216,10 +249,13 @@ class _topic extends \IPS\Content\Controller
{
$comment = \IPS\forums\Topic\Post::loadAndCheckPerms( $commentId );
\IPS\Output::i()->metaTags['description'] = \IPS\Output::i()->metaTags['og:description'] = strip_tags( $comment->content() );
$metaDescription = $comment->content();
}
catch( \Exception $e ){}
}
$metaDescription = strip_tags( $metaDescription );
\IPS\Output::i()->metaTags['description'] = \IPS\Output::i()->metaTags['og:description'] = mb_strlen( $metaDescription ) > 160 ? ( mb_substr( $metaDescription, 0, 157 ) . '...' ) : $metaDescription;
/* Mark read */
if( !$topic->isLastPage() )
@@ -338,23 +374,7 @@ class _topic extends \IPS\Content\Controller
}
}
$form = new \IPS\Helpers\Form( 'form', \IPS\Member::loggedIn()->language()->checkKeyExists( $class::$formLangPrefix . '_save' ) ? $class::$formLangPrefix . '_save' : 'save' );
$form->class = 'ipsForm_vertical';
if ( isset( $formElements['poll'] ) )
{
$form->addTab( $class::$formLangPrefix . 'mainTab' );
}
foreach( $formElements AS $k => $element )
{
if ( $k === 'poll' )
{
$form->addTab( $class::$formLangPrefix . 'pollTab' );
}
$form->add( $element );
}
$form = $topic->buildEditForm();
if ( $values = $form->values() )
{
@@ -363,7 +383,10 @@ class _topic extends \IPS\Content\Controller
$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 );
\IPS\Output::i()->redirect( $topic->url() );
}
else
@@ -404,6 +427,8 @@ class _topic extends \IPS\Content\Controller
*/
public function unarchive()
{
\IPS\Session::i()->csrfCheck();
try
{
$topic = \IPS\forums\Topic::loadAndCheckPerms( \IPS\Request::i()->id );
@@ -477,7 +502,7 @@ class _topic extends \IPS\Content\Controller
}
/* Rebuild count */
$question->question_rating = \IPS\Db::i()->select( 'SUM(rating)', 'forums_question_ratings', array( 'topic=?', $question->tid ) )->first();
$question->question_rating = \IPS\Db::i()->select( 'SUM(rating)', 'forums_question_ratings', array( 'topic=?', $question->tid ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$question->save();
/* Redirect back */
@@ -513,16 +538,25 @@ class _topic extends \IPS\Content\Controller
{
\IPS\Output::i()->error( 'form_bad_value', '2F173/6', 403, '' );
}
\IPS\Db::i()->insert( 'forums_answer_ratings', array(
'post' => $answer->pid,
'topic' => $question->tid,
'member' => \IPS\Member::loggedIn()->member_id,
'rating' => $rating,
'date' => time()
), TRUE );
$answer->post_field_int = \IPS\Db::i()->select( 'SUM(rating)', 'forums_answer_ratings', array( 'post=?', $answer->pid ) )->first();
/* 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 )
{
\IPS\Db::i()->insert( 'forums_answer_ratings', array(
'post' => $answer->pid,
'topic' => $question->tid,
'member' => \IPS\Member::loggedIn()->member_id,
'rating' => $rating,
'date' => time()
), TRUE );
}
$answer->post_field_int = (int) \IPS\Db::i()->select( 'SUM(rating)', 'forums_answer_ratings', array( 'post=?', $answer->pid ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$answer->save();
if ( \IPS\Request::i()->isAjax() )
@@ -2,9 +2,9 @@
/**
* @brief 4.0.0 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 30 Oct 2014
* @version SVN_VERSION_NUMBER
@@ -2,9 +2,9 @@
/**
* @brief 4.0.0 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 12 Dec 2014
* @version SVN_VERSION_NUMBER
@@ -40,10 +40,10 @@ class _Upgrade
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 2 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 2 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr ) ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr ) ) ) );
}
}
@@ -2,10 +2,10 @@
/**
* @brief 4.0.0 RC 1 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 3 Feb 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,10 @@
/**
* @brief 4.0.0 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 15 Jan 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,10 +2,10 @@
/**
* @brief 4.0.0 RC 5 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Blog
* @package IPS Community Suite
* @subpackage Forums
* @since 5 May 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief 4.0.0 RC6 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 18 Mar 2015
* @version SVN_VERSION_NUMBER
Whitespace-only changes.
@@ -2,10 +2,10 @@
/**
* @brief 4.0.5 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Blog
* @package IPS Community Suite
* @subpackage Forums
* @since 5 May 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief 4.0.7 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 27 May 2015
* @version SVN_VERSION_NUMBER
@@ -2,9 +2,10 @@
/**
* @brief 4.0.8 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 15 Jan 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,10 @@
/**
* @brief 4.0.9 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 19 Jun 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,10 @@
/**
* @brief 4.0.0 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 15 Jan 2015
* @version SVN_VERSION_NUMBER
*/
@@ -17,14 +17,10 @@
"method": "dropColumn",
"params": [
"forums_posts",
"use_sig"
]
},
"4": {
"method": "dropColumn",
"params": [
"forums_posts",
"use_emo"
[
"use_sig",
"use_emo"
]
]
}
}
@@ -1,107 +0,0 @@
<?php
/**
* @brief 4.1.0 Beta 10 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 22 Oct 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101009;
/* 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;
}
/**
* 4.1.0 Beta 10 Upgrade Code
*/
class _Upgrade
{
/**
* Step 1
* Fix the first post flagged for topics
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
$perCycle = 500;
$did = 0;
$limit = intval( \IPS\Request::i()->extra );
/* Try to prevent timeouts to the extent possible */
$cutOff = \IPS\core\Setup\Upgrade::determineCutoff();
foreach( \IPS\Db::i()->select( '*', 'forums_topics', array( 'topic_firstpost=?', 0 ), 'tid ASC', array( $limit, $perCycle ) ) as $topic )
{
if( $cutOff !== null AND time() >= $cutOff )
{
return ( $limit + $did );
}
$did++;
try
{
$firstPost = \IPS\Db::i()->select( 'pid', 'forums_posts', array( 'topic_id=?', $topic['tid'] ), 'post_date ASC', array( 1 ) )->first();
}
catch( \UnderflowException $e )
{
continue;
}
\IPS\Db::i()->update( 'forums_topics', array( 'topic_firstpost' => $firstPost ), 'tid=' . $topic['tid'] );
}
if( $did )
{
return ( $limit + $did );
}
else
{
unset( $_SESSION['_step1Count'] );
$toRun = \IPS\core\Setup\Upgrade::runManualQueries( array(
array(
'table' => 'forums_posts',
'query' => "UPDATE " . \IPS\Db::i()->prefix . "forums_posts SET new_topic=1 WHERE pid IN ( SELECT topic_firstpost FROM " . \IPS\Db::i()->prefix . "forums_topics )"
)
) );
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 2, '_upgradeData' => 0 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr ) ) ) );
}
return TRUE;
}
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
$limit = isset( \IPS\Request::i()->extra ) ? \IPS\Request::i()->extra : 0;
if( !isset( $_SESSION['_step1Count'] ) )
{
$_SESSION['_step1Count'] = \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics' )->first();
}
$message = "Fixing flagged first posts (Upgraded so far: " . ( ( $limit > $_SESSION['_step1Count'] ) ? $_SESSION['_step1Count'] : $limit ) . ' out of ' . $_SESSION['_step1Count'] . ')';
return $message;
}
}
@@ -2,9 +2,10 @@
/**
* @brief 4.1.2 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 29 Oct 2015
* @version SVN_VERSION_NUMBER
*/
@@ -0,0 +1,15 @@
{
"1": {
"method": "update",
"params": [
"forums_forums",
{
"sub_can_post": 0
},
[
"parent_id=?",
-1
]
]
}
}
@@ -10,9 +10,11 @@
"columns": [
"topic_id",
"queued",
"post_date"
"post_date",
"author_id"
],
"length": [
null,
null,
null,
null
@@ -1,15 +1,16 @@
<?php
/**
* @brief 4.0.12 Upgrade Code
* @brief 4.1.4 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 21 Jul 2015
* @package IPS Community Suite
* @subpackage Forums
* @since 06 Nov 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_100042;
namespace IPS\forums\setup\upg_101016;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
@@ -19,28 +20,32 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
}
/**
* 4.0.12 Upgrade Code
* 4.1.4 Upgrade Code
*/
class _Upgrade
{
/**
* Fix new_topic flag if it is incorrectly set from an older version
* Fixing incorrectly hidden posts
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
$toRun = \IPS\core\Setup\Upgrade::runManualQueries( array( array(
'table' => 'forums_posts',
'query' => "UPDATE " . \IPS\Db::i()->prefix . "forums_posts SET new_topic=0 WHERE new_topic=1 AND pid NOT IN( SELECT topic_firstpost FROM " . \IPS\Db::i()->prefix . "forums_topics)"
) ) );
$toRunQueries = array(
array(
'table' => 'forums_posts',
'query' => "UPDATE " . \IPS\Db::i()->prefix . "forums_posts SET queued=0 WHERE (queued=2 AND topic_id IN( SELECT tid FROM " . \IPS\Db::i()->prefix . "forums_topics WHERE approved=1 ) )",
)
);
$toRun = \IPS\core\Setup\Upgrade::runManualQueries( $toRunQueries );
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 2, '_upgradeData' => 0 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 'extra' => array( '_upgradeStep' => 2 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr ) ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr ) ) ) );
}
return TRUE;
@@ -53,6 +58,6 @@ class _Upgrade
*/
public function step1CustomTitle()
{
return "Fixing flagged first posts";
return "Fixing incorrectly hidden posts";
}
}
@@ -0,0 +1,94 @@
<?php
/**
* @brief 4.1.5 Upgrade Code
* @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
* @subpackage Forums
* @since 23 Nov 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101018;
/* 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;
}
/**
* 4.1.5 Upgrade Code
*/
class _Upgrade
{
/**
* Find forums where the parent/child mapping creates an infinite loop
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
$count = \IPS\Db::i()->select( 'COUNT(*)', array( 'forums_forums', 'f1' ), 'f1.parent_id=f2.id' )->join( array( 'forums_forums', 'f2' ), 'f1.id=f2.parent_id' )->first();
if( $count )
{
/* Create a new category */
$category = new \IPS\forums\Forum;
$category->parent_id = -1;
$category->forum_parent_id = 0;
$category->forum_min_posts_view = 0;
$category->forum_can_view_others = 1;
$category->forum_sort_key = 'last_post';
$category->forum_permission_showtopic = 0;
$category->save();
\IPS\Lang::saveCustom( 'forums', 'forums_forums_' . $category->id, "Temporary Category" );
foreach( \IPS\Db::i()->select( 'f1.*', array( 'forums_forums', 'f1' ), 'f1.parent_id=f2.id' )->join( array( 'forums_forums', 'f2' ), 'f1.id=f2.parent_id' ) as $forum )
{
\IPS\Db::i()->update( 'forums_forums', array( 'parent_id' => $category->id ), array( 'id=?', $forum['id'] ) );
}
$category->setLastComment();
$category->save();
}
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Fixing incorrectly mapped forums";
}
/**
* Fix container counts that may be off due to bug with unapproved topics
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step2()
{
\IPS\Task::queue( 'core', 'RebuildContainerCounts', array( 'class' => 'IPS\forums\Forum', 'count' => 0 ), 5, array( 'class' ) );
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step2CustomTitle()
{
return "Rebuilding forum post counts";
}
}
@@ -0,0 +1,48 @@
<?php
/**
* @brief 4.1.7 Upgrade Code
* @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
* @subpackage Forums
* @since 04 Jan 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101023;
/* 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;
}
/**
* 4.1.7 Upgrade Code
*/
class _Upgrade
{
/**
* Trigger background task
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\Task::queue( 'forums', 'TopicStarterIds', array(), 4 );
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Updating topic starter IDs";
}
}
@@ -0,0 +1,15 @@
{
"1": {
"method": "update",
"params": [
"forums_forums",
{
"ipseo_priority": "-1"
},
[
"ipseo_priority=?",
""
]
]
}
}
@@ -0,0 +1,48 @@
<?php
/**
* @brief 4.1.7 Upgrade Code
* @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
* @subpackage Forums
* @since 04 Jan 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101026;
/* 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;
}
/**
* 4.1.9 Upgrade Code
*/
class _Upgrade
{
/**
* Trigger background task
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\Task::queue( 'forums', 'HiddenFirstPost', array(), 4 );
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Updating incorrectly hidden topics";
}
}
@@ -0,0 +1,37 @@
<?php
/**
* @brief 4.1.10 Upgrade Code
* @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
{subpackage}
* @since 12 Apr 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101027;
/* 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;
}
/**
* 4.1.10 Upgrade Code
*/
class _Upgrade
{
/**
* Rebuild container counts
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\Task::queue( 'core', 'RebuildContainerCounts', array( 'class' => 'IPS\forums\Forum', 'count' => 0 ), 5, array( 'class' ) );
return TRUE;
}
}
@@ -0,0 +1,48 @@
<?php
/**
* @brief 4.1.11 Upgrade Code
* @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
{subpackage}
* @since 12 Apr 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101028;
/* 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;
}
/**
* 4.1.11 Upgrade Code
*/
class _Upgrade
{
/**
* ...
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\Task::queue( 'forums', 'RebuildNewTopicFlag', array(), 4 );
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Fixing first posts";
}
}
@@ -0,0 +1,22 @@
{
"1": {
"method": "addIndex",
"params": [
"forums_topics",
{
"type": "key",
"name": "last_true_post",
"columns": [
"forum_id",
"pinned",
"last_post"
],
"length": [
null,
null,
null
]
}
]
}
}
@@ -0,0 +1,38 @@
<?php
/**
* @brief 4.1.14 Upgrade Code
* @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
* @subpackage Forums
* @since 07 Jul 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101042;
/* 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;
}
/**
* 4.1.14 Upgrade Code
*/
class _Upgrade
{
/**
* Recount categories in case pending topics/posts count is off
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function finish()
{
\IPS\Task::queue( 'core', 'RebuildContainerCounts', array( 'class' => 'IPS\forums\Forum', 'count' => 0 ), 5, array( 'class' ) );
return TRUE;
}
}
@@ -0,0 +1,39 @@
{
"1": {
"method": "addIndex",
"params": [
"forums_archive_posts",
{
"type": "key",
"name": "archive_forum_id",
"columns": [
"archive_forum_id"
],
"length": [
null
]
}
]
},
"2": {
"method": "changeColumn",
"params": [
"forums_topics",
"last_post",
{
"name": "last_post",
"type": "INT",
"length": 10,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
}
}
@@ -0,0 +1,14 @@
{
"1": {
"method": "delete",
"params": [
"forums_archive_rules",
[
"archive_app=? AND archive_field=? AND archive_text=?",
"forums",
"member",
""
]
]
}
}
@@ -0,0 +1,82 @@
<?php
/**
* @brief 4.1.19 Beta 1 Upgrade Code
* @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
* @subpackage Forums
* @since 27 Jan 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\setup\upg_101090;
/* 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;
}
/**
* 4.1.19 Beta 1 Upgrade Code
*/
class _Upgrade
{
/**
* Add index to forums_archive_posts (taking into account it may be in a remote database)
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
/* If we already have an index on the ip address AND the queued column, we can just move along. */
if( \IPS\forums\Topic\ArchivedPost::db()->checkForIndex( 'forums_archive_posts', 'archive_ip_address' ) AND
\IPS\forums\Topic\ArchivedPost::db()->checkForIndex( 'forums_archive_posts', 'archive_queued' ) )
{
return TRUE;
}
/* Get the query that needs to be ran */
$missingIndexes = array();
if( !\IPS\forums\Topic\ArchivedPost::db()->checkForIndex( 'forums_archive_posts', 'archive_ip_address' ) )
{
$missingIndexes[] = \IPS\forums\Topic\ArchivedPost::db()->buildIndex( 'forums_archive_posts', array( 'type' => 'key', 'name' => 'archive_ip_address', 'columns' => array( 'archive_ip_address' ) ) );
}
if( !\IPS\forums\Topic\ArchivedPost::db()->checkForIndex( 'forums_archive_posts', 'archive_queued' ) )
{
$missingIndexes[] = \IPS\forums\Topic\ArchivedPost::db()->buildIndex( 'forums_archive_posts', array( 'type' => 'key', 'name' => 'archive_queued', 'columns' => array( 'archive_queued', 'archive_content_date' ) ) );
}
$query = "ALTER TABLE `" . \IPS\forums\Topic\ArchivedPost::db()->prefix . \IPS\forums\Topic\ArchivedPost::db()->escape_string( 'forums_archive_posts' ) . "` " . implode( ', ', $missingIndexes );
$toRun = \IPS\core\Setup\Upgrade::runManualQueries( array( array(
'table' => 'forums_archive_posts',
'query' => $query,
'db' => \IPS\forums\Topic\ArchivedPost::db()
) ) );
if ( count( $toRun ) )
{
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 2, '_upgradeData' => 0 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr ) ) ) );
}
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Updating archived posts table for performance";
}
}
@@ -2,9 +2,10 @@
/**
* @brief Upgrader: Custom Upgrade Options
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Forums
* @since 5 Jun 2014
* @version SVN_VERSION_NUMBER
*/
@@ -468,6 +468,16 @@
]
},
"18": {
"method": "update",
"params": [
"forums_forums",
{
"topics": 0
},
"topics IS NULL"
]
},
"19": {
"method": "changeColumn",
"params": [
"forums_forums",
@@ -488,7 +498,7 @@
}
]
},
"19": {
"20": {
"method": "changeColumn",
"params": [
"forums_forums",
@@ -509,7 +519,7 @@
}
]
},
"20": {
"21": {
"method": "changeIndex",
"params": [
"forums_forums",
@@ -527,5 +537,31 @@
]
}
]
},
"22": {
"method": "update",
"params": [
"core_sys_conf_settings",
{
"conf_key": "forums_topics_per_page"
},
[
"conf_key=?",
"display_max_topics"
]
]
},
"23": {
"method": "update",
"params": [
"core_sys_conf_settings",
{
"conf_key": "forums_posts_per_page"
},
[
"conf_key=?",
"display_max_posts"
]
]
}
}
+19 -15
View File
@@ -2,10 +2,10 @@
/**
* @brief 4.0.0 Alpha 1 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 15 Jan 2015
* @version SVN_VERSION_NUMBER
*/
@@ -273,13 +273,14 @@ class _Upgrade
$dropLastPost = \IPS\Db::i()->checkForIndex( 'forums_topics', 'last_post' ) ? "DROP INDEX last_post," : '';
$dropLastPostSorting = \IPS\Db::i()->checkForIndex( 'forums_topics', 'last_post_sorting' ) ? ",\nDROP INDEX last_post_sorting" : '';
$dropHasAttach = \IPS\Db::i()->checkForColumn( 'forums_topics', 'topic_hasattach' ) ? "DROP COLUMN topic_hasattach," : '';
$dropHasTDelete = \IPS\Db::i()->checkForColumn( 'forums_topics', 'tdelete_time' ) ? "DROP COLUMN tdelete_time," : '';
$toRun = \IPS\core\Setup\Upgrade::runManualQueries( array( array(
'table' => 'forums_topics',
'query' => "ALTER TABLE " . \IPS\Db::i()->prefix . "forums_topics {$description}
{$dropHasAttach}
DROP COLUMN topic_deleted_posts,
DROP COLUMN tdelete_time,
{$dropHasTDelete}
DROP COLUMN seo_last_name,
DROP COLUMN seo_first_name,
ADD COLUMN popular_time INT(10) NULL DEFAULT NULL COMMENT 'Timestamp of when this topic will stop being popular.',
@@ -293,15 +294,15 @@ ADD INDEX last_post (forum_id, pinned, last_real_post, state)
),
array(
'table' => 'forums_topics',
'query' => "UPDATE " . \IPS\Db::i()->prefix . "forums_topics SET posts=posts+1, last_real_post=last_post"
'query' => "UPDATE " . \IPS\Db::i()->prefix . "forums_topics SET posts=posts+1, last_real_post=IFNULL(last_post,0)"
) ) );
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 5, '_upgradeData' => 0 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 5, '_upgradeData' => 0 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr ) ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr ) ) ) );
}
return TRUE;
@@ -402,10 +403,10 @@ ADD INDEX last_post (forum_id, pinned, last_real_post, state)
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 8 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 8 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr, 'extra' => 0 ) ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr, 'extra' => 0 ) ) ) );
}
return TRUE;
@@ -461,9 +462,9 @@ ADD INDEX last_post (forum_id, pinned, last_real_post, state)
if ( !\IPS\Request::i()->run_anyway and $archiveDb->select( 'count(*)', 'forums_archive_posts' )->first() > \IPS\UPGRADE_MANUAL_THRESHOLD )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 9 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 9 ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( array( $query ), \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr, 'extra' => 0 ) ), "You must run this query against your archive database, <strong>{$INFO['archive_remote_sql_database']}</strong> on {$INFO['archive_remote_sql_host']}, <strong>NOT</strong> the normal community database." ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( array( $query ), \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr, 'extra' => 0 ) ), "You must run this query against your archive database, <strong>{$INFO['archive_remote_sql_database']}</strong> on {$INFO['archive_remote_sql_host']}, <strong>NOT</strong> the normal community database." ) );
}
else
{
@@ -518,10 +519,10 @@ ADD INDEX last_post (forum_id, pinned, last_real_post, state)
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 10 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 10 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr, 'extra' => 0 ) ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr, 'extra' => 0 ) ) ) );
}
}
@@ -559,10 +560,10 @@ ADD INDEX last_post (forum_id, pinned, last_real_post, state)
if ( count( $toRun ) )
{
$mr = \IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 11 ) ) );
\IPS\core\Setup\Upgrade::adjustMultipleRedirect( array( 1 => 'forums', 'extra' => array( '_upgradeStep' => 11 ) ) );
/* Queries to run manually */
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => $mr, 'extra' => 0 ) ) ) );
return array( 'html' => \IPS\Theme::i()->getTemplate( 'forms' )->queries( $toRun, \IPS\Http\Url::internal( 'controller=upgrade' )->setQueryString( array( 'key' => $_SESSION['uniqueKey'], 'mr_continue' => 1, 'mr' => \IPS\Request::i()->mr, 'extra' => 0 ) ) ) );
}
return TRUE;
@@ -586,6 +587,9 @@ ADD INDEX last_post (forum_id, pinned, last_real_post, state)
*/
public function finish()
{
/* Fix bbcode links for RSS feed 'full article' */
\IPS\Db::i()->update( 'forums_rss_import', array( "rss_import_showlink" => 'View the full article' ) );
\IPS\Task::queue( 'core', 'RebuildPosts', array( 'class' => 'IPS\forums\Topic' ), 2 );
\IPS\Task::queue( 'core', 'RebuildPosts', array( 'class' => 'IPS\forums\Topic\Post' ), 2 );
\IPS\Task::queue( 'core', 'RebuildPosts', array( 'class' => 'IPS\forums\Topic\ArchivedPost' ), 2 );
+23 -9
View File
@@ -2,10 +2,10 @@
/**
* @brief Feed Import Node
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 4 Fed 2014
* @version SVN_VERSION_NUMBER
*/
@@ -107,7 +107,7 @@ class _Feed extends \IPS\Node\Model
{
if ( $enabled )
{
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( '`key`=?', 'rssimport' ) );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), array( '`key`=?', 'rssimport' ) );
}
$this->enabled = $enabled;
}
@@ -254,6 +254,12 @@ class _Feed extends \IPS\Node\Model
*/
public function run()
{
/* Skip this if the member is restricted from posting */
if( \IPS\Member::load( $this->mid )->restrict_post or \IPS\Member::load( $this->mid )->members_bitoptions['unacknowledged_warnings'] )
{
return;
}
$previouslyImportedGuids = iterator_to_array( \IPS\Db::i()->select( 'rss_imported_guid', 'forums_rss_imported', array( 'rss_imported_impid=?', $this->id ) ) );
$request = \IPS\Http\Url::external( $this->url )->request();
@@ -269,11 +275,11 @@ class _Feed extends \IPS\Node\Model
$inserts = array();
$request = $request->decodeXml();
if( !in_array( $request->getname(), array( 'feed', 'rss' ) ) )
if( !( $request instanceof \IPS\Xml\RssOne ) AND !( $request instanceof \IPS\Xml\Rss ) AND !( $request instanceof \IPS\Xml\Atom ) )
{
throw new \RuntimeException( 'rss_import_invalid' );
}
foreach ( $request->articles( $this->id ) as $guid => $article )
{
if ( !in_array( $guid, $previouslyImportedGuids ) )
@@ -293,8 +299,16 @@ class _Feed extends \IPS\Node\Model
if ( $article['link'] and $this->showlink )
{
$rel = array();
$rel['nofollow'] = \IPS\Settings::i()->posts_add_nofollow ? "nofollow" : FALSE;
$rel['external'] = \IPS\Settings::i()->links_external ? "external" : FALSE;
if( \IPS\Settings::i()->posts_add_nofollow )
{
$rel['nofollow'] = 'nofollow';
}
if( \IPS\Settings::i()->links_external )
{
$rel['external'] = 'external';
}
$linkRelPart = '';
if ( count ( $rel ) )
@@ -306,7 +320,7 @@ class _Feed extends \IPS\Node\Model
}
$member = \IPS\Member::load( $this->mid );
$content = \IPS\Text\Parser::parseStatic( $article['content'] . $readMoreLink, FALSE, NULL, $member, 'forums_Forums', TRUE, !(bool) $member->group['g_dohtml'] );
$content = \IPS\Text\Parser::parseStatic( $article['content'] . $readMoreLink, TRUE, NULL, $member, 'forums_Forums', TRUE, !(bool) $member->group['g_dohtml'] );
$post = \IPS\forums\Topic\Post::create( $topic, $content, TRUE, NULL, \IPS\forums\Topic\Post::incrementPostCount( $container ), $member, $article['date'] );
$topic->topic_firstpost = $post->pid;
+265 -38
View File
@@ -2,10 +2,10 @@
/**
* @brief Forum Node
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 7 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -143,6 +143,20 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
*/
public static $icon = 'comments';
/**
* Callback from \IPS\Http\Url\Inernal::correctUrlFromVerifyClass()
*
* This is called when verifying the *the URL currently being viewed* is correct, before calling self::loadFromUrl()
* Can be used if there is a more effecient way to load and cache the objects that will be used later on that page
*
* @param \IPS\Http\Url $url The URL of the page being viewed, which belongs to this class
* @return void
*/
public static function preCorrectUrlFromVerifyClass( \IPS\Http\Url $url )
{
static::loadIntoMemory();
}
/**
* Form fields prefix with "forum_" but the database columns do not have this prefix - let's strip for the massChange feature
*
@@ -162,6 +176,24 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
parent::__set( $k, $v );
}
/**
* When setting parent ID to -1 (category) make sure sub_can_post is toggled off too
*
* @param int $val Parent ID
* @return void
*/
protected function set_parent_id( $val )
{
$this->_data['parent_id'] = $val;
$this->changed['parent_id'] = $val;
/* sub_can_post should get set to 0 for a category */
if( $val == -1 )
{
$this->sub_can_post = 0;
}
}
/**
* Get SEO name
*
@@ -171,11 +203,11 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
{
if( !$this->_data['name_seo'] )
{
$this->name_seo = \IPS\Http\Url::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'forums_forum_' . $this->id ) );
$this->name_seo = \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'forums_forum_' . $this->id ) );
$this->save();
}
return $this->_data['name_seo'] ?: \IPS\Http\Url::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'forums_forum_' . $this->id ) );
return $this->_data['name_seo'] ?: \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'forums_forum_' . $this->id ) );
}
/**
@@ -292,13 +324,27 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
/* We prefer fetching post, joining topic, etc. but that is not efficient and causes a temp table and filesort against posts table so we'll lean on the cached last_post value for the topic */
$select = \IPS\Db::i()->select( '*', 'forums_topics', array( "forums_topics.forum_id=? AND forums_topics.approved=1 AND forums_topics.state != ?", $this->id, 'link' ), 'forums_topics.last_post DESC', 1 )->first();
$topic = \IPS\forums\Topic::constructFromData( $select );
if ( $topic->last_poster_id and ! $topic->last_poster_name )
{
$member = \IPS\Member::load( $topic->last_poster_id );
if ( $member->member_id )
{
$topic->last_poster_name = $member->name;
}
else
{
$topic->last_poster_name = '';
$topic->last_poster_id = 0;
}
}
$this->last_post = $topic->last_post;
$this->last_poster_id = (int) $topic->last_poster_id;
$this->last_poster_name = $topic->last_poster_name;
$this->seo_last_name = \IPS\Http\Url::seoTitle( $this->last_poster_name );
$this->seo_last_name = \IPS\Http\Url\Friendly::seoTitle( $this->last_poster_name );
$this->last_title = $topic->title;
$this->seo_last_title = \IPS\Http\Url::seoTitle( $this->last_title );
$this->seo_last_title = \IPS\Http\Url\Friendly::seoTitle( $this->last_title );
$this->last_id = $topic->tid;
return;
}
@@ -316,9 +362,9 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
$this->last_post = $comment->mapped('date');
$this->last_poster_id = (int) $comment->author()->member_id;
$this->last_poster_name = $comment->author()->member_id ? $comment->author()->name : $comment->mapped('author_name');
$this->seo_last_name = \IPS\Http\Url::seoTitle( $this->last_poster_name );
$this->seo_last_name = \IPS\Http\Url\Friendly::seoTitle( $this->last_poster_name );
$this->last_title = $comment->item()->title;
$this->seo_last_title = \IPS\Http\Url::seoTitle( $this->last_title );
$this->seo_last_title = \IPS\Http\Url\Friendly::seoTitle( $this->last_title );
$this->last_id = $comment->item()->tid;
}
@@ -370,28 +416,41 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
*/
public function lastPost()
{
/* If this is a forum where users cannot see other user's posts, and the user is not a moderator
who can override that, we'll show the last post that was created by the user */
$fetchLastPostFromUser = FALSE;
/* This forum does not allow you to see topics from other users... */
if( !$this->can_view_others )
{
/* If we do not have the 'can_read_all_topics' permission, then it doesn't matter what forums we can moderate - we can't see
other users posts */
if( !\IPS\Member::loggedIn()->modPermission( 'can_read_all_topics' ) )
{
$fetchLastPostFromUser = TRUE;
}
/* If we hit the else statement, we do have moderator permissions to read all topics, so now we have to see if we can
moderate in this forum */
else
{
/* If we are not a moderator of all forums... */
if( \IPS\Member::loggedIn()->modPermission( 'forums' ) !== -1 AND \IPS\Member::loggedIn()->modPermission( 'forums' ) !== TRUE )
{
/* If we cannot moderate in this forum, we need to fetch our last post */
if( !is_array( \IPS\Member::loggedIn()->modPermission( 'forums' ) ) OR
!in_array( $this->_id, \IPS\Member::loggedIn()->modPermission( 'forums' ) ) )
{
$fetchLastPostFromUser = TRUE;
}
}
}
}
if ( !$this->loggedInMemberHasPasswordAccess() )
{
return NULL;
}
elseif
(
!$this->can_view_others
and
(
!(
\IPS\Member::loggedIn()->modPermission( 'forums' ) === -1
or
(
is_array( \IPS\Member::loggedIn()->modPermission( 'forums' ) )
and
in_array( $this->_id, \IPS\Member::loggedIn()->modPermission( 'forums' ) )
)
)
and
!\IPS\Member::loggedIn()->modPermission( 'can_read_all_topics' )
)
)
elseif ( $fetchLastPostFromUser )
{
try
{
@@ -420,7 +479,7 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
return $result;
}
elseif ( !$this->permission_showtopic and !$this->can('read') )
elseif ( !$this->permission_showtopic and !$this->can('view') )
{
$return = NULL;
@@ -475,7 +534,12 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
$result = $childLastPost;
}
}
if ( $this->sub_can_post and !$this->permission_showtopic and !$this->can('read') AND !is_null( $result ) )
{
$result['topic_title'] = NULL;
}
return $result;
}
}
@@ -526,7 +590,7 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
return TRUE;
}
if ( isset( \IPS\Request::i()->cookie[ 'ipbforumpass_' . $this->id ] ) and md5( $this->password ) === \IPS\Request::i()->cookie[ 'ipbforumpass_' . $this->id ] )
if ( isset( \IPS\Request::i()->cookie[ 'ipbforumpass_' . $this->id ] ) and \IPS\Login::compareHashes( md5( $this->password ), \IPS\Request::i()->cookie[ 'ipbforumpass_' . $this->id ] ) )
{
return TRUE;
}
@@ -642,7 +706,7 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
$where[] = array( 'min_posts_view<=?', $member->member_posts );
if ( !$member->member_id )
{
$where[] = array( 'sub_can_post=0 OR can_view_others=1' );
$where[] = array( '(sub_can_post=0 OR can_view_others=1)' );
}
}
@@ -815,10 +879,13 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
'forum_permission_custom_error',
"form_{$id}_header_permissions",
"form_{$id}_tab_forum_display",
'forum_allow_rating',
'forum_disable_sharelinks',
"form_{$id}_tab_posting_settings",
"form_{$id}_header_forum_display_topic",
'forum_preview_posts',
'forum_icon',
'forum_sort_key'
),
'qa' => array(
'forum_password_on',
@@ -830,6 +897,8 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
'forum_permission_custom_error',
"form_{$id}_header_permissions",
"form_{$id}_tab_forum_display",
'forum_allow_rating',
'forum_disable_sharelinks',
"form_{$id}_tab_posting_settings",
"form_{$id}_header_forum_display_question",
'forum_can_view_others_qa',
@@ -838,6 +907,12 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
'forum_qa_rate_answers',
'forum_preview_posts_qa',
'forum_icon',
'forum_sort_key_qa'
),
'category' => array(
"form_{$id}_tab_forum_display",
'forum_rules_title',
'forum_rules_text'
),
'redirect' => array(
'forum_password_on',
@@ -914,14 +989,19 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
$form->add( new \IPS\Helpers\Form\Number( 'forum_min_posts_view', $this->id ? $this->min_posts_view : 0, FALSE, array( 'unlimited' => 0, 'unlimitedLang' => 'no_restriction' ), NULL, NULL, \IPS\Member::loggedIn()->language()->addToStack('approved_posts_comments'), 'forum_min_posts_view' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'forum_can_view_others', $this->id ? $this->can_view_others : TRUE, FALSE, array(), NULL, NULL, NULL, 'forum_can_view_others' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'forum_can_view_others_qa', $this->id ? $this->can_view_others : TRUE, FALSE, array(), NULL, NULL, NULL, 'forum_can_view_others_qa' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'forum_permission_showtopic', $this->permission_showtopic, FALSE, array(), NULL, NULL, NULL, 'forum_permission_showtopic' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'forum_permission_showtopic_qa', $this->permission_showtopic, FALSE, array(), NULL, NULL, NULL, 'forum_permission_showtopic_qa' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'forum_permission_showtopic', $this->permission_showtopic ?: 0, FALSE, array(), NULL, NULL, NULL, 'forum_permission_showtopic' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'forum_permission_showtopic_qa', $this->permission_showtopic ?: 0, FALSE, array(), NULL, NULL, NULL, 'forum_permission_showtopic_qa' ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'forum_permission_custom_error', NULL, FALSE, array( 'app' => 'forums', 'key' => ( $this->id ? "forums_forum_{$this->id}_permerror" : NULL ), 'editor' => array( 'app' => 'forums', 'key' => 'Forums', 'autoSaveKey' => ( $this->id ? "forums-permerror-{$this->id}" : "forums-new-permerror" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'permerror' ) : NULL, 'minimize' => 'forum_permerror_placeholder' ) ), NULL, NULL, NULL, 'forum_permission_custom_error' ) );
$form->addTab( 'forum_display' );
$form->addHeader( 'forum_display_forum' );
$sortOptions = array( 'last_post' => 'sort_updated', 'last_real_post' => 'sort_last_comment', 'posts' => 'sort_num_comments', 'views' => 'sort_views', 'title' => 'sort_title', 'starter_name' => 'sort_author_name', 'last_poster_name' => 'sort_last_comment_name', 'start_date' => 'sort_date' );
$sortOptionsQA = array( 'question_rating' => 'sort_question_rating' );
$form->add( new \IPS\Helpers\Form\Select( 'forum_sort_key', $this->id ? $this->sort_key : 'last_post', FALSE, array( 'options' => $sortOptions ), NULL, NULL, NULL, 'forum_sort_key' ) );
$form->add( new \IPS\Helpers\Form\Select( 'forum_sort_key_qa', $this->id ? $this->sort_key : 'last_post', FALSE, array( 'options' => array_merge( $sortOptions, $sortOptionsQA ) ), NULL, NULL, NULL, 'forum_sort_key_qa' ) );
$form->add( new \IPS\Helpers\Form\Select( 'forum_sort_key', $this->id ? $this->sort_key : 'last_post', FALSE, array( 'options' => array( 'last_post' => 'sort_updated', 'last_real_post' => 'sort_last_comment', 'posts' => 'sort_num_comments', 'views' => 'sort_views', 'title' => 'sort_title', 'starter_name' => 'sort_author_name', 'last_poster_name' => 'sort_last_comment_name', 'start_date' => 'sort_date' ) ), NULL, NULL, NULL, 'forum_sort_key' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'forum_show_rules', $this->id ? $this->show_rules : 0, FALSE, array(
'options' => array(
0 => 'forum_show_rules_none',
@@ -1033,6 +1113,7 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
$values['forum_preview_posts'] = $values['forum_preview_posts_qa'];
$values['forum_can_view_others'] = $values['forum_can_view_others_qa'];
$values['forum_permission_showtopic'] = $values['forum_permission_showtopic_qa'];
$values['forum_sort_key'] = $values['forum_sort_key_qa'];
}
else
{
@@ -1048,6 +1129,7 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
unset( $values['forum_can_view_others_qa'] );
unset( $values['forum_permission_showtopic_qa'] );
unset( $values['forum_preview_posts_qa'] );
unset( $values['forum_sort_key_qa'] );
}
if ( isset( $values['forum_parent_id'] ) )
@@ -1101,6 +1183,13 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$values['password'] = NULL;
}
/* Reset password and can view others if toggling back to a category */
if( in_array( $values['type'], array( 'category', 'redirect' ) ) )
{
$values['password'] = NULL;
$values['can_view_others'] = TRUE;
}
/* Reverse */
if( isset( $values['disable_sharelinks'] ) )
@@ -1136,13 +1225,13 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
foreach ( array( 'name' => "forums_forum_{$this->id}", 'description' => "forums_forum_{$this->id}_desc", 'rules_title' => "forums_forum_{$this->id}_rulestitle", 'rules_text' => "forums_forum_{$this->id}_rules", 'permission_custom_error' => "forums_forum_{$this->id}_permerror" ) as $fieldKey => $langKey )
{
if ( isset( $values[ $fieldKey ] ) )
if ( array_key_exists( $fieldKey, $values ) )
{
\IPS\Lang::saveCustom( 'forums', $langKey, $values[ $fieldKey ] );
if ( $fieldKey === 'name' )
{
$this->name_seo = \IPS\Http\Url::seoTitle( $values[ $fieldKey ][ \IPS\Lang::defaultLanguage() ] );
$this->name_seo = \IPS\Http\Url\Friendly::seoTitle( $values[ $fieldKey ][ \IPS\Lang::defaultLanguage() ] );
$this->save();
}
@@ -1158,6 +1247,13 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
unset( $values[ $k ] );
}
}
/* Update index */
if( $this->can_view_others !== NULL and isset( $values['can_view_others'] ) and $values['can_view_others'] != $this->can_view_others )
{
$this->can_view_others = $values['can_view_others'];
$this->updateSearchIndexPermissions();
}
return $values;
}
@@ -1217,6 +1313,13 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
public function delete()
{
\IPS\File::unclaimAttachments( 'forums_Forums', $this->id );
try
{
\IPS\File::get( 'forums_Icons', $this->icon )->delete();
}
catch( \Exception $ex ) { }
parent::delete();
foreach ( array( 'rules_title' => "forums_forum_{$this->id}_rulestitle", 'rules_text' => "forums_forum_{$this->id}_rules", 'permission_custom_error' => "forums_forum_{$this->id}_permerror" ) as $fieldKey => $langKey )
@@ -1346,6 +1449,62 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
return $result;
}
/**
* Get which permission keys can access all topics in a forum which
* can normally only show topics to the author
*
* @return array
*/
public function permissionsThatCanAccessAllTopics()
{
$normal = $this->searchIndexPermissions();
$return = array();
$members = array();
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $moderator )
{
if ( $moderator['perms'] === '*' or in_array( 'can_read_all_topics', explode( ',', $moderator['perms'] ) ) )
{
if( $moderator['type'] === 'g' )
{
$return[] = $moderator['id'];
}
else
{
$members[] = "m{$moderator['id']}";
}
}
}
$return = ( $normal == '*' ) ? array_unique( $return ) : array_intersect( explode( ',', $normal ), array_unique( $return ) );
if( count( $members ) )
{
$return = array_merge( $return, $members );
}
return $return;
}
/**
* Update search index permissions
*
* @return void
*/
protected function updateSearchIndexPermissions()
{
if ( $this->can_view_others )
{
return parent::updateSearchIndexPermissions();
}
else
{
$permissions = implode( ',', $this->permissionsThatCanAccessAllTopics() );
\IPS\Content\Search\Index::i()->massUpdate( 'IPS\forums\Topic', $this->_id, NULL, $permissions, NULL, NULL, NULL, NULL, NULL, TRUE );
\IPS\Content\Search\Index::i()->massUpdate( 'IPS\forums\Topic\Post', $this->_id, NULL, $permissions, NULL, NULL, NULL, NULL, NULL, TRUE );
}
}
/**
* Mass move content items in this node to another node
*
@@ -1477,7 +1636,10 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
\IPS\Widget::deleteCaches( NULL, static::$permApp );
/* Log */
\IPS\Session::i()->modLog( 'modlog__action_massmove', array( $contentItemClass::$title . '_pl_lc' => TRUE, $node->url()->__toString() => FALSE, $node->_title => FALSE ) );
if ( \IPS\Dispatcher::hasInstance() )
{
\IPS\Session::i()->modLog( 'modlog__action_massmove', array( $contentItemClass::$title . '_pl_lc' => TRUE, $node->url()->__toString() => FALSE, $node->_title => FALSE ) );
}
return NULL;
}
@@ -1512,11 +1674,76 @@ class _Forum extends \IPS\Node\Model implements \IPS\Node\Permissions
$disabled = array();
$guestGroup = \IPS\Member\Group::load( \IPS\Settings::i()->guest_group );
if( !$this->can_view_others )
if( $this->sub_can_post and !$this->can_view_others )
{
$disabled[ $guestGroup->g_id ][] = 'view';
}
return $disabled;
}
/**
* The permission key or function used when building a node selector
* in search or stream functions.
*
* @return string|callable function
*/
public static function searchableNodesPermission()
{
return function( $node )
{
if ( $node->can( 'view' ) and $node->sub_can_post )
{
return TRUE;
}
return FALSE;
};
}
/**
* @brief Cached unsearchable node ids
*/
protected static $unsearchableNodeIds = FALSE;
/**
* Return either NULL for no restrictions, or a list of container IDs we cannot search in because of app specific permissions and configuration
* You do not need to check for 'view' permissions against the logged in member here. The Query search class does this for you.
* This method is intended for more complex set up items, like needing to have X posts to see a forum, etc.
* This is used for search and the activity stream.
* We return a list of IDs and not node objects for memory efficiency.
*
* return null|array
*/
public static function unsearchableNodeIds()
{
if( static::$unsearchableNodeIds !== FALSE )
{
return static::$unsearchableNodeIds;
}
/* For memory efficiency, we query the database directly rather than manage nodes */
$forums = iterator_to_array( \IPS\Db::i()->select( 'id', 'forums_forums', array( 'min_posts_view > ?', \IPS\Member::loggedIn()->member_posts ) )->setKeyField('id') );
static::$unsearchableNodeIds = count( $forums ) ? $forums : NULL;
return static::$unsearchableNodeIds;
}
/**
* Get output for API
*
* @return array
* @apiresponse int id ID number
* @apiresponse string name Forum name
* @apiresponse int topics Number of topics in forum
* @apiresponse string url URL
*/
public function apiOutput()
{
return array(
'id' => $this->id,
'name' => $this->_title,
'topics' => $this->topics,
'url' => (string) $this->url()
);
}
}
@@ -2,10 +2,10 @@
/**
* @brief Saved Action Node
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 31 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -230,10 +230,6 @@ class _SavedAction extends \IPS\Node\Model
{
throw new \DomainException('DISABLED');
}
if ( $this->mm_forums !== '*' and !in_array( $topic->container()->_id, explode( ',', $this->mm_forums ) ) )
{
throw new \DomainException('BAD_FORUM');
}
if ( $this->mm_forums !== '*' and !in_array( $topic->container()->_id, explode( ',', $this->mm_forums ) ) )
{
throw new \DomainException('BAD_FORUM');
@@ -278,11 +274,11 @@ class _SavedAction extends \IPS\Node\Model
/* Hide/Unhide */
if ( $this->topic_approve == 1 )
{
$topic->unhide();
$topic->unhide( $member );
}
elseif ( $this->topic_approve == 2 )
{
$topic->hide();
$topic->hide( $member );
}
/* Reply */
@@ -2,10 +2,10 @@
/**
* @brief Archived Post Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 24 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -28,6 +28,11 @@ class _ArchivedPost extends Post
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief Title
*/
public static $archiveTitle = 'archivedpost';
/**
* @brief [ActiveRecord] Database Connection
+121 -37
View File
@@ -2,10 +2,10 @@
/**
* @brief Post Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 8 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -116,41 +116,53 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
/**
* Create comment
*
* @param \IPS\Content\Item $item The content item just created
* @param string $comment The comment
* @param bool $first Is the first comment?
* @param string $guestName If author is a guest, the name to use
* @param \IPS\Content\Item $item The content item just created
* @param string $comment The comment
* @param bool $first Is the first comment?
* @param string $guestName If author is a guest, the name to use
* @param bool|NULL $incrementPostCount Increment post count? If NULL, will use static::incrementPostCount()
* @param \IPS\Member|NULL $member The author of this comment. If NULL, uses currently logged in member.
* @param \IPS\DateTime|NULL $time The time
* @param string|NULL $ipAddress The IP address or NULL to detect automatically
* @param int|NULL $hiddenStatus NULL to set automatically or override: 0 = unhidden; 1 = hidden, pending moderator approval; -1 = hidden (as if hidden by a moderator)
* @return static
*/
public static function create( $item, $comment, $first=FALSE, $guestName=NULL, $incrementPostCount=NULL, $member=NULL, \IPS\DateTime $time=NULL )
public static function create( $item, $comment, $first=FALSE, $guestName=NULL, $incrementPostCount=NULL, $member=NULL, \IPS\DateTime $time=NULL, $ipAddress=NULL, $hiddenStatus=NULL )
{
$comment = call_user_func_array( 'parent::create', func_get_args() );
if ( !$comment->hidden() and $popularNowSettings = json_decode( \IPS\Settings::i()->forums_popular_now, TRUE ) and $popularNowSettings['posts'] and $popularNowSettings['minutes'] )
if ( !$comment->hidden() )
{
$popularNowInterval = new \DateInterval( 'PT' . $popularNowSettings['minutes'] . 'M' );
$comments = $item->comments( NULL, NULL, 'date', 'desc', NULL, FALSE, \IPS\DateTime::create()->sub( $popularNowInterval ) );
if ( count( $comments ) >= $popularNowSettings['posts'] )
{
$commentToBasePopularNowTimeOff = array_slice( $comments, ( $popularNowSettings['posts'] - 1 ), 1 );
$commentToBasePopularNowTimeOff = array_pop( $commentToBasePopularNowTimeOff );
$item->popular_time = \IPS\DateTime::ts( $commentToBasePopularNowTimeOff->post_date )->add( $popularNowInterval )->getTimestamp();
$item->save();
}
elseif ( $item->popular_time !== NULL )
{
$item->popular_time = NULL;
$item->save();
}
$item->rebuildPopularTime();
}
return $comment;
}
/**
* Syncing to run when hiding
*
* @param \IPS\Member|NULL|FALSE $member The member doing the action (NULL for currently logged in member, FALSE for no member)
* @return void
*/
public function onHide( $member )
{
parent::onHide( $member );
$this->item()->rebuildPopularTime();
}
/**
* Syncing to run when unhiding
*
* @param bool $approving If true, is being approved for the first time
* @param \IPS\Member|NULL|FALSE $member The member doing the action (NULL for currently logged in member, FALSE for no member)
* @return void
*/
public function onUnhide( $approving, $member )
{
parent::onUnhide( $approving, $member );
$this->item()->rebuildPopularTime();
}
/**
* Should posting this increment the poster's post count?
@@ -186,7 +198,7 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
* @param string $order MySQL ORDER BY clause (NULL to order by date)
* @param int|array $limit Limit clause
* @param string $permissionKey A key which has a value in the permission map (either of the container or of this class) matching a column ID in core_permission_index
* @param bool|NULL $includeHiddenItems Include hidden files? Boolean or NULL to detect if currently logged member has permission
* @param mixed $includeHiddenItems Include hidden comments? NULL to detect if currently logged in member has permission, -1 to return public content only, TRUE to return unapproved content and FALSE to only return unapproved content the viewing member submitted
* @param int $queryFlags Select bitwise flags
* @param \IPS\Member $member The member (NULL to use currently logged in member)
* @param bool $joinContainer If true, will join container data (set to TRUE if your $where clause depends on this data)
@@ -194,7 +206,7 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
* @param bool $joinReviews If true, will join review data (set to TRUE if your $where clause depends on this data)
* @return \IPS\Patterns\ActiveRecordIterator|int
*/
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=NULL, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL )
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=\IPS\Content\Hideable::FILTER_AUTOMATIC, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL )
{
$where = \IPS\forums\Topic::getItemsWithPermissionWhere( $where, $permissionKey, $member, $joinContainer );
@@ -207,15 +219,17 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param bool $iPostedIn If the user has posted in the item
* @param string $view 'expanded' or 'condensed'
* @param bool $asItem Displaying results as items?
* @param bool $canIgnoreComments Can ignore comments in the result stream? Activity stream can, but search results cannot.
* @param array $template Optional custom template
* @return string
*/
public static function searchResult( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem )
public static function searchResult( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments=FALSE, $template=NULL )
{
/* Password protected */
if (
@@ -224,7 +238,7 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
and (
!isset( \IPS\Request::i()->cookie[ 'ipbforumpass_' . $indexData['index_container_id'] ] )
or
md5( $containerData['password'] ) !== \IPS\Request::i()->cookie[ 'ipbforumpass_' . $indexData['index_container_id'] ]
!\IPS\Login::compareHashes( md5( $containerData['password'] ), \IPS\Request::i()->cookie[ 'ipbforumpass_' . $indexData['index_container_id'] ] )
) // We don't have the correct password
)
{
@@ -233,9 +247,9 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
\IPS\Http\Url::internal( \IPS\forums\Forum::$urlBase . $indexData['index_container_id'], 'front', \IPS\forums\Forum::$urlTemplate, array( $containerData[ \IPS\forums\Forum::$databasePrefix . \IPS\forums\Forum::$seoTitleColumn ] ) )->setQueryString( 'topic', $indexData['index_item_id'] )
);
}
/* Minimum posts */
elseif ( $containerData['min_posts_view'] and $containerData['min_posts_view'] >= \IPS\Member::loggedIn()->member_po )
elseif ( $containerData['min_posts_view'] and $containerData['min_posts_view'] >= \IPS\Member::loggedIn()->member_posts )
{
return \IPS\Theme::i()->getTemplate( 'global', 'forums' )->searchNoPermission( \IPS\Member::loggedIn()->language()->addToStack( 'no_perm_post_min_posts', FALSE, array( 'pluralize' => array( $containerData['min_posts_view'] ) ) ) );
}
@@ -243,7 +257,7 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
/* Normal */
else
{
return parent::searchResult( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $iPostedIn, $view, $asItem );
return parent::searchResult( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $iPostedIn, $view, $asItem, $canIgnoreComments, $template );
}
}
@@ -310,22 +324,56 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
*/
public function delete()
{
/* It is possible to delete a post that is orphaned, so let's try to protect against that */
try
{
$item = $this->item();
}
catch( \OutOfRangeException $e )
{
$item = NULL;
}
/* Reset best answer if relevant */
if ( $this->item()->topic_answered_pid == $this->pid )
if ( $item !== NULL AND $item->topic_answered_pid == $this->pid )
{
$this->item()->topic_answered_pid = FALSE;
$this->item()->save();
$item->topic_answered_pid = FALSE;
$item->save();
}
parent::delete();
/* Deleting a post may make the item no longer popular */
if( $item !== NULL )
{
$item->rebuildPopularTime();
}
}
/**
/**
* Indefinite Article
*
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public function indefiniteArticle( \IPS\Lang $lang = NULL )
{
if ( $this->isFirst() AND $this->item()->container()->forums_bitoptions['bw_enable_answers'] )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( '__indefart_question', FALSE );
}
return parent::indefiniteArticle( $lang );
}
/**
* Indefinite Article
*
* @param array $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param \IPS\Lang $lang The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public static function _indefiniteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
{
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
@@ -340,6 +388,28 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
return parent::_indefiniteArticle( $containerData, $lang );
}
}
/**
* Definite Article
*
* @param array $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
* @param \IPS\Lang $lang The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
{
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
if ( $bitOptions['bw_enable_answers'] )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( '__defart_answer', FALSE );
}
else
{
return parent::_definiteArticle( $containerData, $lang );
}
}
/**
* Get HTML
@@ -353,4 +423,18 @@ class _Post extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \
return parent::html();
}
/**
* Force HTML posting abilities to TRUE for this comment
* This is usually determined by the member group and Editor extension.
* Here it can be overridden on a per comment basis
*
* @note Used currently in applications/core/extensions/core/Queue/RebuildPosts when rebuilding
*
* @return boolean
*/
public function htmlParsingEnforced()
{
return (boolean) $this->post_htmlstate > 0;
}
}
+317 -107
View File
@@ -2,10 +2,10 @@
/**
* @brief Topic Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 8 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -144,6 +144,20 @@ class _Topic extends \IPS\Content\Item implements
* @brief Hover preview
*/
public $tableHoverUrl = TRUE;
/**
* Callback from \IPS\Http\Url\Inernal::correctUrlFromVerifyClass()
*
* This is called when verifying the *the URL currently being viewed* is correct, before calling self::loadFromUrl()
* Can be used if there is a more effecient way to load and cache the objects that will be used later on that page
*
* @param \IPS\Http\Url $url The URL of the page being viewed, which belongs to this class
* @return void
*/
public static function preCorrectUrlFromVerifyClass( \IPS\Http\Url $url )
{
\IPS\forums\Forum::loadIntoMemory();
}
/**
* Check the request for legacy parameters we may need to redirect to
@@ -168,6 +182,7 @@ class _Topic extends \IPS\Content\Item implements
/* p=123 needs to go to comment=123 */
if( isset( \IPS\Request::i()->p ) )
{
$paramsToSet['do'] = 'findComment';
$paramsToSet['comment'] = \IPS\Request::i()->p;
$paramsToUnset[] = 'p';
}
@@ -233,13 +248,13 @@ class _Topic extends \IPS\Content\Item implements
}
/**
* Get items with permisison check
* Get items with permission check
*
* @param array $where Where clause
* @param string $order MySQL ORDER BY clause (NULL to order by date)
* @param int|array $limit Limit clause
* @param string|NULL $permissionKey A key which has a value in the permission map (either of the container or of this class) matching a column ID in core_permission_index or NULL to ignore permissions
* @param bool|NULL $includeHiddenItems Include hidden files? Boolean or NULL to detect if currently logged member has permission
* @param mixed $includeHiddenItems Include hidden items? NULL to detect if currently logged in member has permission, -1 to return public content only, TRUE to return unapproved content and FALSE to only return unapproved content the viewing member submitted
* @param int $queryFlags Select bitwise flags
* @param \IPS\Member $member The member (NULL to use currently logged in member)
* @param bool $joinContainer If true, will join container data (set to TRUE if your $where clause depends on this data)
@@ -251,12 +266,13 @@ class _Topic extends \IPS\Content\Item implements
* @param bool $joinTags If true, will join the tags table
* @param bool $joinAuthor If true, will join the members table for the author
* @param bool $joinLastCommenter If true, will join the members table for the last commenter
* @param bool $showMovedLinks If true, moved item links are included in the results
* @return \IPS\Patterns\ActiveRecordIterator|int
*/
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=NULL, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL, $skipPermission=FALSE, $joinTags=TRUE, $joinAuthor=TRUE, $joinLastCommenter=TRUE )
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=\IPS\Content\Hideable::FILTER_AUTOMATIC, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL, $skipPermission=FALSE, $joinTags=TRUE, $joinAuthor=TRUE, $joinLastCommenter=TRUE, $showMovedLinks=FALSE )
{
$where = static::getItemsWithPermissionWhere( $where, $permissionKey, $member, $joinContainer, $skipPermission );
return parent::getItemsWithPermission( $where, $order, $limit, $permissionKey, $includeHiddenItems, $queryFlags, $member, $joinContainer, $joinComments, $joinReviews, $countOnly, $joins, $skipPermission, $joinTags, $joinAuthor, $joinLastCommenter );
return parent::getItemsWithPermission( $where, $order, $limit, $permissionKey, $includeHiddenItems, $queryFlags, $member, $joinContainer, $joinComments, $joinReviews, $countOnly, $joins, $skipPermission, $joinTags, $joinAuthor, $joinLastCommenter, $showMovedLinks );
}
/**
@@ -279,7 +295,7 @@ class _Topic extends \IPS\Content\Item implements
* @param string $permissionKey A key which has a value in the permission map (either of the container or of this class) matching a column ID in core_permission_index
* @param \IPS\Member $member The member (NULL to use currently logged in member)
* @param bool $joinContainer If true, will join container data (set to TRUE if your $where clause depends on this data)
* @param mixed $skipPermission If you are getting records from a specific container, pass the container to reduce the number of permission checks necessary or pass TRUE to skip conatiner-based permission. You must still specify this in the $where clause
* @param mixed $skipPermission If you are getting records from a specific container, pass the container to reduce the number of permission checks necessary or pass TRUE to skip container-based permission. You must still specify this in the $where clause
* @return array
*/
public static function getItemsWithPermissionWhere( $where, $permissionKey, $member, &$joinContainer, $skipPermission=FALSE )
@@ -304,18 +320,16 @@ class _Topic extends \IPS\Content\Item implements
}
}
}
/* Don't show links to moved topics */
$where['item'][] = array( "( NULLIF(forums_topics.moved_to, '') IS NULL )" );
$where['container'][] = array_merge( array( '( ' . $whereString . ' )' ), $whereParams );
}
/* Don't show topics from forums in which topics only show to the poster */
if ( $skipPermission !== TRUE and in_array( $permissionKey, array( 'view', 'read' ) ) )
{
$member = $member ?: \IPS\Member::loggedIn();
if ( !$member->modPermission( 'can_read_all_topics' ) or $member->modPermission( 'forums' ) !== -1 )
if ( !$member->modPermission( 'can_read_all_topics' ) or ( $member->modPermission( 'forums' ) !== TRUE and $member->modPermission( 'forums' ) !== -1 ) )
{
if ( $skipPermission instanceof \IPS\forums\Forum )
{
@@ -343,7 +357,7 @@ class _Topic extends \IPS\Content\Item implements
}
}
}
/* Don't show topics in forums we can't view because our post count is too low */
if ( !$skipPermission and in_array( $permissionKey, array( 'view', 'read' ) ) )
{
@@ -496,17 +510,11 @@ class _Topic extends \IPS\Content\Item implements
/* Moderator actions */
if ( isset( $values['topic_create_state'] ) )
{
if ( static::modPermission( 'feature', NULL, $this->container() ) )
if ( static::modPermission( 'lock', NULL, $this->container() ) )
{
$this->state = ( in_array( 'lock', $values['topic_create_state'] ) ) ? 'closed' : 'open';
}
if ( static::modPermission( 'hide', NULL, $this->container() ) )
{
$this->approved = ( in_array( 'hide', $values['topic_create_state'] ) ) ? -1 : 1;
}
if ( static::modPermission( 'pin', NULL, $this->container() ) )
{
$this->pinned = ( in_array( 'pin', $values['topic_create_state'] ) ) ? 1 : 0;
@@ -521,17 +529,11 @@ class _Topic extends \IPS\Content\Item implements
if ( static::modPermission( 'lock', NULL, $this->container() ) )
{
/* Set open/close time */
if ( isset( $values['topic_open_time'] ) and $values['topic_open_time'] )
$this->topic_open_time = !empty( $values['topic_open_time'] ) ? $values['topic_open_time']->getTimestamp() : 0;
$this->topic_close_time = !empty( $values['topic_close_time'] ) ? $values['topic_close_time']->getTimestamp() : 0;
if( isset( $values['topic_create_state'] ) and !in_array( 'lock', $values['topic_create_state'] ) )
{
$this->topic_open_time = $values['topic_open_time']->getTimestamp();
}
if ( isset( $values['topic_close_time'] ) and $values['topic_close_time'] )
{
$this->topic_close_time = $values['topic_close_time']->getTimestamp();
}
else if( isset( $values['topic_create_state'] ) and !in_array( 'lock', $values['topic_create_state'] ) )
{
$this->topic_close_time = 0;
$this->state = 'open';
}
@@ -541,8 +543,20 @@ class _Topic extends \IPS\Content\Item implements
$this->state = 'closed';
}
}
}
/**
* Process created object AFTER the object has been created
*
* @param \IPS\Content\Comment|NULL $comment The first comment
* @param array $values Values from form
* @return void
*/
protected function processAfterCreate( $comment, $values )
{
$this->processAfterCreateOrEdit( $values );
parent::processAfterCreate( $comment, $values );
}
/**
@@ -553,11 +567,13 @@ class _Topic extends \IPS\Content\Item implements
*/
public function processAfterEdit( $values )
{
$this->processAfterCreateOrEdit( $values );
/* Initial Comment */
parent::processAfterEdit( $values );
/* Topic changed? */
if ( ! $this->hidden() and ( $this->tid === $this->container()->last_id ) and ( $this->title_seo !== $this->container()->seo_last_title ) )
if ( ! $this->hidden() and ( $this->tid === $this->container()->last_id ) )
{
$this->container()->seo_last_title = $this->title_seo;
$this->container()->last_title = $this->title;
@@ -574,6 +590,32 @@ class _Topic extends \IPS\Content\Item implements
}
}
}
/**
* Process after the object has been edited or created on the front-end
*
* @param array $values Values from form
* @return void
*/
protected function processAfterCreateOrEdit( $values )
{
/* Moderator actions */
if ( isset( $values['topic_create_state'] ) )
{
if ( static::modPermission( 'hide', NULL, $this->container() ) )
{
if( in_array( 'hide', $values['topic_create_state'] ) )
{
$this->hide( NULL );
}
/* Only unhide if the topic is not pending approval */
elseif( $this->hidden() !== 1 )
{
$this->unhide( NULL );
}
}
}
}
/**
* @brief Cached URLs
@@ -633,6 +675,35 @@ class _Topic extends \IPS\Content\Item implements
return $stats;
}
/**
* Set the new popular time if needed
*
*/
public function rebuildPopularTime( )
{
$popularNowSettings = json_decode( \IPS\Settings::i()->forums_popular_now, TRUE );
if ( $popularNowSettings['posts'] and $popularNowSettings['minutes'] )
{
$popularNowInterval = new \DateInterval( 'PT' . $popularNowSettings['minutes'] . 'M' );
$comments = $this->comments( NULL, NULL, 'date', 'desc', NULL, FALSE, \IPS\DateTime::create()->sub( $popularNowInterval ) );
if ( count( $comments ) >= $popularNowSettings['posts'] )
{
$commentToBasePopularNowTimeOff = array_slice( $comments, ( $popularNowSettings['posts'] - 1 ), 1 );
$commentToBasePopularNowTimeOff = array_pop( $commentToBasePopularNowTimeOff );
$this->popular_time = \IPS\DateTime::ts( $commentToBasePopularNowTimeOff->post_date )->add( $popularNowInterval )->getTimestamp();
$this->save();
}
elseif ( $this->popular_time !== NULL )
{
$this->popular_time = NULL;
$this->save();
}
}
}
/**
* Set name
@@ -643,7 +714,7 @@ class _Topic extends \IPS\Content\Item implements
public function set_title( $title )
{
$this->_data['title'] = $title;
$this->_data['title_seo'] = \IPS\Http\Url::seoTitle( $title );
$this->_data['title_seo'] = \IPS\Http\Url\Friendly::seoTitle( $title );
}
/**
@@ -655,11 +726,11 @@ class _Topic extends \IPS\Content\Item implements
{
if( !$this->_data['title_seo'] )
{
$this->title_seo = \IPS\Http\Url::seoTitle( $this->title );
$this->title_seo = \IPS\Http\Url\Friendly::seoTitle( $this->title );
$this->save();
}
return $this->_data['title_seo'] ?: \IPS\Http\Url::seoTitle( $this->title );
return $this->_data['title_seo'] ?: \IPS\Http\Url\Friendly::seoTitle( $this->title );
}
/**
@@ -722,9 +793,9 @@ class _Topic extends \IPS\Content\Item implements
*/
public function searchIndexPermissions()
{
$return = parent::searchIndexPermissions();
$return = $this->container()->searchIndexPermissions();
if ( !$this->container()->can_view_others )
if ( $this->starter_id and !$this->container()->can_view_others )
{
/* If the search index permissions are empty, just return now because no one can see content in this forum */
if( !$return )
@@ -732,40 +803,16 @@ class _Topic extends \IPS\Content\Item implements
return $return;
}
$normal = $return;
$return = array();
$members = array();
foreach ( \IPS\Db::i()->select( '*', 'core_moderators' ) as $moderator )
{
if ( $moderator['perms'] === '*' or in_array( 'can_read_all_topics', explode( ',', $moderator['perms'] ) ) )
{
if( $moderator['type'] === 'g' )
{
$return[] = $moderator['id'];
}
else
{
$members[] = "m{$moderator['id']}";
}
}
}
$return = ( $normal == '*' ) ? array_unique( $return ) : array_intersect( explode( ',', $normal ), array_unique( $return ) );
$return = $this->container()->permissionsThatCanAccessAllTopics();
if ( $this->starter_id )
{
$members[] = "m{$this->starter_id}";
}
if( count( $members ) )
{
$return = array_merge( $return, $members );
$return[] = "m{$this->starter_id}";
}
$return = implode( ',', $return );
}
return $return;
}
@@ -855,11 +902,11 @@ class _Topic extends \IPS\Content\Item implements
if ( !empty( $openIds ) )
{
\IPS\Db::i()->update( 'forums_topics', array( 'state' => 'open', 'topic_close_time' => 0 ), \IPS\Db::i()->in( 'tid', $openIds ) );
\IPS\Db::i()->update( 'forums_topics', array( 'state' => 'open', 'topic_open_time' => 0 ), \IPS\Db::i()->in( 'tid', $openIds ) );
}
if ( !empty( $closeIds ) )
{
\IPS\Db::i()->update( 'forums_topics', array( 'state' => 'closed', 'topic_open_time' => 0 ), \IPS\Db::i()->in( 'tid', $closeIds ) );
\IPS\Db::i()->update( 'forums_topics', array( 'state' => 'closed', 'topic_close_time' => 0 ), \IPS\Db::i()->in( 'tid', $closeIds ) );
}
}
@@ -922,12 +969,123 @@ class _Topic extends \IPS\Content\Item implements
public function delete()
{
parent::delete();
\IPS\forums\Topic\ArchivedPost::db()->delete( 'forums_archive_posts', array( 'archive_topic_id=?', $this->tid ) );
try
{
\IPS\forums\Topic\ArchivedPost::db()->delete( 'forums_archive_posts', array( 'archive_topic_id=?', $this->tid ) );
}
/* catch db exceptions if e.g. if the connection credentials didn't work or if the database doesn't exist anymore */
catch ( \IPS\Db\Exception $e ){}
\IPS\Db::i()->delete( 'forums_question_ratings', array( 'topic=?', $this->tid ) );
\IPS\Db::i()->delete( 'forums_answer_ratings', array( 'topic=?', $this->tid ) );
/* Delete any moved topic links that point to this topic */
\IPS\Db::i()->delete( 'forums_topics', array( "state=? AND moved_to LIKE CONCAT( ?, '%' )", 'link', $this->tid . '&' ) );
}
/**
* Merge other items in (they will be deleted, this will be kept)
*
* @param array $items Items to merge in
* @param bool $keepLinks Retain redirect links for the items that were merge in
* @return void
*/
public function mergeIn( array $items, $keepLinks=FALSE )
{
/* If this is a QA forum we need to make sure we only have one best answer (at most) post-merge */
if( $this->isQuestion() )
{
/* Does this topic already have a best answer? */
if( $this->topic_answered_pid )
{
/* Then we need to make sure none of the items also has a best answer */
foreach( $items as $item )
{
/* Reset best answer for this topic */
if( $item->topic_answered_pid )
{
try
{
$post = \IPS\forums\Topic\Post::load( $item->topic_answered_pid );
$post->post_bwoptions['best_answer'] = FALSE;
$post->save();
}
catch( \OutOfRangeException $e ){}
}
}
}
/* The topic doesn't have a best answer, but we still need to make sure we only have one best answer total post-merge */
else
{
$bestAnswerSeen = FALSE;
foreach( $items as $item )
{
if( $item->topic_answered_pid )
{
/* Have we seen a best answer yet? If not, then we're ok. */
if( $bestAnswerSeen === FALSE )
{
/* This topic had no best answer flag set, so set it now */
$this->topic_answered_pid = $item->topic_answered_pid;
$this->save();
$bestAnswerSeen = TRUE;
continue;
}
/* If we have though, reset any others */
try
{
$post = \IPS\forums\Topic\Post::load( $item->topic_answered_pid );
$post->post_bwoptions['best_answer'] = FALSE;
$post->save();
}
catch( \OutOfRangeException $e ){}
}
}
}
}
return parent::mergeIn( $items, $keepLinks );
}
/**
* Hide
*
* @param \IPS\Member|NULL|FALSE $member The member doing the action (NULL for currently logged in member, FALSE for no member)
* @param string $reason Reason
* @return void
*/
public function hide( $member, $reason = NULL )
{
/* Hide any moved topic links that point to this topic */
foreach( \IPS\Db::i()->select( '*', 'forums_topics', array( "state=? AND moved_to LIKE CONCAT( ?, '%' )", 'link', $this->tid . '&' ) ) as $link )
{
\IPS\forums\Topic::constructFromData( $link )->hide( $member, $reason );
}
return parent::hide( $member, $reason );
}
/**
* Unhide
*
* @param \IPS\Member|NULL|FALSE $member The member doing the action (NULL for currently logged in member, FALSE for no member)
* @return void
*/
public function unhide( $member )
{
/* Unhide any moved topic links that point to this topic */
foreach( \IPS\Db::i()->select( '*', 'forums_topics', array( "state=? AND moved_to LIKE CONCAT( ?, '%' )", 'link', $this->tid . '&' ) ) as $link )
{
\IPS\forums\Topic::constructFromData( $link )->unhide( $member );
}
return parent::unhide( $member );
}
/* !Saved Actions */
/**
@@ -1052,14 +1210,14 @@ class _Topic extends \IPS\Content\Item implements
{
return TRUE;
}
/* Or if we're a moderator */
if
(
$member->modPermission( 'can_set_best_answer' )
and
(
$member->modPermission( \IPS\forums\Forum::$modPerm ) === -1
( $member->modPermission( \IPS\forums\Forum::$modPerm ) === TRUE or $member->modPermission( \IPS\forums\Forum::$modPerm ) === -1 )
or
(
is_array( $member->modPermission( \IPS\forums\Forum::$modPerm ) )
@@ -1217,6 +1375,27 @@ class _Topic extends \IPS\Content\Item implements
}
}
/**
* Definite Article
*
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public static function _definiteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
{
$bitOptions = ( $containerData['forums_bitoptions'] instanceof \IPS\Patterns\Bitwise ) ? $containerData['forums_bitoptions'] : new \IPS\Patterns\Bitwise( array( 'forums_bitoptions' => $containerData['forums_bitoptions'] ), \IPS\forums\Forum::$bitOptions['forums_bitoptions'] );
if ( $bitOptions['bw_enable_answers'] )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( '__defart_question', FALSE );
}
else
{
return parent::_definiteArticle( $containerData, $lang );
}
}
/* !Sitemap */
/**
@@ -1327,38 +1506,6 @@ class _Topic extends \IPS\Content\Item implements
return parent::canEdit( $member );
}
/**
* Can pin?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canPin( $member=NULL )
{
if ( $this->isArchived() )
{
return FALSE;
}
return parent::canPin( $member );
}
/**
* Can unpin?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canUnpin( $member=NULL )
{
if ( $this->isArchived() )
{
return FALSE;
}
return parent::canUnpin( $member );
}
/**
* Can feature?
*
@@ -1663,4 +1810,67 @@ class _Topic extends \IPS\Content\Item implements
return $metaDescription;
}
/**
* Get output for API
*
* @return array
* @apiresponse int id ID number
* @apiresponse string title Title
* @apiresponse \IPS\forums\Forum forum Forum
* @apiresponse int posts Number of posts
* @apiresponse int views Number of posts
* @apiresponse string prefix The prefix tag, if there is one
* @apiresponse [string] tags The tags
* @apiresponse \IPS\forums\Topic\Post firstPost The first post in the topic
* @apiresponse \IPS\forums\Topic\Post lastPost The last post in the topic
* @apiresponse \IPS\forums\Topic\Post bestAnswer The best answer, if this is a question and there is one
* @apiresponse bool locked Topic is locked
* @apiresponse bool hidden Topic is hidden
* @apiresponse bool pinned Topic is pinned
* @apiresponse bool featured Topic is featured
* @apiresponse bool archived Topic is archived
* @apiresponse \IPS\Poll poll Poll data, if there is one
* @apiresponse string url URL
* @apiresponse float rating Average Rating
*/
public function apiOutput()
{
$firstPost = $this->comments( 1, 0, 'date', 'asc' );
$lastPost = $this->comments( 1, 0, 'date', 'desc' );
$bestAnswer = $this->bestAnswer();
return array(
'id' => $this->tid,
'title' => $this->title,
'forum' => $this->container()->apiOutput(),
'posts' => $this->posts,
'views' => $this->views,
'prefix' => $this->prefix(),
'tags' => $this->tags(),
'firstPost' => $firstPost ? $firstPost->apiOutput() : null,
'lastPost' => $lastPost ? $lastPost->apiOutput() : null,
'bestAnswer' => $bestAnswer ? $bestAnswer->apiOutput() : null,
'locked' => (bool) $this->locked(),
'hidden' => (bool) $this->hidden(),
'pinned' => (bool) $this->mapped('pinned'),
'featured' => (bool) $this->mapped('featured'),
'archived' => (bool) $this->isArchived(),
'poll' => $this->poll_state ? \IPS\Poll::load( $this->poll_state )->apiOutput() : null,
'url' => (string) $this->url(),
'rating' => $this->averageRating(),
);
}
/**
* Returns the content
*
* @return string
* @throws \BadMethodCallException
* @note This is overridden for performance reasons - selecting a post by a PID is more efficient than select * from posts order by date desc limit 1
*/
public function content()
{
$firstComment = $this->firstComment();
return $firstComment ? $firstComment->content() : '';
}
}
+44 -113
View File
@@ -2,10 +2,10 @@
/**
* @brief archive Task
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage forums
* @package IPS Community Suite
* @subpackage Forums
* @since 24 Jan 2014
* @version SVN_VERSION_NUMBER
*/
@@ -44,18 +44,10 @@ class _archive extends \IPS\Task
*/
public function execute()
{
/* If we're disabled, disable the task, but only if we don't have things that need restoring */
$count = \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics', array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_RESTORE ) )->first();
$restoreOnly = FALSE;
if ( !\IPS\Settings::i()->archive_on AND $count > 0 )
/* If archiving is disabled, disable the task */
if ( !\IPS\Settings::i()->archive_on )
{
$restoreOnly = TRUE;
}
if ( !\IPS\Settings::i()->archive_on AND $restoreOnly !== TRUE )
{
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'archive' ) );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'archive' ) );
}
/* Otherwise, let's do this! */
@@ -75,50 +67,49 @@ class _archive extends \IPS\Task
'sql_tbl_prefix'=> \IPS\Settings::i()->archive_sql_tbl_prefix,
'sql_utf8mb4' => isset( \IPS\Settings::i()->sql_utf8mb4 ) ? \IPS\Settings::i()->sql_utf8mb4 : FALSE
) );
/* Do we have a topic we're working on? */
if ( $restoreOnly !== TRUE )
/* Do we have a topic we are working on? */
try
{
try
/* Get the topic */
$topic = \IPS\forums\Topic::constructFromData( \IPS\Db::i()->select( '*', 'forums_topics', array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_WORKING ) )->first() );
/* Do as many posts as we can */
$offset = $this->storage->select( 'MAX(archive_id)', 'forums_archive_posts', array( 'archive_topic_id=?', $topic->tid ) )->first();
$posts = \IPS\Db::i()->select( 'forums_posts.*,forums_topics.forum_id', 'forums_posts', array( 'pid>? AND topic_id=?', intval( $offset ), $topic->tid ), 'pid ASC', static::PROCESS_PER_BATCH, NULL, NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS )->join( 'forums_topics', 'tid=topic_id' );
foreach ( $posts as $post )
{
$this->archive( $post, $post['forum_id'] );
$postsProcessed++;
}
/* If we did them all, mark that this topic is done and remove from search index */
if ( $postsProcessed == $posts->count( TRUE ) )
{
/* Get the topic */
$topic = \IPS\forums\Topic::constructFromData( \IPS\Db::i()->select( '*', 'forums_topics', array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_WORKING ) )->first() );
/* Do as many posts as we can */
$offset = $this->storage->select( 'MAX(archive_id)', 'forums_archive_posts', array( 'archive_topic_id=?', $topic->tid ) )->first();
$posts = \IPS\Db::i()->select( 'forums_posts.*,forums_topics.forum_id', 'forums_posts', array( 'pid>? AND topic_id=?', intval( $offset ), $topic->tid ), 'pid ASC', static::PROCESS_PER_BATCH, NULL, NULL, \IPS\Db::SELECT_SQL_CALC_FOUND_ROWS )->join( 'forums_topics', 'tid=topic_id' );
foreach ( $posts as $post )
{
$this->archive( $post, $post['forum_id'] );
$postsProcessed++;
}
$topic->topic_archive_status = \IPS\forums\Topic::ARCHIVE_DONE;
$topic->save();
/* If we did them all, mark that this topic is done and remove from search index */
if ( $postsProcessed == $posts->count( TRUE ) )
{
$topic->topic_archive_status = \IPS\forums\Topic::ARCHIVE_DONE;
$topic->save();
\IPS\Db::i()->delete( 'forums_posts', array( 'topic_id=?', $inProgress ) );
\IPS\Content\Search\Index::i()->removeFromSearchIndex( $topic );
}
\IPS\Db::i()->delete( 'forums_posts', array( 'topic_id=?', $topic->tid ) );
\IPS\Content\Search\Index::i()->removeFromSearchIndex( $topic );
}
catch ( \UnderflowException $e ) { }
}
/* Any that need to be restored? */
catch ( \UnderflowException $e ) { }
/* Can we do even more? */
$query = array_merge( array( array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_NOT ) ), \IPS\Application::load('forums')->archiveWhere( \IPS\Db::i()->select( '*', 'forums_archive_rules' ) ) );
if ( $postsProcessed < static::PROCESS_PER_BATCH )
{
/* Loop topics */
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_RESTORE ), 'tid ASC', 250 ), 'IPS\forums\Topic' ) as $topic )
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', $query, 'tid ASC', 250 ), 'IPS\forums\Topic' ) as $topic )
{
/* First set it as working */
\IPS\Db::i()->update( 'forums_topics', array( 'topic_archive_status' => \IPS\forums\Topic::ARCHIVE_WORKING ), array( 'tid=?', $topic->tid ) );
/* Do as many posts as we can */
$offset = \IPS\Db::i()->select( 'MAX(pid)', 'forums_posts', array( 'topic_id=?', $topic->tid ) )->first();
foreach ( $this->storage->select( '*', 'forums_archive_posts', array( 'archive_id>? AND archive_topic_id=?', intval( $offset ), $topic->tid ), 'archive_id ASC', static::PROCESS_PER_BATCH - $postsProcessed ) as $post )
foreach ( \IPS\Db::i()->select( '*', 'forums_posts', array( 'topic_id=?', $topic->tid ), 'pid ASC', static::PROCESS_PER_BATCH - $postsProcessed ) as $post )
{
$this->unarchive( $post );
\IPS\Content\Search\Index::i()->index( \IPS\forums\Topic\Post::load( $post['archive_id'] ) );
$this->archive( $post, $topic->forum_id );
$postsProcessed++;
if ( $postsProcessed >= static::PROCESS_PER_BATCH )
{
@@ -127,41 +118,11 @@ class _archive extends \IPS\Task
}
/* Set that it's done */
\IPS\Db::i()->update( 'forums_topics', array( 'topic_archive_status' => \IPS\forums\Topic::ARCHIVE_EXCLUDE ), array( 'tid=?', $topic->tid ) );
$this->storage->delete( 'forums_archive_posts', array( 'archive_topic_id=?', $topic->tid ) );
}
}
/* Can we do even more? */
if ( $restoreOnly !== TRUE )
{
$query = array_merge( array( array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_NOT ) ), \IPS\Application::load('forums')->archiveWhere( \IPS\Db::i()->select( '*', 'forums_archive_rules' ) ) );
if ( $postsProcessed < static::PROCESS_PER_BATCH )
{
/* Loop topics */
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', $query, 'tid ASC', 250 ), 'IPS\forums\Topic' ) as $topic )
{
/* First set it as working */
\IPS\Db::i()->update( 'forums_topics', array( 'topic_archive_status' => \IPS\forums\Topic::ARCHIVE_WORKING ), array( 'tid=?', $topic->tid ) );
/* Do as many posts as we can */
foreach ( \IPS\Db::i()->select( '*', 'forums_posts', array( 'topic_id=?', $topic->tid ), 'pid ASC', static::PROCESS_PER_BATCH - $postsProcessed ) as $post )
{
$this->archive( $post, $topic->forum_id );
$postsProcessed++;
if ( $postsProcessed >= static::PROCESS_PER_BATCH )
{
break 2;
}
}
/* Set that it's done */
\IPS\Db::i()->update( 'forums_topics', array( 'topic_archive_status' => \IPS\forums\Topic::ARCHIVE_DONE ), array( 'tid=?', $topic->tid ) );
\IPS\Db::i()->delete( 'forums_posts', array( 'topic_id=?', $topic->tid ) );
\IPS\Db::i()->update( 'forums_topics', array( 'topic_archive_status' => \IPS\forums\Topic::ARCHIVE_DONE ), array( 'tid=?', $topic->tid ) );
\IPS\Db::i()->delete( 'forums_posts', array( 'topic_id=?', $topic->tid ) );
/* Remove from search index */
\IPS\Content\Search\Index::i()->removeFromSearchIndex( $topic );
}
/* Remove from search index */
\IPS\Content\Search\Index::i()->removeFromSearchIndex( $topic );
}
}
}
@@ -203,39 +164,9 @@ class _archive extends \IPS\Task
/* Insert */
$this->storage->replace( 'forums_archive_posts', $archive );
}
/**
* Unarchive
*
* @param array $post The post to be unarchived
* @return void
*/
protected function unarchive( $post )
{
/* Translate the fields */
$row = array(
'pid' => intval( $post['archive_id'] ),
'author_id' => intval( $post['archive_author_id'] ),
'author_name' => $post['archive_author_name'],
'ip_address' => $post['archive_ip_address'],
'post_date' => intval( $post['archive_content_date'] ),
'post' => $post['archive_content'],
'queued' => $post['archive_queued'],
'topic_id' => intval( $post['archive_topic_id'] ),
'new_topic' => intval( $post['archive_is_first'] ),
'post_bwoptions' => $post['archive_bwoptions'],
'post_key' => $post['archive_attach_key'],
'post_htmlstate' => $post['archive_html_mode'],
'append_edit' => $post['archive_show_edited_by'],
'edit_time' => $post['archive_edit_time'],
'edit_name' => $post['archive_edit_name'],
'post_edit_reason' => $post['archive_edit_reason'],
'post_field_int' => $post['archive_field_int'],
);
/* Insert */
\IPS\Db::i()->replace( 'forums_posts', $row );
/* Update reports table */
\IPS\Db::i()->update( 'core_rc_index', array( 'class' => 'IPS\forums\Topic\ArchivedPost' ), array( 'class=? AND content_id=?', 'IPS\forums\Topic\Post', $post['pid'] ) );
}
/**
+39 -18
View File
@@ -2,10 +2,10 @@
/**
* @brief rssimport Task
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @package IPS Community Suite
* @subpackage Forums
* @since 05 Feb 2014
* @version SVN_VERSION_NUMBER
*/
@@ -37,21 +37,42 @@ class _rssimport extends \IPS\Task
*/
public function execute()
{
try
{
$feed = \IPS\forums\Feed::constructFromData( \IPS\Db::i()->select( '*', 'forums_rss_import', array( 'rss_import_enabled=1' ), 'rss_import_last_import ASC', 1 )->first() );
$feed->run();
}
/* UnderflowException means there's no feed, so we can disable the task */
catch ( \UnderflowException $e )
{
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'rssimport' ) );
}
/* Any other exception means an error which should be logged */
catch ( \Exception $e )
{
throw new \IPS\Task\Exception( $this, $e->getMessage() );
}
$timeCheck = new \IPS\DateTime;
$timeCheck->sub( new \DateInterval( 'PT10M' ) );
$this->runUntilTimeout(function() use ( $timeCheck ) {
try
{
$feed = \IPS\forums\Feed::constructFromData( \IPS\Db::i()->select( '*', 'forums_rss_import', array( 'rss_import_enabled=1 AND rss_import_last_import<?', $timeCheck->getTimestamp() ), 'rss_import_last_import ASC', 1 )->first() );
$feed->run();
}
/* There's nothing more left to process */
catch ( \UnderflowException $e )
{
/* Check to see if there are any feeds.. If no feed, we can disable the task */
if( !\IPS\Db::i()->select( 'count(rss_import_id)', 'forums_rss_import', array( 'rss_import_enabled=1' ), NULL, 1 )->first() )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'rssimport' ) );
}
/* No further processing needed */
return FALSE;
}
/* Any other exception means an error which should be logged */
catch ( \Exception $e )
{
/* If there is an error, we need to log it but the error should not prevent other feeds from importing */
if ( isset( $feed ) AND ( $feed instanceof \IPS\forums\Feed ) )
{
$feed->last_import = time();
$feed->save();
}
throw new \IPS\Task\Exception( $this, $e->getMessage() );
}
/* Run again to see if there's anything left */
return TRUE;
});
}
/**
+147
View File
@@ -0,0 +1,147 @@
<?php
/**
* @brief unarchive Task
* @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
* @subpackage Forums
* @since 07 Sep 2016
* @version SVN_VERSION_NUMBER
*/
namespace IPS\forums\tasks;
/* 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;
}
/**
* unarchive Task
*/
class _unarchive extends \IPS\Task
{
const PROCESS_PER_BATCH = 250;
/**
* @brief Storage database
*/
protected $storage;
/**
* Execute
*
* If ran successfully, should return anything worth logging. Only log something
* worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases).
* If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log.
* Tasks should execute within the time of a normal HTTP request.
*
* @return mixed Message to log or NULL
* @throws \IPS\Task\Exception
*/
public function execute()
{
/* If we're disabled, disable the task, but only if we don't have things that need restoring */
$count = \IPS\Db::i()->select( 'COUNT(*)', 'forums_topics', array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_RESTORE ) )->first();
if ( !\IPS\Settings::i()->archive_on AND !$count )
{
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 0 ), array( '`key`=?', 'unarchive' ) );
return NULL;
}
/* Init */
$postsProcessed = 0;
/* Connect to the remote DB if needed */
$this->storage = !\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
) );
/* Loop topics */
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'forums_topics', array( 'topic_archive_status=?', \IPS\forums\Topic::ARCHIVE_RESTORE ), 'tid ASC', 250 ), 'IPS\forums\Topic' ) as $topic )
{
/* Do as many posts as we can */
$offset = \IPS\Db::i()->select( 'MAX(pid)', 'forums_posts', array( 'topic_id=?', $topic->tid ) )->first();
foreach ( $this->storage->select( '*', 'forums_archive_posts', array( 'archive_id>? AND archive_topic_id=?', intval( $offset ), $topic->tid ), 'archive_id ASC', static::PROCESS_PER_BATCH - $postsProcessed ) as $post )
{
$unarchivedPost = $this->unarchive( $post );
\IPS\Content\Search\Index::i()->index( $unarchivedPost );
$postsProcessed++;
if ( $postsProcessed >= static::PROCESS_PER_BATCH )
{
break 2;
}
}
/* Set that it's done */
\IPS\Db::i()->update( 'forums_topics', array( 'topic_archive_status' => \IPS\forums\Topic::ARCHIVE_EXCLUDE ), array( 'tid=?', $topic->tid ) );
$this->storage->delete( 'forums_archive_posts', array( 'archive_topic_id=?', $topic->tid ) );
}
return NULL;
}
/**
* Unarchive
*
* @param array $post The post to be unarchived
* @return \IPS\forums\Topic\Post
*/
protected function unarchive( $post )
{
/* Translate the fields */
$row = array(
'pid' => intval( $post['archive_id'] ),
'author_id' => intval( $post['archive_author_id'] ),
'author_name' => $post['archive_author_name'],
'ip_address' => $post['archive_ip_address'],
'post_date' => intval( $post['archive_content_date'] ),
'post' => $post['archive_content'],
'queued' => $post['archive_queued'],
'topic_id' => intval( $post['archive_topic_id'] ),
'new_topic' => intval( $post['archive_is_first'] ),
'post_bwoptions' => $post['archive_bwoptions'],
'post_key' => $post['archive_attach_key'],
'post_htmlstate' => $post['archive_html_mode'],
'append_edit' => $post['archive_show_edited_by'],
'edit_time' => $post['archive_edit_time'],
'edit_name' => $post['archive_edit_name'],
'post_edit_reason' => $post['archive_edit_reason'],
'post_field_int' => $post['archive_field_int'],
);
/* Insert */
\IPS\Db::i()->replace( 'forums_posts', $row );
/* Update reports table */
\IPS\Db::i()->update( 'core_rc_index', array( 'class' => 'IPS\forums\Topic\Post' ), array( 'class=? AND content_id=?', 'IPS\forums\Topic\ArchivedPost', $post['archive_id'] ) );
return \IPS\forums\Topic\Post::constructFromData( $row );
}
/**
* Cleanup
*
* If your task takes longer than 15 minutes to run, this method
* will be called before execute(). Use it to clean up anything which
* may not have been done
*
* @return void
*/
public function cleanup()
{
}
}
@@ -2,10 +2,10 @@
/**
* @brief forumStatistics Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage forums
* @package IPS Community Suite
* @subpackage Forums
* @since 27 Mar 2014
* @version SVN_VERSION_NUMBER
*/
+4 -4
View File
@@ -2,10 +2,10 @@
/**
* @brief hotTopics Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage forums
* @package IPS Community Suite
* @subpackage Forums
* @since 2 Sep 2014
* @version SVN_VERSION_NUMBER
*/
@@ -64,7 +64,7 @@ class _hotTopics extends \IPS\Widget\PermissionCache
*/
public function render()
{
$topics = \IPS\forums\Topic::getItemsWithPermission( array( array( 'popular_time > ? AND forums_forums.password IS NULL AND forums_forums.can_view_others=1', time() ) ), NULL, isset( $this->configuration['number_to_show'] ) ? $this->configuration['number_to_show'] : 5 );
$topics = \IPS\forums\Topic::getItemsWithPermission( array( array( 'popular_time > ? AND forums_forums.password IS NULL AND forums_forums.can_view_others=1', time() ) ), NULL, isset( $this->configuration['number_to_show'] ) ? $this->configuration['number_to_show'] : 5, 'read', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY );
if ( count( $topics ) )
{
return $this->output( $topics );
+4 -4
View File
@@ -2,10 +2,10 @@
/**
* @brief poll Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage forums
* @package IPS Community Suite
* @subpackage Forums
* @since 21 Jul 2015
* @version SVN_VERSION_NUMBER
*/
@@ -22,7 +22,7 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* poll Widget
*/
class _poll extends \IPS\Widget\PermissionCache
class _poll extends \IPS\Widget
{
/**
* @brief Widget Key
+8 -3
View File
@@ -2,10 +2,10 @@
/**
* @brief Topic Feed Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage forums
* @package IPS Community Suite
* @subpackage Forums
* @since 16 Oct 2014
* @version SVN_VERSION_NUMBER
*/
@@ -44,6 +44,11 @@ class _postFeed extends \IPS\Content\WidgetComment
*/
protected static $class = 'IPS\forums\Topic\Post';
/**
* @brief Moderator permission to generate caches on [optional]
*/
protected $moderatorPermissions = array( 'can_view_hidden_content', 'can_view_hidden_post' );
/**
* Get where clause
*
+4 -4
View File
@@ -2,10 +2,10 @@
/**
* @brief Topic Feed Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage forums
* @package IPS Community Suite
* @subpackage Forums
* @since 16 Oct 2014
* @version SVN_VERSION_NUMBER
*/
@@ -43,7 +43,7 @@ class _topicFeed extends \IPS\Content\Widget
* Class
*/
protected static $class = 'IPS\forums\Topic';
/**
* Get where clause
*