/** * Merge several topics into a target topic * * @param array $nodeids Source topic node IDs * @param int $targetnodeid Target topic node ID * * @return array */ public function mergeTopics($nodeids, $targetnodeid, array $leaveRedirectData = array()) { $this->inlinemodAuthCheck(); // check that the user has permission $nodesToCheck = $nodeids; $nodesToCheck[] = $targetnodeid; foreach ($nodesToCheck as $key => $nodeid) { // this is here just in case for some reason, a nodeid is 0. Shouldn't happen, but // I don't want getChannelPermission to go bonkers from it. if (empty($nodeid)) { unset($nodesToCheck[$key]); continue; } if (!vB::getUserContext()->getChannelPermission('moderatorpermissions', 'canmanagethreads', $nodeid)) { // perhaps we could generate a list of unmergeable nodes and return a warning instead, but // I don't think there's a real use case where a moderator can manage only *some* of the // nodes they're trying to merge. I think that would require multiple channels being involved, and // we don't have a UI for that so I can't test it. As such I'm just going to throw an exception if // *any* of the nodes fail the check. throw new vB_Exception_Api('no_permission'); } } $mergedNodes = array(); $sourceNodes = array(); if (count($nodeids) < 2) { throw new vB_Exception_Api('not_much_would_be_accomplished_by_merging'); } if (!in_array($targetnodeid, $nodeids)) { throw new vB_Exception_Api('invalid_target'); } $userContext = vB::getUserContext(); $nodes = vB::getDbAssertor()->getRows('vBForum:node', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'nodeid' => $nodeids), array('field' => array('publishdate'), 'direction' => array(vB_dB_Query::SORT_ASC))); $loginfo = array(); $targetnode = $this->getNode($targetnodeid); foreach ($nodes as $node) { if (intval($node['inlist']) and !intval($node['protected']) and $userContext->getChannelPermission('forumpermissions', 'canview', $node['nodeid'], false, $node['parentid']) and $node['nodeid'] == $node['starter']) { $mergedNodes[] = $node['nodeid']; if ($node['nodeid'] != $targetnodeid) { $sourceNodes[] = $node['nodeid']; $extra = array('targetnodeid' => $targetnode['nodeid'], 'targettitle' => $targetnode['title']); $loginfo[] = array('nodeid' => $node['nodeid'], 'nodetitle' => $node['title'], 'nodeusername' => $node['authorname'], 'nodeuserid' => $node['userid'], 'action' => $extra); } } } if (count($mergedNodes) < 2) { throw new vB_Exception_Api('not_much_would_be_accomplished_by_merging'); } if ($mergedNodes == $sourceNodes) { // Something wrong with target node throw new vB_Exception_Api('invalid_target'); } $this->moveNodes($sourceNodes, $targetnodeid, false, false, false, $leaveRedirectData); // Dont log the individual moves // We need to promote the replies of the sourcenodes to the replies of the targetnode instead of being comments of the sourcenodes. foreach ($sourceNodes as $sourcenodeid) { $sourcereplies = vB::getDbAssertor()->getRows('vBForum:node', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'parentid' => $sourcenodeid), array('field' => array('publishdate'), 'direction' => array(vB_dB_Query::SORT_ASC))); $replyNodes = array(); foreach ($sourcereplies as $replies) { $replyNodes[] = $replies['nodeid']; } if ($replyNodes) { // Move the replies to the targetnode $this->moveNodes($replyNodes, $targetnodeid, false, false, false); } } // If source node is a poll, we need to delete it // Here all source nodes' children have been promoted so they won't be deleted foreach ($nodes as $node) { if ($node['nodeid'] != $targetnodeid and $node['contenttypeid'] == vB_Types::instance()->getContentTypeId('vBForum_Poll')) { $this->library->deleteNode($node['nodeid']); } } vB_Library_Admin::logModeratorAction($loginfo, 'node_merged_by_x'); $clearCacheNodes = array_unique(array_merge($mergedNodes, $sourceNodes, array($targetnodeid))); $this->library->clearChildCache($clearCacheNodes); $this->clearCacheEvents($clearCacheNodes); return array($mergedNodes, $sourceNodes, $targetnodeid); }