Файл: library/XenForo/Model/InlineMod/Thread.php
Строк: 1295
<?php
/**
* Model to handle inline mod-style actions on threads. Generally, these are simply
* bulk actions. They can be applied to other circumstances if desired.
*
* @package XenForo_Thread
*/
class XenForo_Model_InlineMod_Thread extends XenForo_Model
{
public $enableLogging = true;
/**
* Determines if the selected thread IDs can be generally edited (titles, prefixes etc.)
*
* @param array $threadIds List of thread IDs check
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canEditThreads(array $threadIds, &$errorKey = '', $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canEditThreadsData($threads, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be generally edited (titles, prefixes etc.)
*
* @param array $threads List of information about threads to be checked
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canEditThreadsData(array $threads, array $forums, &$errorKey = '', $viewingUser = null)
{
return $this->_checkPermissionOnThreads('canEditThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Apply a thread prefix to the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param integer $prefixId ID of the thread prefix to apply
* @param array $unchangedThreadIds Array of thread IDs that were not updated by this action
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function applyThreadPrefix(array $threadIds, $prefixId, &$unchangedThreadIds = array(), array $options = array(), &$errorKey = '', array $viewingUser = null)
{
$prefixModel = $this->_getPrefixModel();
$prefixPerms = array();
if (!$this->canEditThreads($threadIds, $errorKey, $viewingUser))
{
return false;
}
foreach ($threadIds AS $threadId)
{
$dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread', XenForo_DataWriter::ERROR_SILENT);
if (!$dw->setExistingData($threadId))
{
continue;
}
$thread = $dw->getMergedData();
$nodeId = $dw->get('node_id');
if (!isset($prefixPerms[$nodeId]))
{
$prefixPerms[$nodeId] = $prefixModel->verifyPrefixIsUsable($prefixId, $nodeId, $viewingUser);
}
if (!$prefixPerms[$nodeId])
{
$unchangedThreadIds[] = $threadId;
continue;
}
$dw->set('prefix_id', $prefixId);
$dw->save();
if ($thread['prefix_id'] != $prefixId)
{
if ($thread['prefix_id'])
{
$phrase = new XenForo_Phrase('thread_prefix_' . $thread['prefix_id']);
$oldValue = $phrase->render();
}
else
{
$oldValue = '-';
}
XenForo_Model_Log::logModeratorAction('thread', $thread, 'prefix', array('old' => $oldValue));
}
}
return true;
}
/**
* Determines if the selected thread IDs can be deleted.
*
* @param array $threadIds List of thread IDs check
* @param string $deleteType The type of deletion being requested (soft or hard)
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canDeleteThreads(array $threadIds, $deleteType = 'soft', &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canDeleteThreadsData($threads, $deleteType, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be deleted. This is a slightly more
* "internal" version of the canDeleteThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param string $deleteType Type of deletion (soft or hard)
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canDeleteThreadsData(array $threads, $deleteType, array $forums, &$errorKey = '', array $viewingUser = null)
{
// note: this cannot use _checkPermissionOnThreads because of extra param
if (!$threads)
{
return true;
}
$this->standardizeViewingUserReference($viewingUser);
$threadModel = $this->_getThreadModel();
foreach ($threads AS $thread)
{
$forum = $this->_getForumFromThread($thread, $forums);
if (!$threadModel->canViewThreadAndContainer($thread, $forum, $null, $forum['nodePermissions'], $viewingUser))
{
return false;
}
if (!$threadModel->canDeleteThread($thread, $forum, $deleteType, $errorKey, $forum['nodePermissions'], $viewingUser))
{
return false;
}
}
return true;
}
/**
* Deletes the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to delete
* @param array $options Options that control the delete. Supports deleteType (soft or hard).
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function deleteThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
$options = array_merge(
array(
'deleteType' => '',
'reason' => ''
), $options
);
if (!$options['deleteType'])
{
throw new XenForo_Exception('No deletion type specified.');
}
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canDeleteThreadsData($threads, $options['deleteType'], $forums, $errorKey, $viewingUser))
{
return false;
}
foreach ($threads AS $thread)
{
$dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread', XenForo_DataWriter::ERROR_SILENT);
if (!$dw->setExistingData($thread))
{
continue;
}
if (array_key_exists($dw->get('node_id'), $forums))
{
$dw->setExtraData(XenForo_DataWriter_Discussion_Thread::DATA_FORUM, $forums[$dw->get('node_id')]);
}
if ($options['deleteType'] == 'hard')
{
$dw->delete();
if ($this->enableLogging)
{
XenForo_Model_Log::logModeratorAction('thread', $thread, 'delete_hard');
}
}
else
{
$dw->setExtraData(XenForo_DataWriter_Discussion::DATA_DELETE_REASON, $options['reason']);
$dw->set('discussion_state', 'deleted');
$dw->save();
if ($this->enableLogging)
{
XenForo_Model_Log::logModeratorAction('thread', $thread, 'delete_soft', array('reason' => $options['reason']));
}
}
}
return true;
}
/**
* Determines if the selected thread IDs can be undeleted.
*
* @param array $threadIds List of thread IDs check
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canUndeleteThreads(array $threadIds, &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canUndeleteThreadsData($threads, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be undeleted. This is a slightly more
* "internal" version of the canUndeleteThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canUndeleteThreadsData(array $threads, array $forums, &$errorKey = '', array $viewingUser = null)
{
return $this->_checkPermissionOnThreads('canUndeleteThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Undeletes the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to undelete
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function undeleteThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canUndeleteThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsDiscussionState($threads, $forums, 'visible', 'deleted');
return true;
}
/**
* Determines if the selected thread IDs can be approved/unapproved.
*
* @param array $threadIds List of thread IDs check
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canApproveUnapproveThreads(array $threadIds, &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canApproveUnapproveThreadsData($threads, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be approved/unapproved. This is a slightly more
* "internal" version of the canApproveUnapproveThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canApproveUnapproveThreadsData(array $threads, array $forums, &$errorKey = '', array $viewingUser = null)
{
return $this->_checkPermissionOnThreads('canApproveUnapproveThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Approves the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to approve
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function approveThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canApproveUnapproveThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsDiscussionState($threads, $forums, 'visible', 'moderated');
return true;
}
/**
* Unapproves the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to unapprove
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function unapproveThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canApproveUnapproveThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsDiscussionState($threads, $forums, 'moderated', 'visible');
return true;
}
/**
* Determines if the selected thread IDs can be locked/unlocked.
*
* @param array $threadIds List of thread IDs check
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canLockUnlockThreads(array $threadIds, &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canLockUnlockThreadsData($threads, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be locked/unlocked. This is a slightly more
* "internal" version of the canLockUnlockThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canLockUnlockThreadsData(array $threads, array $forums, &$errorKey = '', array $viewingUser = null)
{
return $this->_checkPermissionOnThreads('canLockUnlockThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Locks the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function lockThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canLockUnlockThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsBulk($threads, $forums, array('discussion_open' => 0), 'lock');
return true;
}
/**
* Unlocks the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function unlockThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canLockUnlockThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsBulk($threads, $forums, array('discussion_open' => 1), 'unlock');
return true;
}
/**
* Determines if the selected thread IDs can be stickied/unstickied.
*
* @param array $threadIds List of thread IDs check
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canStickUnstickThreads(array $threadIds, &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canStickUnstickThreadsData($threads, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be stickied/unstickied. This is a slightly more
* "internal" version of the canStickUnstickThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canStickUnstickThreadsData(array $threads, array $forums, &$errorKey = '', array $viewingUser = null)
{
return $this->_checkPermissionOnThreads('canStickUnstickThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Stickies the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function stickThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canStickUnstickThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsBulk($threads, $forums, array('sticky' => 1), 'stick');
return true;
}
/**
* Stickies the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function unstickThreads(array $threadIds, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canStickUnstickThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$this->_updateThreadsBulk($threads, $forums, array('sticky' => 0), 'unstick');
return true;
}
/**
* Determines if the selected thread IDs can be moved.
*
* @param array $threadIds List of thread IDs check
* @param integer $targetNodeId ID of node where threads are being moved to. Use 0 if unknown.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canMoveThreads(array $threadIds, $targetNodeId, &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canMoveThreadsData($threads, $targetNodeId, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be moved. This is a slightly more
* "internal" version of the canMoveThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param integer $targetNodeId ID of node where threads are being moved to. Use 0 if unknown.
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canMoveThreadsData(array $threads, $targetNodeId, array $forums, &$errorKey = '', array $viewingUser = null)
{
if ($targetNodeId > 0)
{
$forum = $this->_getForumModel()->getForumById($targetNodeId);
if (!$forum)
{
$errorKey = 'please_select_valid_forum';
return false;
}
}
return $this->_checkPermissionOnThreads('canMoveThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Moves the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param integer $targetNodeId ID of node where threads are being moved to. Use 0 if unknown.
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function moveThreads(array $threadIds, $targetNodeId, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canMoveThreadsData($threads, $targetNodeId, $forums, $errorKey, $viewingUser))
{
return false;
}
if ($targetNodeId < 1)
{
return false;
}
$options = array_merge(
array(
'redirect' => false,
'redirectExpiry' => 0,
'checkSameForum' => true,
'approveModerated' => false,
'notifyWatch' => false
),
$options
);
if ($options['checkSameForum'])
{
$allSameForum = true;
foreach ($threads AS $thread)
{
if ($thread['node_id'] != $targetNodeId)
{
$allSameForum = false;
break;
}
}
if ($allSameForum)
{
$errorKey = 'all_threads_in_destination_forum';
return false;
}
}
$updateOptions = array('node_id' => $targetNodeId);
if (isset($options['prefix_id']))
{
$updateOptions['prefix_id'] = $options['prefix_id'];
}
foreach ($threads AS $thread)
{
$dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread', XenForo_DataWriter::ERROR_SILENT);
if (!$dw->setExistingData($thread))
{
continue;
}
$dw->bulkSet($updateOptions);
if (array_key_exists($dw->get('node_id'), $forums))
{
$dw->setExtraData(XenForo_DataWriter_Discussion_Thread::DATA_FORUM, $forums[$dw->get('node_id')]);
}
if ($options['approveModerated'] && $dw->get('discussion_state') == 'moderated')
{
$dw->set('discussion_state', 'visible');
}
$dw->save();
}
if ($this->enableLogging)
{
foreach ($threads AS $thread)
{
if ($thread['node_id'] != $targetNodeId)
{
$forum = $this->_getForumFromThread($thread, $forums);
$forumTitle = ($forum ? $forum['title'] : '');
XenForo_Model_Log::logModeratorAction('thread', $thread, 'move', array('from' => $forumTitle));
}
if (isset($options['prefix_id']) && $thread['prefix_id'] != $options['prefix_id'])
{
if ($thread['prefix_id'])
{
$prefixTitle = new XenForo_Phrase($this->_getPrefixModel()->getPrefixTitlePhraseName($thread['prefix_id']));
$prefixTitle = $prefixTitle->render();
}
else
{
$prefixTitle = '-';
}
XenForo_Model_Log::logModeratorAction('thread', $thread, 'prefix', array('old' => $prefixTitle));
}
}
}
if ($options['redirect'])
{
/** @var XenForo_Model_ThreadRedirect $threadRedirectModel */
$threadRedirectModel = $this->getModelFromCache('XenForo_Model_ThreadRedirect');
foreach ($threads AS $thread)
{
if ($targetNodeId == $thread['node_id'])
{
continue;
}
$threadRedirectModel->createRedirectThread(
XenForo_Link::buildPublicLink('threads', $thread), $thread,
"thread-$thread[thread_id]-$thread[node_id]-", $options['redirectExpiry']
);
}
}
if ($options['notifyWatch'])
{
/** @var XenForo_Model_ForumWatch $watchModel */
$watchModel = $this->getModelFromCache('XenForo_Model_ForumWatch');
/** @var XenForo_Model_Post $postModel */
$postModel = $this->getModelFromCache('XenForo_Model_Post');
foreach ($threads AS $thread)
{
if ($targetNodeId == $thread['node_id'])
{
continue;
}
$firstPost = $postModel->getPostById($thread['first_post_id']);
if ($firstPost && $firstPost['thread_id'] == $thread['thread_id'])
{
$watchModel->sendNotificationToWatchUsersOnMove(
$firstPost, $thread['node_id']
);
}
}
}
return true;
}
/**
* Determines if the selected thread IDs can be merged.
*
* @param array $threadIds List of thread IDs check
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canMergeThreads(array $threadIds, &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
return $this->canMergeThreadsData($threads, $forums, $errorKey, $viewingUser);
}
/**
* Determines if the selected threads can be merged. This is a slightly more
* "internal" version of the canMergeThreads() function, as the required data
* must already be retrieved.
*
* @param array $threads List of information about threads to be checked
* @param array $forums List of information about forums the threads are in; must include unserialized permissions in 'nodePermissions' key
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean
*/
public function canMergeThreadsData(array $threads, array $forums, &$errorKey = '', array $viewingUser = null)
{
if (count($threads) <= 1)
{
$errorKey = 'please_select_more_one_thread_merge';
return false;
}
$threadModel = $this->_getThreadModel();
foreach ($threads AS $thread)
{
if ($threadModel->isRedirect($thread))
{
$errorKey = 'cannot_merge_thread_redirection_notice';
return false;
}
}
return $this->_checkPermissionOnThreads('canMergeThread', $threads, $forums, $errorKey, $viewingUser);
}
/**
* Merge the specified threads if permissions are sufficient.
*
* @param array $threadIds List of thread IDs to change
* @param integer $targetThreadId ID of the thread (in the list) that the merging will happen into
* @param array $options Options that control the action. Nothing supported at this time.
* @param string $errorKey Modified by reference. If no permission, may include a key of a phrase that gives more info
* @param array|null $viewingUser
*
* @return boolean True if permissions were ok
*/
public function mergeThreads(array $threadIds, $targetThreadId, array $options = array(), &$errorKey = '', array $viewingUser = null)
{
list($threads, $forums) = $this->getThreadsAndParentData($threadIds, $viewingUser);
if (empty($options['skipPermissions']) && !$this->canMergeThreadsData($threads, $forums, $errorKey, $viewingUser))
{
return false;
}
$options['log'] = $this->enableLogging;
return $this->_getThreadModel()->mergeThreads($threads, $targetThreadId, $options);
}
/**
* Checks a standard thread permission against a collection of threads.
* True is returned only if the action is possible on all threads.
*
* @param string $permissionMethod Name of the permission method to call in the thread model
* @param array $threads List of threads to check
* @param array $forums List of forums the threads are in
* @param string $errorKey Returned by reference. Phrase key if an error occurs
* @param array|null $viewingUser
*
* @return boolean
*/
protected function _checkPermissionOnThreads($permissionMethod, array $threads, array $forums, &$errorKey = '', array $viewingUser = null)
{
if (!$threads)
{
return true;
}
$this->standardizeViewingUserReference($viewingUser);
$threadModel = $this->_getThreadModel();
foreach ($threads AS $thread)
{
$forum = $this->_getForumFromThread($thread, $forums);
if (!$threadModel->canViewThreadAndContainer($thread, $forum, $null, $forum['nodePermissions'], $viewingUser))
{
return false;
}
if ($permissionMethod && !$threadModel->$permissionMethod($thread, $forum, $errorKey, $forum['nodePermissions'], $viewingUser))
{
return false;
}
}
return true;
}
/**
* Internal helper to update the discussion_state of a collection of threads.
*
* @param array $threads Information about the threads to update
* @param array $forums Information about the forums that the threads are in
* @param string $newState New message state (visible, moderated, deleted)
* @param string|false $expectedOldState If specified, only updates if the old state matches
*/
protected function _updateThreadsDiscussionState(array $threads, array $forums, $newState, $expectedOldState = false)
{
switch ($newState)
{
case 'visible':
switch (strval($expectedOldState))
{
case 'visible': return;
case 'moderated': $logAction = 'approve'; break;
case 'deleted': $logAction = 'undelete'; break;
default: $logAction = 'undelete'; break;
}
break;
case 'moderated':
switch (strval($expectedOldState))
{
case 'visible': $logAction = 'unapprove'; break;
case 'moderated': return;
case 'deleted': $logAction = 'unapprove'; break;
default: $logAction = 'unapprove'; break;
}
break;
case 'deleted':
switch (strval($expectedOldState))
{
case 'visible': $logAction = 'delete_soft'; break;
case 'moderated': $logAction = 'delete_soft'; break;
case 'deleted': return;
default: $logAction = 'delete_soft'; break;
}
break;
default: return;
}
foreach ($threads AS $thread)
{
if ($expectedOldState && $thread['discussion_state'] != $expectedOldState)
{
continue;
}
$dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread', XenForo_DataWriter::ERROR_SILENT);
if (!$dw->setExistingData($thread))
{
continue;
}
$dw->set('discussion_state', $newState);
if (array_key_exists($dw->get('node_id'), $forums))
{
$dw->setExtraData(XenForo_DataWriter_Discussion_Thread::DATA_FORUM, $forums[$dw->get('node_id')]);
}
$dw->save();
if ($this->enableLogging)
{
XenForo_Model_Log::logModeratorAction('thread', $thread, $logAction);
}
}
}
/**
* Bulk update 1 or more fields in the given threads.
*
* @param array $threads List of threads to update
* @param array $forums List of forums threads are in
* @param array $updates Key-value pairs to update
* @param string $logAction If specified, this action will be logged with this action
*/
protected function _updateThreadsBulk(array $threads, array $forums, array $updates, $logAction = '')
{
foreach ($threads AS $thread)
{
$dw = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread', XenForo_DataWriter::ERROR_SILENT);
if (!$dw->setExistingData($thread))
{
continue;
}
$dw->bulkSet($updates);
if (array_key_exists($dw->get('node_id'), $forums))
{
$dw->setExtraData(XenForo_DataWriter_Discussion_Thread::DATA_FORUM, $forums[$dw->get('node_id')]);
}
$dw->save();
if ($dw->hasChanges() && $this->enableLogging && $logAction)
{
XenForo_Model_Log::logModeratorAction('thread', $thread, $logAction);
}
}
}
/**
* Gets information about the forum a thread belogns to.
*
* @param array $thread Info about the thread
* @param array $forums List of forums that the thread could belong to
*
* @return array Forum info
*/
protected function _getForumFromThread(array $thread, array $forums)
{
return $forums[$thread['node_id']];
}
/**
* From a list of threads IDs, gets info about the threads and
* the forums the threads are in.
*
* @param array $threadIds List of thread IDs
* @param array|null $viewingUser
*
* @return array Format: [0] => list of threads, [1] => list of forums
*/
public function getThreadsAndParentData(array $threadIds, array $viewingUser = null)
{
$this->standardizeViewingUserReference($viewingUser);
return $this->_getThreadModel()->getThreadsAndParentData($threadIds, $viewingUser['permission_combination_id']);
}
/**
* @return XenForo_Model_Thread
*/
protected function _getThreadModel()
{
return $this->getModelFromCache('XenForo_Model_Thread');
}
/**
* @return XenForo_Model_ThreadPrefix
*/
protected function _getPrefixModel()
{
return $this->getModelFromCache('XenForo_Model_ThreadPrefix');
}
/**
* @return XenForo_Model_Forum
*/
protected function _getForumModel()
{
return $this->getModelFromCache('XenForo_Model_Forum');
}
}