2580 lines
78 KiB
PHP
2580 lines
78 KiB
PHP
<?php
|
|
/**
|
|
* @brief Content Controller
|
|
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
|
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
|
* @license http://www.invisionpower.com/legal/standards/
|
|
* @package IPS Community Suite
|
|
* @since 5 Jul 2013
|
|
* @version SVN_VERSION_NUMBER
|
|
*/
|
|
|
|
namespace IPS\Content;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/**
|
|
* Content Controller
|
|
*/
|
|
class _Controller extends \IPS\Helpers\CoverPhoto\Controller
|
|
{
|
|
/**
|
|
* @brief Should views and item markers be updated by AJAX requests?
|
|
*/
|
|
protected $updateViewsAndMarkersOnAjax = FALSE;
|
|
|
|
/**
|
|
* Execute
|
|
*
|
|
* @return void
|
|
*/
|
|
public function execute()
|
|
{
|
|
/* We do this to prevent SQL errors with page offsets */
|
|
if ( isset( \IPS\Request::i()->page ) )
|
|
{
|
|
\IPS\Request::i()->page = intval( \IPS\Request::i()->page );
|
|
if ( !\IPS\Request::i()->page OR \IPS\Request::i()->page < 1 )
|
|
{
|
|
\IPS\Request::i()->page = 1;
|
|
}
|
|
}
|
|
|
|
/* Ensure JS loaded for forms/content functions such as moderation */
|
|
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_core.js', 'core' ) );
|
|
|
|
return parent::execute();
|
|
}
|
|
|
|
/**
|
|
* View Item
|
|
*
|
|
* @return \IPS\Content\Item|NULL
|
|
*/
|
|
protected function manage()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
/* If this is an AJAX request (like the topic hovercard), we don't want to do any of the below like update views and mark read */
|
|
if ( \IPS\Request::i()->isAjax() and !$this->updateViewsAndMarkersOnAjax )
|
|
{
|
|
/* But we do want to mark read if we are paging through the content */
|
|
if( $item instanceof \IPS\Content\ReadMarkers AND isset( \IPS\Request::i()->page ) AND \IPS\Request::i()->page AND $item->isLastPage() )
|
|
{
|
|
$item->markRead();
|
|
}
|
|
|
|
/* We also want to update the views if we have a page parameter */
|
|
if( $item instanceof \IPS\Content\ReadMarkers AND isset( \IPS\Request::i()->page ) AND \IPS\Request::i()->page )
|
|
{
|
|
|
|
$idColumn = $class::$databaseColumnId;
|
|
if ( in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
|
{
|
|
\IPS\Db::i()->insert( 'core_view_updates', array(
|
|
'classname' => $class,
|
|
'id' => $item->$idColumn
|
|
) );
|
|
}
|
|
}
|
|
|
|
|
|
return $item;
|
|
}
|
|
|
|
/* Do we need to convert any legacy URL parameters? */
|
|
if( $redirectToUrl = $item->checkForLegacyParameters() )
|
|
{
|
|
\IPS\Output::i()->redirect( $redirectToUrl );
|
|
}
|
|
|
|
/* Check we're on a valid page */
|
|
if ( isset( \IPS\Request::i()->page ) )
|
|
{
|
|
$paginationType = 'comment';
|
|
if ( isset( \IPS\Request::i()->tab ) and \IPS\Request::i()->tab === 'reviews' )
|
|
{
|
|
$paginationType = 'review';
|
|
}
|
|
|
|
$pageCount = call_user_func( array( $item, "{$paginationType}PageCount" ) );
|
|
if ( $pageCount and \IPS\Request::i()->page > $pageCount )
|
|
{
|
|
\IPS\Output::i()->redirect( call_user_func( array( $item, 'last' . ucfirst( $paginationType ) . 'PageUrl' ) ), NULL, 303 );
|
|
}
|
|
}
|
|
|
|
/* Update Views */
|
|
$idColumn = $class::$databaseColumnId;
|
|
if ( in_array( 'IPS\Content\Views', class_implements( $class ) ) AND isset( $class::$databaseColumnMap['views'] ) )
|
|
{
|
|
\IPS\Db::i()->insert( 'core_view_updates', array(
|
|
'classname' => $class,
|
|
'id' => $item->$idColumn
|
|
) );
|
|
}
|
|
|
|
/* Mark read */
|
|
if( $item instanceof \IPS\Content\ReadMarkers )
|
|
{
|
|
/* Note time last read before we mark it read so that the line is in the right place */
|
|
$item->timeLastRead();
|
|
|
|
if ( $item->isLastPage() )
|
|
{
|
|
$item->markRead();
|
|
}
|
|
}
|
|
|
|
/* Have we moved? */
|
|
if ( isset( $class::$databaseColumnMap['state'] ) AND isset( $class::$databaseColumnMap['moved_to'] ) )
|
|
{
|
|
$stateColumn = $class::$databaseColumnMap['state'];
|
|
$movedToColumn = $class::$databaseColumnMap['moved_to'];
|
|
$movedTo = explode( '&', $item->$movedToColumn );
|
|
|
|
if ( $item->$stateColumn == 'link' OR $item->$stateColumn == 'merged' )
|
|
{
|
|
try
|
|
{
|
|
$moved = $class::loadAndCheckPerms( $movedTo[0] );
|
|
\IPS\Output::i()->redirect( $moved->url(), '', 301 );
|
|
}
|
|
catch( \OutOfRangeException $e ) { }
|
|
}
|
|
}
|
|
|
|
/* Set navigation and title */
|
|
$this->_setBreadcrumbAndTitle( $item, FALSE );
|
|
|
|
/* Set meta tags */
|
|
\IPS\Output::i()->linkTags['canonical'] = (string) ( \IPS\Request::i()->page > 1 ) ? $item->url()->setQueryString( 'page', \IPS\Request::i()->page ) : $item->url() ;
|
|
\IPS\Output::i()->metaTags['description'] = $item->metaDescription();
|
|
\IPS\Output::i()->metaTags['og:title'] = $item->mapped( 'title' );
|
|
\IPS\Output::i()->metaTags['og:type'] = 'object';
|
|
\IPS\Output::i()->metaTags['og:url'] = (string) $item->url();
|
|
\IPS\Output::i()->metaTags['og:description'] = $item->metaDescription();
|
|
if( $item->mapped( 'updated' ) OR $item->mapped( 'last_comment' ) OR $item->mapped( 'last_review' ) )
|
|
{
|
|
\IPS\Output::i()->metaTags['og:updated_time'] = \IPS\DateTime::ts( $item->mapped( 'updated' ) ? $item->mapped( 'updated' ) : ( $item->mapped( 'last_comment' ) ? $item->mapped( 'last_comment' ) : $item->mapped( 'last_review' ) ) )->rfc3339();
|
|
}
|
|
|
|
/* Add contextual search options */
|
|
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_' . $item::$title ) ] = array( 'type' => mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ), 'item' => $item->$idColumn );
|
|
try
|
|
{
|
|
$container = $item->container();
|
|
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_' . $container::$nodeTitle ) ] = array( 'type' => mb_strtolower( str_replace( '\\', '_', mb_substr( $class, 4 ) ) ), 'nodes' => $container->_id );
|
|
}
|
|
catch ( \BadMethodCallException $e ) { }
|
|
|
|
/* Return */
|
|
return $item;
|
|
|
|
}
|
|
catch ( \LogicException $e )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX - check for new replies
|
|
*
|
|
* @return \IPS\Content\Item|NULL
|
|
*/
|
|
protected function checkForNewReplies()
|
|
{
|
|
/* If auto-polling isn't enabled, kill the polling now */
|
|
if ( !\IPS\Settings::i()->auto_polling_enabled )
|
|
{
|
|
\IPS\Output::i()->json( array( 'error' => 'auto_polling_disabled' ) );
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
|
|
/* no need for polling if the content item doesn't have comments */
|
|
if ( !isset( $class::$commentClass ) )
|
|
{
|
|
\IPS\Output::i()->json( array( 'error' => 'auto_polling_disabled' ) );
|
|
return;
|
|
}
|
|
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
$commentClass = $class::$commentClass;
|
|
$commentIdColumn = $commentClass::$databaseColumnId;
|
|
$commentDateColumn = $commentClass::$databaseColumnMap['date'];
|
|
|
|
/* The form field has an underscore, but this value is sent in a query string value without an underscore via AJAX */
|
|
if( ! \IPS\Request::i()->lastSeenID or ! \IPS\Member::loggedIn()->member_id )
|
|
{
|
|
\IPS\Output::i()->json( array( 'count' => 0 ) );
|
|
}
|
|
|
|
$lastComment = $commentClass::load( \IPS\Request::i()->lastSeenID );
|
|
$authorColumn = $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['author'];
|
|
|
|
$where = array();
|
|
|
|
/* Ignored Users */
|
|
if( ! \IPS\Member::loggedIn()->members_bitoptions['has_no_ignored_users'] )
|
|
{
|
|
$ignored = iterator_to_array( \IPS\Db::i()->select( 'ignore_ignore_id', 'core_ignored_users', array( 'ignore_owner_id=? and ignore_messages=?', \IPS\Member::loggedIn()->member_id, 1 ) ) );
|
|
if( count( $ignored ) )
|
|
{
|
|
$where[] = array( \IPS\Db::i()->in( $authorColumn, $ignored, TRUE ) );
|
|
}
|
|
}
|
|
|
|
/* We will fetch up to 200 comments - anything over this is excessive.
|
|
@see https://community.invisionpower.com/4bugtrack/active-reports/x-new-replies-doesnt-show-more-than-15-replies-r7192/ */
|
|
$newComments = $item->comments( 200, 0, 'date', 'asc', NULL, NULL, \IPS\DateTime::ts( $lastComment->$commentDateColumn ), array_merge( $where, array( "{$authorColumn} != " . \IPS\Member::loggedIn()->member_id ) ) );
|
|
|
|
if ( \IPS\Request::i()->type === 'count' )
|
|
{
|
|
$data = array(
|
|
'totalNewCount' => (int) count( $newComments ),
|
|
'count' => (int) count( $newComments ), /* This is here for legacy purposes only */
|
|
'perPage' => $class::getCommentsPerPage(),
|
|
'totalCount' => $item->mapped( 'num_comments' ),
|
|
'title' => $item->mapped( 'title' ) ,
|
|
'spillOverUrl' => $item->url( 'getNewComment' )
|
|
);
|
|
|
|
if( $data['count'] === 1 ){
|
|
$itemData = reset( $newComments );
|
|
$author = $itemData->author();
|
|
|
|
$data['name'] = htmlspecialchars( $author->name, \IPS\HTMLENTITIES | ENT_QUOTES, 'UTF-8', FALSE );
|
|
$data['photo'] = (string) $author->photo;
|
|
}
|
|
|
|
\IPS\Output::i()->json( $data );
|
|
}
|
|
else
|
|
{
|
|
$output = array();
|
|
$lastId = 0;
|
|
foreach ( $newComments as $newComment )
|
|
{
|
|
$output[] = $newComment->html();
|
|
$lastId = ( $newComment->$commentIdColumn > $lastId ) ? $newComment->$commentIdColumn : $lastId;
|
|
}
|
|
|
|
/* Only mark as read if we'll be staying on this page, otherise we'll be marking it read despite
|
|
the user not having seen everything */
|
|
if( (int) \IPS\Request::i()->showing + (int) count( $newComments ) <= $class::getCommentsPerPage() ){
|
|
$item->markRead();
|
|
}
|
|
}
|
|
|
|
\IPS\Output::i()->json( array(
|
|
'content' => $output,
|
|
'id' => $lastId,
|
|
'totalCount' => $item->mapped( 'num_comments' ),
|
|
'totalNewCount' => (int) count( $newComments ),
|
|
'perPage' => $class::getCommentsPerPage(),
|
|
'spillOverUrl' => $item->url( 'getNewComment' )
|
|
) );
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->json( $e->getMessage(), 500 );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Edit Item
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function edit()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
if ( !$item->canEdit() and !\IPS\Request::i()->form_submitted ) // We check if the form has been submitted to prevent the user loosing their content
|
|
{
|
|
throw new \OutOfRangeException;
|
|
}
|
|
|
|
$container = NULL;
|
|
try
|
|
{
|
|
$container = $item->container();
|
|
}
|
|
catch ( \BadMethodCallException $e ) {}
|
|
|
|
/* Build the form */
|
|
$form = $item->buildEditForm();
|
|
|
|
if ( $values = $form->values() )
|
|
{
|
|
if ( $item->canEdit() )
|
|
{
|
|
$item->processForm( $values );
|
|
if ( isset( $item::$databaseColumnMap['updated'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['updated'];
|
|
$item->$column = time();
|
|
}
|
|
|
|
if ( isset( $item::$databaseColumnMap['date'] ) and isset( $values[ $item::$formLangPrefix . 'date' ] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['date'];
|
|
|
|
if ( $values[ $item::$formLangPrefix . 'date' ] instanceof \IPS\DateTime )
|
|
{
|
|
$item->$column = $values[ $item::$formLangPrefix . 'date' ]->getTimestamp();
|
|
}
|
|
else
|
|
{
|
|
$item->$column = time();
|
|
}
|
|
}
|
|
|
|
$item->save();
|
|
$item->processAfterEdit( $values );
|
|
|
|
/* Moderator log */
|
|
\IPS\Session::i()->modLog( 'modlog__item_edit', array( $item::$title => FALSE, $item->url()->__toString() => FALSE, $item::$title => TRUE, $item->mapped( 'title' ) => FALSE ), $item );
|
|
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
else
|
|
{
|
|
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'edit_no_perm_err' );
|
|
}
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->editContentForm( \IPS\Member::loggedIn()->language()->addToStack( 'edit_title', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $item::$title ) ) ) ), $form );
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Log::debug( $e, 'content_debug' );
|
|
\IPS\Output::i()->error( 'edit_no_perm_err', '2S136/E', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Edit item's tags
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function editTags()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
/* Make sure tagging is supported in this class */
|
|
if ( !in_array( 'IPS\Content\Tags', class_implements( $class ) ) )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
/* Get the container as we'll need it for permission checking */
|
|
$container = NULL;
|
|
try
|
|
{
|
|
$container = $item->container();
|
|
}
|
|
catch ( \BadMethodCallException $e ) {}
|
|
|
|
/* Make sure we can edit and tag */
|
|
if ( ( !$item->canEdit() OR !$item::canTag( NULL, $container ) ) )
|
|
{
|
|
throw new \OutOfRangeException;
|
|
}
|
|
|
|
/* If the tag form field is generated, create the form, otherwise throw an exception */
|
|
if( $tagsField = $item::tagsFormField( $item, $container ) )
|
|
{
|
|
$form = new \IPS\Helpers\Form( 'form', \IPS\Member::loggedIn()->language()->checkKeyExists( $item::$formLangPrefix . '_save' ) ? $item::$formLangPrefix . '_save' : 'save' );
|
|
$form->class = 'ipsForm_vertical ipsForm_fullWidth';
|
|
|
|
$form->add( $tagsField );
|
|
}
|
|
else
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
/* If we are simply removing a tag, do it */
|
|
if( isset( \IPS\Request::i()->removeTag ) )
|
|
{
|
|
/* Get our current tags */
|
|
$existingTags = ( $item->prefix() ? array_merge( array( 'prefix' => $item->prefix() ), $item->tags() ) : $item->tags() );
|
|
|
|
/* Remove the tag from the array. Preserve index since it could be 'prefix' which we need to remember. */
|
|
foreach( $existingTags as $index => $tag )
|
|
{
|
|
if( $tag == \IPS\Request::i()->removeTag )
|
|
{
|
|
unset( $existingTags[ $index ] );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Now set the tags */
|
|
$name = $tagsField->name;
|
|
\IPS\Request::i()->$name = implode( ',', $existingTags );
|
|
|
|
if( isset( $existingTags['prefix'] ) )
|
|
{
|
|
$prefix = $tagsField->name . '_prefix';
|
|
\IPS\Request::i()->$prefix = $existingTags['prefix'];
|
|
|
|
$prefix = $tagsField->name . '_freechoice_prefix';
|
|
\IPS\Request::i()->$prefix = 'on';
|
|
}
|
|
|
|
$tagsField->setValue( FALSE, TRUE );
|
|
|
|
$submittedKey = $form->id . "_submitted";
|
|
\IPS\Request::i()->$submittedKey = 1;
|
|
}
|
|
|
|
/* Process the values */
|
|
if ( $values = $form->values() )
|
|
{
|
|
$item->setTags( $values[ $item::$formLangPrefix . 'tags' ] ?: array() );
|
|
|
|
/* If we edited tags for a topic, we have to manually update search index because it wants
|
|
the first comment and not the content item itself. */
|
|
if ( $item instanceof \IPS\Content\Item and $item::$firstCommentRequired and $item instanceof \IPS\Content\Searchable )
|
|
{
|
|
\IPS\Content\Search\Index::i()->index( $item->firstComment() );
|
|
}
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
/* Build html we'll need to display */
|
|
$toReturn = array( 'tags' => '', 'prefix' => '' );
|
|
|
|
foreach ( $item->tags() as $tag )
|
|
{
|
|
$toReturn['tags'] .= \IPS\Theme::i()->getTemplate( 'global', 'core' )->tag( $tag, $item->url() );
|
|
}
|
|
|
|
if( $item->prefix() )
|
|
{
|
|
$toReturn['prefix'] = \IPS\Theme::i()->getTemplate( 'global', 'core' )->prefix( $item->prefix( TRUE ), $item->prefix() );
|
|
}
|
|
|
|
\IPS\Output::i()->json( $toReturn );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
|
|
/* If we tried to delete a tag and this is an AJAX request, just return the error. If it's not AJAX, we
|
|
can just let the regular form output which will show the error. */
|
|
if( $tagsField->error AND \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->error( $tagsField->error, '1S136/13', 403, '' );
|
|
}
|
|
|
|
/* Show the output */
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->editTagsForm( $form );
|
|
}
|
|
catch ( \DomainException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'edit_no_tags_defined', '2S131/3', 403, 'edit_no_tags_defined_admin' );
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'edit_no_perm_err', '2S136/12', 403, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Quick Edit Title
|
|
*
|
|
* @return void
|
|
*/
|
|
public function ajaxEditTitle()
|
|
{
|
|
try
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
if ( !$item->canEdit() )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
$oldTitle = $item->mapped( 'title' );
|
|
|
|
$titleField = $item::$databaseColumnMap['title'];
|
|
$item->$titleField = \IPS\Request::i()->newTitle;
|
|
$idField = $item::$databaseColumnId;
|
|
$item->save();
|
|
|
|
/* rebuild the container last item data */
|
|
if ( ! $item->hidden() and ( $item->$idField === $item->container()->last_id ) )
|
|
{
|
|
$item->container()->seo_last_title = $item->title_seo;
|
|
$item->container()->last_title = $item->title;
|
|
$item->container()->save();
|
|
|
|
foreach( $item->container()->parents() AS $parent )
|
|
{
|
|
if ( ( $item::$databaseColumnId === $parent->last_id ) )
|
|
{
|
|
$parent->seo_last_title = $item->title_seo;
|
|
$parent->last_title = $item->title;
|
|
$parent->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $item instanceof \IPS\Content\Searchable )
|
|
{
|
|
\IPS\Content\Search\Index::i()->index( $item );
|
|
}
|
|
|
|
\IPS\Session::i()->modLog( 'modlog__comment_edit_title', array( (string) $item->url() => FALSE, $item->$titleField => FALSE, $oldTitle => FALSE ), $item );
|
|
|
|
\IPS\Output::i()->json( 'OK' );
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/11', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the breadcrumb and title
|
|
*
|
|
* @param \IPS\Content\Item $item Content item
|
|
* @param bool $link Link the content item element in the breadcrumb
|
|
* @return void
|
|
*/
|
|
protected function _setBreadcrumbAndTitle( $item, $link=TRUE )
|
|
{
|
|
$container = NULL;
|
|
try
|
|
{
|
|
$container = $item->container();
|
|
foreach ( $container->parents() as $parent )
|
|
{
|
|
\IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
|
|
}
|
|
\IPS\Output::i()->breadcrumb[] = array( $container->url(), $container->_title );
|
|
}
|
|
catch ( \Exception $e ) { }
|
|
\IPS\Output::i()->breadcrumb[] = array( $link ? $item->url() : NULL, $item->mapped( 'title' ) );
|
|
|
|
$title = ( isset( \IPS\Request::i()->page ) and \IPS\Request::i()->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $item->mapped( 'title' ), \IPS\Request::i()->page ) ) ) : $item->mapped( 'title' );
|
|
\IPS\Output::i()->title = $container ? ( $title . ' - ' . $container->_stripTagsTitle ) : $title;
|
|
}
|
|
|
|
/**
|
|
* Toggle a poll status
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function pollStatus()
|
|
{
|
|
try
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
if ( ! \IPS\Member::loggedIn()->modPermission('can_close_polls') )
|
|
{
|
|
\IPS\Output::i()->error( 'no_permission', '2S136/Z', 403, '' );
|
|
}
|
|
|
|
if ( $poll = $item->getPoll() )
|
|
{
|
|
$poll->poll_closed = ( \IPS\Request::i()->value == 1 ? 0 : 1 );
|
|
$poll->save();
|
|
|
|
\IPS\Output::i()->redirect( $item->url(), ( \IPS\Request::i()->value == 1 ? 'poll_status_opened' : 'poll_status_closed' ) );
|
|
}
|
|
else
|
|
{
|
|
throw new \UnderflowException;
|
|
}
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/Y', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Moderate
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function moderate()
|
|
{
|
|
try
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
if ( $item::$hideLogKey and \IPS\Request::i()->action === 'hide' )
|
|
{
|
|
/* If this is an AJAX request, and we're coming from the approval queue, just do it. */
|
|
if ( \IPS\Request::i()->isAjax() AND isset( \IPS\Request::i()->_fromApproval ) )
|
|
{
|
|
$item->modAction( \IPS\Request::i()->action );
|
|
\IPS\Output::i()->json( 'OK' );
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
|
|
$form = new \IPS\Helpers\Form;
|
|
$form->add( new \IPS\Helpers\Form\Text( 'hide_reason' ) );
|
|
if ( $values = $form->values() )
|
|
{
|
|
$item->modAction( \IPS\Request::i()->action, NULL, $values['hide_reason'] );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$item->modAction( \IPS\Request::i()->action );
|
|
}
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->json( 'OK' );
|
|
}
|
|
else
|
|
{
|
|
if( \IPS\Request::i()->action == 'delete' )
|
|
{
|
|
\IPS\Output::i()->redirect( $item->container()->url() );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url(), 'mod_confirm_' . \IPS\Request::i()->action );
|
|
}
|
|
}
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/1', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Move
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function move()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
if ( !$item->canMove() )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
$container = $item->container();
|
|
|
|
$form = new \IPS\Helpers\Form( 'form', \IPS\Member::loggedIn()->language()->addToStack( 'move_send_to_container', FALSE, array( 'sprintf' => $container->_title ) ), NULL, array( 'data-bypassValidation' => true ) );
|
|
$form->actionButtons[] = \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->button( \IPS\Member::loggedIn()->language()->addToStack( 'move_send_to_item', FALSE, array( 'sprintf' => $item->definiteArticle() ) ), 'submit', null, 'ipsButton ipsButton_link', array( 'tabindex' => '3', 'accesskey' => 'i', 'value' => 'item', 'name' => 'returnto' ) );
|
|
$form->class = 'ipsForm_vertical';
|
|
$form->add( new \IPS\Helpers\Form\Node( 'move_to', NULL, TRUE, array(
|
|
'class' => get_class( $item->container() ),
|
|
'permissionCheck' => function( $node ) use ( $item )
|
|
{
|
|
if ( $node->id != $item->container()->id )
|
|
{
|
|
try
|
|
{
|
|
if ( $node->can( 'add' ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
catch( \OutOfBoundsException $e ) { }
|
|
}
|
|
|
|
return false;
|
|
}
|
|
) ) );
|
|
|
|
if ( isset( $class::$databaseColumnMap['moved_to'] ) )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Checkbox( 'move_keep_link' ) );
|
|
|
|
if ( \IPS\Settings::i()->topic_redirect_prune )
|
|
{
|
|
\IPS\Member::loggedIn()->language()->words['move_keep_link_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '_move_keep_link_desc', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->topic_redirect_prune ) ) );
|
|
}
|
|
}
|
|
|
|
if ( $values = $form->values() )
|
|
{
|
|
if ( $values['move_to'] === NULL OR !$values['move_to']->can( 'add' ) OR $values['move_to']->id == $item->container()->id )
|
|
{
|
|
\IPS\Output::i()->error( 'node_move_invalid', '1S136/L', 403, '' );
|
|
}
|
|
|
|
$item->move( $values['move_to'], isset( $values['move_keep_link'] ) ? $values['move_keep_link'] : FALSE );
|
|
\IPS\Session::i()->modLog( 'modlog__action_move', array( $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) ?: ( method_exists( $item, 'item' ) ? $item->item()->mapped( 'title' ) : NULL ) => FALSE ), $item );
|
|
|
|
\IPS\Output::i()->redirect( ( isset( \IPS\Request::i()->returnto ) AND \IPS\Request::i()->returnto == 'item' ) ? $item->url() : $container->url() );
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'move_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $class::$title ) ) ) );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/D', 403, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merge
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function merge()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
if ( !$item->canMerge() )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
$form = new \IPS\Helpers\Form( 'form', 'merge' );
|
|
$form->class = 'ipsForm_vertical';
|
|
$form->add( new \IPS\Helpers\Form\Url( 'merge_with', NULL, TRUE, array(), function ( $val ) use ( $class, $item )
|
|
{
|
|
try
|
|
{
|
|
$toMerge = $class::loadFromUrl( $val );
|
|
if ( $toMerge == $item )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_url_bad_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $class::$title, FALSE, array( 'strtolower' => TRUE ) ) ) ) ) );
|
|
}
|
|
|
|
} ) );
|
|
\IPS\Member::loggedIn()->language()->words['merge_with_desc'] = \IPS\Member::loggedIn()->language()->addToStack( 'merge_with__desc', FALSE, array( 'sprintf' => array( $item->indefiniteArticle(), $item->mapped( 'title' ) ) ) );
|
|
if ( isset( $class::$databaseColumnMap['moved_to'] ) )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Checkbox( 'move_keep_link' ) );
|
|
|
|
if ( \IPS\Settings::i()->topic_redirect_prune )
|
|
{
|
|
\IPS\Member::loggedIn()->language()->words['move_keep_link_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '_move_keep_link_desc', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->topic_redirect_prune ) ) );
|
|
}
|
|
}
|
|
if ( $values = $form->values() )
|
|
{
|
|
$item->mergeIn( array( $class::loadFromUrl( $values['merge_with'] ) ), isset( $values['move_keep_link'] ) ? $values['move_keep_link'] : FALSE );
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'merge_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $class::$title ) ) ) );
|
|
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/G', 403, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send email
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function email()
|
|
{
|
|
/* Share link enabled */
|
|
$node = \IPS\core\ShareLinks\Service::load( 'email', 'share_key' );
|
|
|
|
if( !( $node->enabled and ( $node->groups === "*" or \IPS\Member::loggedIn()->inGroup( explode( ',', $node->groups ) ) ) ) )
|
|
{
|
|
\IPS\Output::i()->error( 'no_module_permission', '2S136/N', 403, '' );
|
|
}
|
|
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
if ( $item instanceof \IPS\Content\Shareable )
|
|
{
|
|
$form = new \IPS\Helpers\Form( 'form', 'send' );
|
|
$form->class = 'ipsForm_vertical';
|
|
|
|
if( !\IPS\Member::loggedIn()->member_id )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Text( 'mail_from_name', NULL, TRUE ) );
|
|
$form->add( new \IPS\Helpers\Form\Email( 'mail_from_email', NULL, TRUE ) );
|
|
}
|
|
$form->add( new \IPS\Helpers\Form\Text( 'email_subject', $item->mapped( 'title' ), TRUE, array( 'maxLength' => 255 ) ) );
|
|
$form->add( new \IPS\Helpers\Form\Email( 'email_email', NULL, TRUE ) );
|
|
|
|
$idColumn = $class::$databaseColumnId;
|
|
$url = $item->url();
|
|
|
|
if ( \IPS\Request::i()->comment )
|
|
{
|
|
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->comment ) );
|
|
}
|
|
|
|
$defaultEmail = \IPS\Member::loggedIn()->language()->addToStack( 'default_email_content', FALSE, array( 'sprintf' => array( $item->mapped( 'title' ), $url ) ) );
|
|
$form->add( new \IPS\Helpers\Form\Editor( 'email_content', $defaultEmail, TRUE, array( 'app' => 'core', 'key' => 'ShareLinks', 'autoSaveKey' => 'contentEdit-' . $class::$application . '/' . $class::$module . '-' . $item->$idColumn ) ) );
|
|
|
|
if( !\IPS\Member::loggedIn()->member_id )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Captcha );
|
|
}
|
|
|
|
if( $values = $form->values() )
|
|
{
|
|
$fromName = ( isset( $values['mail_from_name'] ) ) ? $values['mail_from_name'] : \IPS\Member::loggedIn()->name;
|
|
$email = \IPS\Email::buildFromContent( $values['email_subject'], \IPS\Email::staticParseTextForEmail( $values['email_content'], \IPS\Member::loggedIn()->language() ) )
|
|
->send( $values['email_email'], array(), array(), NULL, $fromName, array(
|
|
'Reply-To' => \IPS\Email::encodeHeader( $fromName, isset( $values['mail_from_email'] ) ? $values['mail_from_email'] : \IPS\Member::loggedIn()->email )
|
|
) );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
$url = $item->url();
|
|
|
|
if ( \IPS\Request::i()->comment )
|
|
{
|
|
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => \IPS\Request::i()->comment ) );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $url, 'email_sent' );
|
|
}
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'send_email_form_with_title', FALSE, array( 'sprintf' => array( $item->mapped( 'title' ) ) ) );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
}
|
|
else
|
|
{
|
|
throw new \BadMethodCallException;
|
|
}
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/5', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Report Item
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function report()
|
|
{
|
|
try
|
|
{
|
|
/* Init */
|
|
$class = static::$contentModel;
|
|
$commentClass = $class::$commentClass;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
/* Permission check */
|
|
$canReport = $item->canReport();
|
|
if ( $canReport !== TRUE )
|
|
{
|
|
\IPS\Output::i()->error( $canReport, '2S136/6', 404, '' );
|
|
}
|
|
|
|
/* Show form */
|
|
$form = new \IPS\Helpers\Form( NULL, 'report_submit' );
|
|
$form->class = 'ipsForm_vertical';
|
|
$idColumn = $class::$databaseColumnId;
|
|
$form->add( new \IPS\Helpers\Form\Editor( 'report_message', NULL, FALSE, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$idColumn}", 'minimize' => 'report_message_placeholder' ) ) );
|
|
if( !\IPS\Member::loggedIn()->member_id )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Captcha );
|
|
}
|
|
if ( $values = $form->values() )
|
|
{
|
|
$report = $item->report( $values['report_message'] );
|
|
\IPS\File::claimAttachments( "report-{$class::$application}-{$class::$module}-{$item->$idColumn}", $report->id );
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Member::loggedIn()->language()->addToStack( 'report_submit_success' ) );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url(), 'report_submit_success' );
|
|
}
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
|
|
/* Even if guests can report something, we don't want the report form indexed in Google */
|
|
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
|
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
}
|
|
catch ( \LogicException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/7', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Next Unread Item
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function nextUnread()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
$next = $item->nextUnread();
|
|
|
|
if ( $next instanceof \IPS\Content\Item )
|
|
{
|
|
\IPS\Output::i()->redirect( $next->url()->setQueryString( array( 'do' => 'getNewComment' ) ) );
|
|
}
|
|
}
|
|
catch( \Exception $e )
|
|
{
|
|
\IPS\Output::i()->error( 'next_unread_not_found', '2S136/J', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rep Item
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function rep()
|
|
{
|
|
try
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
$type = intval( \IPS\Request::i()->rep ) === 1 ? 1 : -1;
|
|
$item->giveReputation( $type );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
if ( \IPS\Request::i()->mini )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->reputationMini( $item->reputation(), $item->canGiveReputation( 1 ), $item->canGiveReputation( -1 ), $item->url( 'showRep' ), $item->url( 'rep' ) ) );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->reputation( $item ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
catch ( \DomainException $e )
|
|
{
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->json( array( 'error' => \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() ) ), 403 );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->error( $e->getMessage(), '1S136/H', 403, '' );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show Comment/Review Rep
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function showRep()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
/* Set navigation */
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
|
|
/* Adjust page title */
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'see_who_repped' ) . ' - '. \IPS\Output::i()->title;
|
|
\IPS\Output::i()->output = $item->reputationTable();
|
|
}
|
|
catch ( \OutOfRangeException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/O', 404, '' );
|
|
}
|
|
catch( \DomainException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'no_module_permission', '2S136/P', 403, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Moderator Log
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function modLog()
|
|
{
|
|
if( !\IPS\Member::loggedIn()->modPermission( 'can_view_moderation_log' ) )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
/* Set navigation */
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
|
|
\IPS\Output::i()->output = $item->moderationTable();
|
|
}
|
|
catch ( \OutOfRangeException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/T', 404, '' );
|
|
}
|
|
catch( \DomainException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'no_module_permission', '2S136/U', 403, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Go to new comment.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function getNewComment()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
$timeLastRead = $item->timeLastRead();
|
|
|
|
if ( $timeLastRead instanceof \IPS\DateTime )
|
|
{
|
|
$comment = NULL;
|
|
if( \IPS\DateTime::ts( $item->mapped('date') ) < $timeLastRead )
|
|
{
|
|
$comment = $item->comments( 1, NULL, 'date', 'asc', NULL, NULL, $timeLastRead );
|
|
}
|
|
|
|
/* If we don't have any unread comments... */
|
|
if ( !$comment and $class::$firstCommentRequired )
|
|
{
|
|
/* If we haven't read the item at all, go there */
|
|
if ( $item->unread() )
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
/* Otherwise, go to the last comment */
|
|
else
|
|
{
|
|
$comment = $item->comments( 1, NULL, 'date', 'desc' );
|
|
}
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $comment ? $comment->url() : $item->url() );
|
|
}
|
|
else
|
|
{
|
|
if ( $item->unread() )
|
|
{
|
|
/* If we do not have a time last read set for this content, fallback to the reset time */
|
|
$resetTimes = \IPS\Member::loggedIn()->markersResetTimes( $class::$application );
|
|
|
|
if ( array_key_exists( $item->container()->_id, $resetTimes ) and $item->mapped('date') < $resetTimes[ $item->container()->_id ] )
|
|
{
|
|
$comment = $item->comments( 1, NULL, 'date', 'asc', NULL, NULL, \IPS\DateTime::ts( $resetTimes[ $item->container()->_id ] ) );
|
|
|
|
if ( $class::$firstCommentRequired and $comment->isFirst() )
|
|
{
|
|
/* link https://community.invisionpower.com/4bugtrack/active-reports/go-to-unread-link-also-links-to-the-fist-postcomment-even-for-totally-unread-content-r7864/ */
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $comment ? $comment->url() : $item->url() );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
}
|
|
catch( \BadMethodCallException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/I', 404, '' );
|
|
}
|
|
catch( \OutOfRangeException $e )
|
|
{
|
|
$class = static::$contentModel;
|
|
|
|
try
|
|
{
|
|
$item = $class::load( \IPS\Request::i()->id );
|
|
$error = ( !$item->canView() and ( $item->containerWrapper( TRUE ) and method_exists( $item->container(), 'errorMessage' ) ) ) ? $item->container()->errorMessage() : 'node_error';
|
|
}
|
|
catch( \OutOfRangeException $e )
|
|
{
|
|
$error = 'node_error';
|
|
}
|
|
|
|
\IPS\Output::i()->error( $error, '2S136/V', 404, '' );
|
|
}
|
|
catch( \LogicException $e )
|
|
{
|
|
$class = static::$contentModel;
|
|
|
|
try
|
|
{
|
|
$item = $class::load( \IPS\Request::i()->id );
|
|
$error = ( !$item->canView() and ( $item->containerWrapper( TRUE ) and method_exists( $item->container(), 'errorMessage' ) ) ) ? $item->container()->errorMessage() : 'node_error';
|
|
}
|
|
catch( \OutOfRangeException $e )
|
|
{
|
|
$error = 'node_error';
|
|
}
|
|
|
|
\IPS\Output::i()->error( $error, '2S136/R', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Go to last comment
|
|
*
|
|
* @return void
|
|
*/
|
|
public function getLastComment()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
$comment = $item->comments( 1, NULL, 'date', 'desc' );
|
|
|
|
if ( $comment !== NULL )
|
|
{
|
|
\IPS\Output::i()->redirect( $comment->url() );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
catch( \BadMethodCallException $e )
|
|
{
|
|
try
|
|
{
|
|
$item = $class::load( \IPS\Request::i()->id );
|
|
$error = ( !$item->canView() and ( $item->containerWrapper( TRUE ) and method_exists( $item->container(), 'errorMessage' ) ) ) ? $item->container()->errorMessage() : 'node_error';
|
|
}
|
|
catch( \OutOfRangeException $e )
|
|
{
|
|
$error = 'node_error';
|
|
}
|
|
|
|
\IPS\Output::i()->error( $error, '2S136/K', 404, '' );
|
|
}
|
|
catch( \LogicException $e )
|
|
{
|
|
try
|
|
{
|
|
$item = $class::load( \IPS\Request::i()->id );
|
|
$error = ( !$item->canView() and ( $item->containerWrapper( TRUE ) and method_exists( $item->container(), 'errorMessage' ) ) ) ? $item->container()->errorMessage() : 'node_error';
|
|
}
|
|
catch( \OutOfRangeException $e )
|
|
{
|
|
$error = 'node_error';
|
|
}
|
|
|
|
\IPS\Output::i()->error( $error, '2S136/Q', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Go to first comment
|
|
*
|
|
* @return void
|
|
*/
|
|
public function getFirstComment()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
if ( $class::$firstCommentRequired )
|
|
{
|
|
$comments = $item->comments( 2, NULL, 'date', 'asc' );
|
|
$comment = array_pop( $comments );
|
|
unset( $comments );
|
|
}
|
|
else
|
|
{
|
|
$comment = $item->comments( 1, NULL, 'date', 'asc' );
|
|
}
|
|
|
|
if ( $comment !== NULL )
|
|
{
|
|
\IPS\Output::i()->redirect( $comment->url() );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
catch( \BadMethodCallException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/W', 404, '' );
|
|
}
|
|
catch( \LogicException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/X', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rate Review as helpful/unhelpful
|
|
*
|
|
* @return void
|
|
*/
|
|
public function rateReview()
|
|
{
|
|
try
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
/* Only logged in members */
|
|
if ( !\IPS\Member::loggedIn()->member_id )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
/* Init */
|
|
$class = static::$contentModel;
|
|
$reviewClass = $class::$reviewClass;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
$review = $reviewClass::load( \IPS\Request::i()->review );
|
|
|
|
/* Review authors can't rate their own reviews */
|
|
if ( $review->author()->member_id === \IPS\Member::loggedIn()->member_id )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
/* Have we already rated? */
|
|
$dataColumn = $reviewClass::$databaseColumnMap['votes_data'];
|
|
$votesData = $review->mapped( 'votes_data' ) ? json_decode( $review->mapped( 'votes_data' ), TRUE ) : array();
|
|
if ( array_key_exists( \IPS\Member::loggedIn()->member_id, $votesData ) )
|
|
{
|
|
\IPS\Output::i()->error( 'you_have_already_rated', '2S136/A', 403, '' );
|
|
}
|
|
|
|
/* Add it */
|
|
$votesData[ \IPS\Member::loggedIn()->member_id ] = intval( \IPS\Request::i()->helpful );
|
|
if ( \IPS\Request::i()->helpful )
|
|
{
|
|
$helpful = $reviewClass::$databaseColumnMap['votes_helpful'];
|
|
$review->$helpful++;
|
|
}
|
|
$total = $reviewClass::$databaseColumnMap['votes_total'];
|
|
$review->$total++;
|
|
$review->$dataColumn = json_encode( $votesData );
|
|
$review->save();
|
|
|
|
/* Boink */
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->json( $review->html() );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $review->url() );
|
|
}
|
|
}
|
|
catch ( \LogicException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/9', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stuff that applies to both comments and reviews
|
|
*
|
|
* @param string $method Desired method
|
|
* @param array $args Arguments
|
|
* @return void
|
|
*/
|
|
public function __call( $method, $args )
|
|
{
|
|
$class = static::$contentModel;
|
|
|
|
try
|
|
{
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
$comment = NULL;
|
|
if ( mb_substr( $method, -7 ) === 'Comment' )
|
|
{
|
|
if ( isset( $class::$commentClass ) )
|
|
{
|
|
$class = $class::$commentClass;
|
|
$method = '_' . mb_substr( $method, 0, mb_strlen( $method ) - 7 );
|
|
|
|
$comment = $method === '_multimod' ? NULL : $class::load( \IPS\Request::i()->comment );
|
|
}
|
|
}
|
|
elseif ( mb_substr( $method, -6 ) === 'Review' )
|
|
{
|
|
if ( isset( $class::$reviewClass ) )
|
|
{
|
|
$class = $class::$reviewClass;
|
|
$method = '_' . mb_substr( $method, 0, mb_strlen( $method ) - 6 );
|
|
$comment = $method === '_multimod' ? NULL : $class::load( \IPS\Request::i()->review );
|
|
}
|
|
}
|
|
|
|
if ( $method === '_multimod' )
|
|
{
|
|
$this->_multimod( $class, $item );
|
|
}
|
|
|
|
if ( !$comment or !method_exists( $this, $method ) )
|
|
{
|
|
\IPS\Output::i()->error( 'page_not_found', '2S136/B', 404, '' );
|
|
}
|
|
else
|
|
{
|
|
$this->$method( $class, $comment, $item );
|
|
}
|
|
}
|
|
catch ( \LogicException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/C', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find a Comment / Review (do=findComment/findReview)
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
*/
|
|
public function _find( $commentClass, $comment, $item )
|
|
{
|
|
$idColumn = $commentClass::$databaseColumnId;
|
|
$itemColumn = $commentClass::$databaseColumnMap['item'];
|
|
|
|
/* Note in the session that we were looking for this comment. This can be used
|
|
to set appropriate meta tag descriptions */
|
|
$_SESSION['_findComment'] = $comment->$idColumn;
|
|
|
|
/* Work out where the comment is in the item */
|
|
$where = array(
|
|
array( $commentClass::$databasePrefix . $itemColumn . '=?', $comment->$itemColumn ),
|
|
array( $commentClass::$databasePrefix . $idColumn . '<=?', $comment->$idColumn )
|
|
);
|
|
if ( $commentClass::commentWhere() !== NULL )
|
|
{
|
|
$where[] = $commentClass::commentWhere();
|
|
}
|
|
if ( $container = $item->containerWrapper() )
|
|
{
|
|
if ( $commentClass::modPermission( 'view_hidden', NULL, $container ) === FALSE )
|
|
{
|
|
if ( isset( $commentClass::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$where[] = array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['approved'] . '=?', 1 );
|
|
}
|
|
elseif( isset( $commentClass::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$where[] = array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['hidden'] . '=?', 0 );
|
|
}
|
|
}
|
|
}
|
|
$commentPosition = \IPS\Db::i()->select( 'COUNT(*) AS position', $commentClass::$databaseTable, $where )->first();
|
|
|
|
/* Now work out what page that makes it */
|
|
$url = $item->url();
|
|
|
|
if( $commentClass instanceof \IPS\Content\Review )
|
|
{
|
|
$perPage = $itemClass::$reviewsPerPage;
|
|
}
|
|
else
|
|
{
|
|
$perPage = $item::getCommentsPerPage();
|
|
}
|
|
|
|
$page = ceil( $commentPosition / $perPage );
|
|
if ( $page != 1 )
|
|
{
|
|
$url = $url->setQueryString( 'page', $page );
|
|
}
|
|
|
|
/* And redirect */
|
|
\IPS\Output::i()->redirect( $url->setFragment( 'comment-' . $comment->$idColumn ) );
|
|
}
|
|
|
|
/**
|
|
* Hide Comment/Review
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
public function _hide( $commentClass, $comment, $item )
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
/* If this is an AJAX request, and we're coming from the approval queue, just do it. */
|
|
if ( \IPS\Request::i()->isAjax() AND isset( \IPS\Request::i()->_fromApproval ) )
|
|
{
|
|
$comment->modAction( 'hide' );
|
|
\IPS\Output::i()->json( 'OK' );
|
|
}
|
|
|
|
if ( $comment::$hideLogKey )
|
|
{
|
|
$form = new \IPS\Helpers\Form;
|
|
$form->add( new \IPS\Helpers\Form\Text( 'hide_reason' ) );
|
|
if ( $values = $form->values() )
|
|
{
|
|
$comment->modAction( 'hide', NULL, $values['hide_reason'] );
|
|
}
|
|
else
|
|
{
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$comment->modAction( 'hide' );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $comment->url() );
|
|
}
|
|
|
|
/**
|
|
* Unhide Comment/Review
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
public function _unhide( $commentClass, $comment, $item )
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
$comment->modAction( 'unhide' );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( $comment->html(), 200, 'text/html' );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $comment->url() );
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Edit Comment/Review
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _edit( $commentClass, $comment, $item )
|
|
{
|
|
$class = static::$contentModel;
|
|
$valueField = $commentClass::$databaseColumnMap['content'];
|
|
$idField = $commentClass::$databaseColumnId;
|
|
$itemIdField = $item::$databaseColumnId;
|
|
|
|
if ( $comment->canEdit() )
|
|
{
|
|
$form = new \IPS\Helpers\Form( 'form', false );
|
|
$form->class = 'ipsForm_vertical';
|
|
$form->add( new \IPS\Helpers\Form\Editor( 'comment_value', $comment->$valueField, TRUE, array(
|
|
'app' => $class::$application,
|
|
'key' => ucfirst( $class::$module ),
|
|
'autoSaveKey' => 'editComment-' . $class::$application . '/' . $class::$module . '-' . $comment->$idField,
|
|
'attachIds' => $comment->attachmentIds()
|
|
) ) );
|
|
|
|
$form->addButton( 'save', 'submit', null, 'ipsButton ipsButton_primary ipsButton_fullWidth', array( 'tabindex' => '2', 'accesskey' => 's' ) );
|
|
|
|
$form->addButton( 'cancel', 'link', $item->url()->setQueryString( in_array( 'IPS\Content\Review', class_parents( $comment ) ) ? array( 'do' => 'findReview', 'review' => $comment->$idField ) : array( 'do' => 'findComment', 'comment' => $comment->$idField ) ), 'ipsButton ipsButton_link ipsButton_fullWidth', array( 'data-action' => 'cancelEditComment', 'data-comment-id' => $comment->$idField ) );
|
|
|
|
if ( $comment instanceof \IPS\Content\EditHistory and \IPS\Settings::i()->edit_log )
|
|
{
|
|
if ( \IPS\Settings::i()->edit_log == 2 or isset( $commentClass::$databaseColumnMap['edit_reason'] ) )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Text( 'comment_edit_reason', ( isset( $commentClass::$databaseColumnMap['edit_reason'] ) ) ? $comment->mapped( 'edit_reason' ) : NULL, FALSE, array( 'maxLength' => 255 ) ) );
|
|
}
|
|
if ( \IPS\Member::loggedIn()->group['g_append_edit'] )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Checkbox( 'comment_log_edit', FALSE ) );
|
|
}
|
|
}
|
|
|
|
if ( $values = $form->values() )
|
|
{
|
|
/* Log History */
|
|
if ( $comment instanceof \IPS\Content\EditHistory and \IPS\Settings::i()->edit_log )
|
|
{
|
|
$editIsPublic = \IPS\Member::loggedIn()->group['g_append_edit'] ? $values['comment_log_edit'] : TRUE;
|
|
|
|
if ( \IPS\Settings::i()->edit_log == 2 )
|
|
{
|
|
\IPS\Db::i()->insert( 'core_edit_history', array(
|
|
'class' => get_class( $comment ),
|
|
'comment_id' => $comment->$idField,
|
|
'member' => \IPS\Member::loggedIn()->member_id,
|
|
'time' => time(),
|
|
'old' => $comment->$valueField,
|
|
'new' => $values['comment_value'],
|
|
'public' => $editIsPublic,
|
|
'reason' => isset( $values['comment_edit_reason'] ) ? $values['comment_edit_reason'] : NULL,
|
|
) );
|
|
}
|
|
|
|
if ( isset( $commentClass::$databaseColumnMap['edit_reason'] ) and isset( $values['comment_edit_reason'] ) )
|
|
{
|
|
$field = $commentClass::$databaseColumnMap['edit_reason'];
|
|
$comment->$field = $values['comment_edit_reason'];
|
|
}
|
|
if ( isset( $commentClass::$databaseColumnMap['edit_time'] ) )
|
|
{
|
|
$field = $commentClass::$databaseColumnMap['edit_time'];
|
|
$comment->$field = time();
|
|
}
|
|
if ( isset( $commentClass::$databaseColumnMap['edit_member_id'] ) )
|
|
{
|
|
$field = $commentClass::$databaseColumnMap['edit_member_id'];
|
|
$comment->$field = \IPS\Member::loggedIn()->member_id;
|
|
}
|
|
if ( isset( $commentClass::$databaseColumnMap['edit_member_name'] ) )
|
|
{
|
|
$field = $commentClass::$databaseColumnMap['edit_member_name'];
|
|
$comment->$field = \IPS\Member::loggedIn()->name;
|
|
}
|
|
if ( isset( $commentClass::$databaseColumnMap['edit_show'] ) and $editIsPublic )
|
|
{
|
|
$field = $commentClass::$databaseColumnMap['edit_show'];
|
|
$comment->$field = \IPS\Member::loggedIn()->group['g_append_edit'] ? $values['comment_log_edit'] : TRUE;
|
|
}
|
|
else if( isset( $commentClass::$databaseColumnMap['edit_show'] ) )
|
|
{
|
|
$field = $commentClass::$databaseColumnMap['edit_show'];
|
|
$comment->$field = 0;
|
|
}
|
|
}
|
|
|
|
/* Do it */
|
|
$comment->editContents( $values['comment_value'] );
|
|
|
|
/* Moderator log */
|
|
\IPS\Session::i()->modLog( 'modlog__comment_edit', array( $comment->url()->__toString() => FALSE, $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) => FALSE ), $item );
|
|
|
|
/* Display */
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->output = $comment->html();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $comment->url() );
|
|
}
|
|
}
|
|
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->breadcrumb[] = array( NULL, in_array( 'IPS\Content\Review', class_parents( $commentClass ) )? \IPS\Member::loggedIn()->language()->addToStack( 'edit_review' ) : \IPS\Member::loggedIn()->language()->addToStack( 'edit_comment' ) );
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'edit_comment' ) . ' - ' . $item->mapped( 'title' );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
}
|
|
else
|
|
{
|
|
throw new \InvalidArgumentException;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete Comment/Review
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _delete( $commentClass, $comment, $item )
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
$currentPageCount = $item->commentPageCount();
|
|
|
|
$valueField = $commentClass::$databaseColumnMap['content'];
|
|
|
|
if ( $item::$firstCommentRequired and $comment->mapped( 'first' ) )
|
|
{
|
|
if ( $item->canDelete() )
|
|
{
|
|
$item->delete();
|
|
}
|
|
else
|
|
{
|
|
throw new \UnderflowException;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( $comment->canDelete() )
|
|
{
|
|
$comment->delete();
|
|
|
|
/* Log */
|
|
\IPS\Session::i()->modLog( 'modlog__comment_delete', array( $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) => FALSE ), $item );
|
|
}
|
|
else
|
|
{
|
|
throw new \UnexpectedValueException;
|
|
}
|
|
}
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
$currentPageCount = \IPS\Request::i()->page;
|
|
$newPageCount = $item->commentPageCount( TRUE );
|
|
if ( isset( \IPS\Request::i()->page ) AND $currentPageCount != $newPageCount )
|
|
{
|
|
/* If we are on page 2 and delete a comment, and there are 3 pages, we don't want to be sent to page 3 (that makes no sense).
|
|
Instead, we'll send you to the page requested. If it exists you'll be on the same page. If it doesn't, the controller will
|
|
handle sending you to the correct location */
|
|
\IPS\Output::i()->json( array( 'type' => 'redirect', 'total' => $item->mapped( 'num_comments' ), 'url' => (string) $item->url()->setQueryString( 'page', (int) \IPS\Request::i()->page ) ) );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->json( array( 'page' => $newPageCount, 'total' => $item->mapped( 'num_comments' ) ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Split Comment
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _split( $commentClass, $comment, $item )
|
|
{
|
|
if ( $comment->canSplit() )
|
|
{
|
|
$itemClass = $comment::$itemClass;
|
|
$idColumn = $itemClass::$databaseColumnId;
|
|
$commentIdColumn = $comment::$databaseColumnId;
|
|
|
|
/* Create a copy of the old item for logging */
|
|
$oldItem = $item;
|
|
|
|
/* Construct a form */
|
|
$form = $this->_splitForm( $item );
|
|
|
|
/* Handle submissions */
|
|
if ( $values = $form->values() )
|
|
{
|
|
/* Are we creating or using an existing? */
|
|
if ( isset( $values['_split_type'] ) and $values['_split_type'] === 'new' )
|
|
{
|
|
$item = $itemClass::createItem( $comment->author(), $comment->mapped( 'ip_address' ), \IPS\DateTime::ts( $comment->mapped( 'date' ) ), isset( $values[ $itemClass::$formLangPrefix . 'container' ] ) ? $values[ $itemClass::$formLangPrefix . 'container' ] : NULL );
|
|
$item->processForm( $values );
|
|
if ( isset( $itemClass::$databaseColumnMap['first_comment_id'] ) )
|
|
{
|
|
$firstCommentIdColumn = $itemClass::$databaseColumnMap['first_comment_id'];
|
|
$item->$firstCommentIdColumn = $comment->$commentIdColumn;
|
|
}
|
|
|
|
/* Does the first post require moderator approval? */
|
|
if ( $comment->hidden() === 1 )
|
|
{
|
|
if ( isset( $item::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['hidden'];
|
|
$item->$column = 1;
|
|
}
|
|
elseif ( isset( $item::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['approved'];
|
|
$item->$column = 0;
|
|
}
|
|
}
|
|
/* Or is it hidden? */
|
|
elseif ( $comment->hidden() === -1 )
|
|
{
|
|
if ( isset( $item::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['hidden'];
|
|
}
|
|
elseif ( isset( $item::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['approved'];
|
|
}
|
|
|
|
$item->$column = -1;
|
|
}
|
|
|
|
$item->save();
|
|
|
|
if( $comment->hidden() !== 0 )
|
|
{
|
|
if ( isset( $comment::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$column = $comment::$databaseColumnMap['hidden'];
|
|
$comment->$column = 0;
|
|
}
|
|
elseif ( isset( $comment::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$column = $comment::$databaseColumnMap['approved'];
|
|
$comment->$column = 1;
|
|
}
|
|
|
|
$comment->save();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$item = $itemClass::loadFromUrl( $values['_split_into_url'] );
|
|
}
|
|
|
|
$comment->move( $item );
|
|
$oldItem->rebuildFirstAndLastCommentData();
|
|
|
|
/* Log it */
|
|
\IPS\Session::i()->modLog( 'modlog__action_split', array(
|
|
$item::$title => FALSE,
|
|
$item->url()->__toString() => FALSE,
|
|
$item->mapped( 'title' ) => FALSE,
|
|
$oldItem->url()->__toString() => FALSE,
|
|
$oldItem->mapped( 'title' ) => FALSE
|
|
), $item );
|
|
|
|
/* Redirect to it */
|
|
\IPS\Output::i()->redirect( $item->url() );
|
|
}
|
|
|
|
/* Display */
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
}
|
|
else
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Edit Log
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
public function _editlog( $commentClass, $comment, $item )
|
|
{
|
|
/* Permission check */
|
|
if ( \IPS\Settings::i()->edit_log != 2 or ( !\IPS\Settings::i()->edit_log_public and !\IPS\Member::loggedIn()->modPermission( 'can_view_editlog' ) ) )
|
|
{
|
|
throw new \DomainException;
|
|
}
|
|
|
|
/* Display */
|
|
$container = NULL;
|
|
try
|
|
{
|
|
$container = $item->container();
|
|
foreach ( $container->parents() as $parent )
|
|
{
|
|
\IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
|
|
}
|
|
\IPS\Output::i()->breadcrumb[] = array( $container->url(), $container->_title );
|
|
}
|
|
catch ( \Exception $e ) { }
|
|
\IPS\Output::i()->breadcrumb[] = array( $comment->url(), $item->mapped( 'title' ) );
|
|
\IPS\Output::i()->breadcrumb[] = array( NULL, \IPS\Member::loggedIn()->language()->addToStack( 'edit_history_title' ) );
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'edit_history_title' );
|
|
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->commentEditHistory( $comment->editHistory( \IPS\Member::loggedIn()->modPermission( 'can_view_editlog' ) ), $comment );
|
|
}
|
|
|
|
/**
|
|
* Report Comment/Review
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _report( $commentClass, $comment, $item )
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
|
|
/* Permission check */
|
|
$canReport = $comment->canReport();
|
|
if ( $canReport !== TRUE )
|
|
{
|
|
\IPS\Output::i()->error( $canReport, '2S136/4', 404, '' );
|
|
}
|
|
|
|
/* Show form */
|
|
$form = new \IPS\Helpers\Form( NULL, 'report_submit' );
|
|
$form->class = 'ipsForm_vertical';
|
|
$itemIdColumn = $class::$databaseColumnId;
|
|
$idColumn = $comment::$databaseColumnId;
|
|
$form->add( new \IPS\Helpers\Form\Editor( 'report_message', NULL, FALSE, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$itemIdColumn}-{$comment->$idColumn}", 'minimize' => 'report_message_placeholder' ) ) );
|
|
if( !\IPS\Member::loggedIn()->member_id )
|
|
{
|
|
$form->add( new \IPS\Helpers\Form\Captcha );
|
|
}
|
|
|
|
if ( $values = $form->values() )
|
|
{
|
|
$report = $comment->report( $values['report_message'] );
|
|
\IPS\File::claimAttachments( "report-{$class::$application}-{$class::$module}-{$item->$itemIdColumn}-{$comment->$idColumn}", $report->id );
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Member::loggedIn()->language()->addToStack( 'report_submit_success' ) );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $comment->url(), 'report_submit_success' );
|
|
}
|
|
}
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
|
|
/* Even if guests can report something, we don't want the report form indexed in Google */
|
|
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
|
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
}
|
|
catch ( \LogicException $e )
|
|
{
|
|
\IPS\Output::i()->error( 'node_error', '2S136/10', 404, '' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rep Comment/Review
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _rep( $commentClass, $comment, $item )
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
|
|
$type = intval( \IPS\Request::i()->rep ) === 1 ? 1 : -1;
|
|
|
|
try
|
|
{
|
|
$comment->giveReputation( $type );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->reputation( $comment ) );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->redirect( $comment->url() );
|
|
}
|
|
}
|
|
catch ( \DomainException $e )
|
|
{
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->json( array( 'error' => \IPS\Member::loggedIn()->language()->addToStack( $e->getMessage() ) ), 403 );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->error( $e->getMessage(), '1S136/M', 403, '' );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show Comment/Review Rep
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Comment $comment The comment/review
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _showRep( $commentClass, $comment, $item )
|
|
{
|
|
$idColumn = $commentClass::$databaseColumnId;
|
|
/* Set navigation */
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'see_who_repped' ) . ' (' . $comment->$idColumn . ') - '. \IPS\Output::i()->title;
|
|
|
|
if( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->output = $comment->reputationTable();
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->genericBlock( $comment->reputationTable(), \IPS\Member::loggedIn()->language()->addToStack( 'see_who_repped' ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Multimod
|
|
*
|
|
* @param string $commentClass The comment/review class
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return void
|
|
* @throws \LogicException
|
|
*/
|
|
protected function _multimod( $commentClass, $item )
|
|
{
|
|
\IPS\Session::i()->csrfCheck();
|
|
if ( \IPS\Request::i()->modaction == 'split' )
|
|
{
|
|
$form = $this->_splitForm( $item );
|
|
$form->hiddenValues['modaction'] = 'split';
|
|
foreach ( \IPS\Request::i()->multimod as $k => $v )
|
|
{
|
|
$form->hiddenValues['multimod['.$k.']'] = $v;
|
|
}
|
|
if ( $values = $form->values() )
|
|
{
|
|
$itemIdColumn = $item::$databaseColumnId;
|
|
$commentIdColumn = $commentClass::$databaseColumnId;
|
|
|
|
/* Create a copy of the old item for logging */
|
|
$oldItem = $item;
|
|
|
|
$comments = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select(
|
|
'*',
|
|
$commentClass::$databaseTable,
|
|
array(
|
|
array( $commentClass::$databasePrefix . $commentClass::$databaseColumnMap['item'] . '=?', $item->$itemIdColumn ),
|
|
\IPS\Db::i()->in( $commentClass::$databasePrefix . $commentClass::$databaseColumnId, array_keys( \IPS\Request::i()->multimod ) )
|
|
),
|
|
$commentClass::$databasePrefix . $commentClass::$databaseColumnMap['date']
|
|
), $commentClass );
|
|
|
|
foreach ( $comments as $comment )
|
|
{
|
|
$firstComment = $comment;
|
|
break;
|
|
}
|
|
|
|
if ( isset( $values['_split_type'] ) and $values['_split_type'] === 'new' )
|
|
{
|
|
$item = $item::createItem( $firstComment->author(), $firstComment->mapped( 'ip_address' ), \IPS\DateTime::ts( $firstComment->mapped( 'date' ) ), $values[ $item::$formLangPrefix . 'container' ] );
|
|
$item->processForm( $values );
|
|
if ( isset( $item::$databaseColumnMap['first_comment_id'] ) )
|
|
{
|
|
$firstCommentIdColumn = $item::$databaseColumnMap['first_comment_id'];
|
|
$item->$firstCommentIdColumn = $comment->$commentIdColumn;
|
|
}
|
|
|
|
/* Does the first post require moderator approval? */
|
|
if ( $firstComment->hidden() === 1 )
|
|
{
|
|
if ( isset( $item::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['hidden'];
|
|
$item->$column = 1;
|
|
}
|
|
elseif ( isset( $item::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['approved'];
|
|
$item->$column = 0;
|
|
}
|
|
}
|
|
/* Or is it hidden? */
|
|
elseif ( $firstComment->hidden() === -1 )
|
|
{
|
|
if ( isset( $item::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['hidden'];
|
|
}
|
|
elseif ( isset( $item::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$column = $item::$databaseColumnMap['approved'];
|
|
}
|
|
|
|
$item->$column = -1;
|
|
}
|
|
|
|
$item->save();
|
|
|
|
}
|
|
else
|
|
{
|
|
$item = $item::loadFromUrl( $values['_split_into_url'] );
|
|
}
|
|
|
|
foreach ( $comments as $comment )
|
|
{
|
|
if( $comment == $firstComment AND $comment->hidden() !== 0 )
|
|
{
|
|
if ( isset( $comment::$databaseColumnMap['hidden'] ) )
|
|
{
|
|
$column = $comment::$databaseColumnMap['hidden'];
|
|
$comment->$column = 0;
|
|
}
|
|
elseif ( isset( $comment::$databaseColumnMap['approved'] ) )
|
|
{
|
|
$column = $comment::$databaseColumnMap['approved'];
|
|
$comment->$column = 1;
|
|
}
|
|
|
|
$comment->save();
|
|
}
|
|
|
|
$comment->move( $item );
|
|
}
|
|
|
|
$item->rebuildFirstAndLastCommentData();
|
|
$oldItem->rebuildFirstAndLastCommentData();
|
|
|
|
/* Log it */
|
|
\IPS\Session::i()->modLog( 'modlog__action_split', array(
|
|
$item::$title => FALSE,
|
|
$item->url()->__toString() => FALSE,
|
|
$item->mapped( 'title' ) => FALSE,
|
|
$oldItem->url()->__toString() => FALSE,
|
|
$oldItem->mapped( 'title' ) => FALSE
|
|
), $item );
|
|
|
|
$url = $item->url();
|
|
|
|
if ( isset( \IPS\Request::i()->page ) )
|
|
{
|
|
$url = $url->setQueryString( 'page', (int) \IPS\Request::i()->page );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $url );
|
|
}
|
|
else
|
|
{
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Output::i()->output );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( \IPS\Output::i()->title, \IPS\Output::i()->output, array( 'app' => \IPS\Dispatcher::i()->application->directory, 'module' => \IPS\Dispatcher::i()->module->key, 'controller' => \IPS\Dispatcher::i()->controller ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
elseif ( \IPS\Request::i()->modaction == 'merge' )
|
|
{
|
|
if ( !( count( \IPS\Request::i()->multimod ) > 1 ) )
|
|
{
|
|
\IPS\Output::i()->error( 'cannot_merge_one_post', '1S136/S', 403, '' );
|
|
}
|
|
|
|
$comments = array();
|
|
$authors = array();
|
|
$content = array();
|
|
foreach( array_keys( \IPS\Request::i()->multimod ) AS $id )
|
|
{
|
|
try
|
|
{
|
|
$comments[$id] = $commentClass::loadAndCheckPerms( $id );
|
|
$content[] = $comments[$id]->mapped( 'content' );
|
|
}
|
|
catch( \Exception $e ) {}
|
|
}
|
|
|
|
$form = new \IPS\Helpers\Form;
|
|
$form->class = 'ipsForm_vertical';
|
|
$form->add( new \IPS\Helpers\Form\Editor( 'final_comment_content', implode( '<p> </p>', $content ), TRUE, array(
|
|
'app' => $item::$application,
|
|
'key' => ucwords( $item::$module ),
|
|
'autoSaveKey' => 'mod-merge-' . implode( '-', array_keys( $comments ) ),
|
|
) ) );
|
|
|
|
if ( $values = $form->values() )
|
|
{
|
|
$idColumn = $item::$databaseColumnId;
|
|
$commentIdColumn = $commentClass::$databaseColumnId;
|
|
$commentIds = array_keys( \IPS\Request::i()->multimod );
|
|
$firstComment = $commentClass::loadAndCheckPerms( array_shift( $commentIds ) );
|
|
$contentColumn = $commentClass::$databaseColumnMap['content'];
|
|
$firstComment->$contentColumn = $values['final_comment_content'];
|
|
$firstComment->save();
|
|
|
|
foreach( $commentIds AS $id )
|
|
{
|
|
try
|
|
{
|
|
$comment = $commentClass::loadAndCheckPerms( $id );
|
|
\IPS\Db::i()->update( 'core_attachments_map', array(
|
|
'id1' => $item->$idColumn,
|
|
'id2' => $firstComment->$commentIdColumn,
|
|
), array( 'location_key=? AND id1=? AND id2=?', (string) $item::$application . '_' . ucfirst( $item::$module ), $item->$idColumn, $comment->$commentIdColumn ) );
|
|
|
|
/* Merge likes */
|
|
if ( in_array( 'IPS\Content\Reputation', class_implements( $commentClass ) ) )
|
|
{
|
|
\IPS\Db::i()->update( 'core_reputation_index', array( 'type_id' => $firstComment->$commentIdColumn ), array( 'app=? and type=? and type_id=?', $item::$application, $comment::$reputationType, $id ) );
|
|
}
|
|
|
|
$comment->delete();
|
|
}
|
|
catch( \Exception $e ) {}
|
|
}
|
|
|
|
$item->rebuildFirstAndLastCommentData();
|
|
|
|
/* Log it */
|
|
\IPS\Session::i()->modLog( 'modlog__action_merge_comments', array(
|
|
$firstComment::$title => FALSE,
|
|
$firstComment->url()->__toString() => FALSE,
|
|
$firstComment->$commentIdColumn => FALSE,
|
|
), $item );
|
|
|
|
\IPS\Output::i()->redirect( $firstComment->url() );
|
|
}
|
|
else
|
|
{
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Output::i()->output );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( \IPS\Output::i()->title, \IPS\Output::i()->output, array( 'app' => \IPS\Dispatcher::i()->application->directory, 'module' => \IPS\Dispatcher::i()->module->key, 'controller' => \IPS\Dispatcher::i()->controller ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
elseif ( \IPS\Request::i()->modaction == 'hide' )
|
|
{
|
|
if ( $commentClass::$hideLogKey )
|
|
{
|
|
$form = new \IPS\Helpers\Form;
|
|
$form->class = 'ipsForm_vertical';
|
|
$form->add( new \IPS\Helpers\Form\Text( 'hide_reason' ) );
|
|
|
|
if ( $values = $form->values() )
|
|
{
|
|
foreach( array_keys( \IPS\Request::i()->multimod ) AS $id )
|
|
{
|
|
try
|
|
{
|
|
$comment = $commentClass::loadAndCheckPerms( $id );
|
|
$comment->modAction( 'hide', NULL, $values['hide_reason'] );
|
|
}
|
|
catch( \Exception $e ) { }
|
|
}
|
|
|
|
if( ! in_array( 'IPS\Content\Review', class_parents( $commentClass ) ) )
|
|
{
|
|
$item->rebuildFirstAndLastCommentData();
|
|
}
|
|
|
|
$url = $item->url();
|
|
|
|
if ( isset( \IPS\Request::i()->page ) )
|
|
{
|
|
$url = $url->setQueryString( 'page', (int) \IPS\Request::i()->page );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $url );
|
|
}
|
|
else
|
|
{
|
|
$this->_setBreadcrumbAndTitle( $item );
|
|
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\Theme::i(), 'getTemplate' ), array( 'forms', 'core' ) ), 'popupTemplate' ) );
|
|
|
|
if ( \IPS\Request::i()->isAjax() )
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Output::i()->output );
|
|
}
|
|
else
|
|
{
|
|
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( \IPS\Output::i()->title, \IPS\Output::i()->output, array( 'app' => \IPS\Dispatcher::i()->application->directory, 'module' => \IPS\Dispatcher::i()->module->key, 'controller' => \IPS\Dispatcher::i()->controller ) ), 200, 'text/html', \IPS\Output::i()->httpHeaders );
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach( array_keys( \IPS\Request::i()->multimod ) AS $id )
|
|
{
|
|
try
|
|
{
|
|
$comment = $commentClass::loadAndCheckPerms( $id );
|
|
$comment->modAction( 'hide' );
|
|
}
|
|
catch( \Exception $e ) { }
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
$object = NULL;
|
|
|
|
if( isset( \IPS\Request::i()->multimod ) AND is_array( \IPS\Request::i()->multimod ) )
|
|
{
|
|
foreach ( array_keys( \IPS\Request::i()->multimod ) as $id )
|
|
{
|
|
try
|
|
{
|
|
$object = $commentClass::loadAndCheckPerms( $id );
|
|
$object->modAction( \IPS\Request::i()->modaction, \IPS\Member::loggedIn() );
|
|
}
|
|
catch ( \Exception $e ) {}
|
|
}
|
|
}
|
|
|
|
$item->resyncCommentCounts();
|
|
$item->save();
|
|
|
|
if ( $object and \IPS\Request::i()->modaction != 'delete' )
|
|
{
|
|
$url = $object->url();
|
|
|
|
if ( isset( \IPS\Request::i()->page ) )
|
|
{
|
|
$url = $url->setQueryString( 'page', (int) \IPS\Request::i()->page );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $url );
|
|
}
|
|
else
|
|
{
|
|
$url = $item->url();
|
|
|
|
if ( isset( \IPS\Request::i()->page ) )
|
|
{
|
|
$url = $url->setQueryString( 'page', (int) \IPS\Request::i()->page );
|
|
}
|
|
|
|
\IPS\Output::i()->redirect( $url );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Form for splitting
|
|
*
|
|
* @param \IPS\Content\Item $item The item
|
|
* @return \IPS\Helpers\Form
|
|
*/
|
|
protected function _splitForm( \IPS\Content\Item $item )
|
|
{
|
|
try
|
|
{
|
|
$container = $item->container();
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
$container = NULL;
|
|
}
|
|
|
|
$form = new \IPS\Helpers\Form;
|
|
if ( $item::canCreate( \IPS\Member::loggedIn(), $container ) )
|
|
{
|
|
$toAdd = array();
|
|
$toggles = array();
|
|
|
|
foreach ( $item::formElements( $item ) as $k => $field )
|
|
{
|
|
if ( !in_array( $k, array( 'poll', 'content', 'comment_edit_reason', 'comment_log_edit' ) ) )
|
|
{
|
|
if ( $k === 'container' )
|
|
{
|
|
$field->defaultValue = $container;
|
|
if ( !$field->value )
|
|
{
|
|
$field->value = $field->defaultValue;
|
|
}
|
|
}
|
|
|
|
if ( !$field->htmlId )
|
|
{
|
|
$field->htmlId = $field->name;
|
|
}
|
|
$toggles[] = $field->htmlId;
|
|
|
|
$toAdd[] = $field;
|
|
}
|
|
}
|
|
|
|
$form->add( new \IPS\Helpers\Form\Radio( '_split_type', 'new', FALSE, array(
|
|
'options' => array(
|
|
'new' => \IPS\Member::loggedIn()->language()->addToStack( 'split_type_new', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $item::$title ) ) ) ),
|
|
'existing' => \IPS\Member::loggedIn()->language()->addToStack( 'split_type_existing', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $item::$title ) ) ) )
|
|
),
|
|
'toggles' => array( 'new' => $toggles, 'existing' => array( 'split_into_url' ) ),
|
|
) ) );
|
|
|
|
foreach ( $toAdd as $field )
|
|
{
|
|
$form->add( $field );
|
|
}
|
|
}
|
|
$form->add( new \IPS\Helpers\Form\Url( '_split_into_url', NULL, FALSE, array(), function ( $val ) use ( $item )
|
|
{
|
|
try
|
|
{
|
|
if ( $val )
|
|
{
|
|
$item::loadFromUrl( $val );
|
|
}
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_url_bad_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $item::$title ) ) ) ) );
|
|
}
|
|
|
|
}, NULL, NULL, 'split_into_url' ) );
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Retrieve content tagged the same
|
|
*
|
|
* @param \int $limit How many items should be returned
|
|
*
|
|
* @note Used with a widget, but can be used elsewhere too
|
|
* @return array|NULL
|
|
*/
|
|
public function getSimilarContent( $limit = 5 )
|
|
{
|
|
if( !isset( static::$contentModel ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
if( $item->tags() === NULL AND $item->prefix( FALSE ) === NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Store tags in array, so that we can add a prefix if set */
|
|
$tags = $item->tags() ?: array();
|
|
$tags[] = $item->prefix( FALSE );
|
|
|
|
$select = \IPS\Db::i()->select(
|
|
'tag_meta_app,tag_meta_area,tag_meta_id',
|
|
'core_tags',
|
|
array(
|
|
array( '(' . \IPS\Db::i()->in( 'tag_text', $tags ) . ')' ),
|
|
array( '!(tag_meta_app=? and tag_meta_area=? and tag_meta_id=?)', $class::$application, $class::$module, \IPS\Request::i()->id ),
|
|
array( '(' . \IPS\Db::i()->findInSet( 'tag_perm_text', \IPS\Member::loggedIn()->groups ) . ' OR ' . 'tag_perm_text=? )', '*' ),
|
|
array( 'tag_perm_visible=1' )
|
|
),
|
|
'tag_added DESC',
|
|
array( 0, $limit )
|
|
)->join(
|
|
'core_tags_perms',
|
|
array( 'tag_perm_aai_lookup=tag_aai_lookup' )
|
|
);
|
|
|
|
$items = array();
|
|
|
|
foreach( $select as $result )
|
|
{
|
|
foreach( \IPS\Application::load( $result['tag_meta_app'] )->extensions( 'core', 'ContentRouter' ) as $key => $router )
|
|
{
|
|
foreach( $router->classes AS $itemClass )
|
|
{
|
|
if( $itemClass::$module == $result['tag_meta_area'] )
|
|
{
|
|
try
|
|
{
|
|
$items[ $result['tag_meta_id'] ] = $itemClass::loadAndCheckPerms( $result['tag_meta_id'] );
|
|
break;
|
|
}
|
|
catch( \Exception $e ){}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return $items;
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Cover Photo Storage Extension
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function _coverPhotoStorageExtension()
|
|
{
|
|
$class = static::$contentModel;
|
|
return $class::$coverPhotoStorageExtension;
|
|
}
|
|
|
|
/**
|
|
* Set Cover Photo
|
|
*
|
|
* @param \IPS\Helpers\CoverPhoto $photo New Photo
|
|
* @return void
|
|
*/
|
|
protected function _coverPhotoSet( \IPS\Helpers\CoverPhoto $photo )
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
$photoColumn = $class::$databaseColumnMap['cover_photo'];
|
|
$item->$photoColumn = (string) $photo->file;
|
|
|
|
$offsetColumn = $class::$databaseColumnMap['cover_photo_offset'];
|
|
$item->$offsetColumn = (int) $photo->offset;
|
|
|
|
$item->save();
|
|
}
|
|
catch ( \OutOfRangeException $e ){}
|
|
}
|
|
|
|
/**
|
|
* Get Cover Photo
|
|
*
|
|
* @return \IPS\Helpers\CoverPhoto
|
|
*/
|
|
protected function _coverPhotoGet()
|
|
{
|
|
try
|
|
{
|
|
$class = static::$contentModel;
|
|
$item = $class::loadAndCheckPerms( \IPS\Request::i()->id );
|
|
|
|
return $item->coverPhoto();
|
|
}
|
|
catch ( \OutOfRangeException $e )
|
|
{
|
|
return new \IPS\Helpers\CoverPhoto;
|
|
}
|
|
}
|
|
} |