Ejemplo n.º 1
0
 /**
  * Create an article category channel. This function works basically like the blog library's version
  *
  * @param array 	$input						data array, should have standard channel data like title, parentid, 
  * @param int 		$channelid					parentid that the new channel should fall under. 
  * @param int		$channelConvTemplateid		"Conversation" level pagetemplate to use. Typically vB_Page::getArticleConversPageTemplate()
  * @param int 		$channelPgTemplateId		"Channel" level pagetemplate to use. Typically  vB_Page::getArticleChannelPageTemplate()
  * @param int 		$ownerSystemGroupId
  *
  * @return int The nodeid of the new blog channel
  */
 public function createChannel($input, $channelid, $channelConvTemplateid, $channelPgTemplateId, $ownerSystemGroupId)
 {
     if (!isset($input['parentid']) or intval($input['parentid']) < 1) {
         $input['parentid'] = $channelid;
     }
     $input['inlist'] = 1;
     // we don't want it to be shown in channel list, but we want to move them
     $input['protected'] = 0;
     if (empty($input['userid'])) {
         $input['userid'] = vB::getCurrentSession()->get('userid');
     }
     if (!isset($input['publishdate'])) {
         $input['publishdate'] = vB::getRequest()->getTimeNow();
     }
     $input['templates']['vB5_Route_Channel'] = $channelPgTemplateId;
     $input['templates']['vB5_Route_Article'] = $channelConvTemplateid;
     $input['childroute'] = 'vB5_Route_Article';
     // add channel node
     $channelLib = vB_Library::instance('content_channel');
     $input['page_parentid'] = 0;
     $result = $channelLib->add($input, array('skipNotifications' => true, 'skipFloodCheck' => true, 'skipDupCheck' => true));
     //Make the current user the channel owner.
     $userApi = vB_Api::instanceInternal('user');
     $usergroup = vB::getDbAssertor()->getRow('usergroup', array('systemgroupid' => $ownerSystemGroupId));
     vB_Cache::allCacheEvent(array('nodeChg_' . $this->articleHomeChannel, "nodeChg_{$channelid}"));
     vB::getUserContext()->rebuildGroupAccess();
     vB_Channel::rebuildChannelTypes();
     // clear follow cache
     vB_Api::instanceInternal('follow')->clearFollowCache(array($input['userid']));
     return $result['nodeid'];
 }
Ejemplo n.º 2
0
 /**
  * Create a blog channel.
  *
  * @param array $input
  * @param int $channelid
  * @param int $channelConvTemplateid
  * @param int $channelPgTemplateId
  * @param int $ownerSystemGroupId
  *
  * @return int The nodeid of the new blog channel
  */
 public function createChannel($input, $channelid, $channelConvTemplateid, $channelPgTemplateId, $ownerSystemGroupId)
 {
     $input['parentid'] = $channelid;
     $input['inlist'] = 1;
     // we don't want it to be shown in channel list, but we want to move them
     $input['protected'] = 0;
     if (empty($input['userid'])) {
         $input['userid'] = vB::getCurrentSession()->get('userid');
     }
     if (!isset($input['publishdate'])) {
         $input['publishdate'] = vB::getRequest()->getTimeNow();
     }
     $input['templates']['vB5_Route_Channel'] = $channelPgTemplateId;
     $input['templates']['vB5_Route_Conversation'] = $channelConvTemplateid;
     // add channel node
     $channelLib = vB_Library::instance('content_channel');
     $input['page_parentid'] = 0;
     $result = $channelLib->add($input, array('skipFloodCheck' => true, 'skipDupCheck' => true));
     //Make the current user the channel owner.
     $userApi = vB_Api::instanceInternal('user');
     $usergroup = vB::getDbAssertor()->getRow('usergroup', array('systemgroupid' => $ownerSystemGroupId));
     if (empty($usergroup) or !empty($usergroup['errors'])) {
         //This should never happen. It would mean an invalid parameter was passed
         throw new vB_Exception_Api('invalid_request');
     }
     vB_User::setGroupInTopic($input['userid'], $result['nodeid'], $usergroup['usergroupid']);
     vB_Cache::allCacheEvent(array('nodeChg_' . $this->blogChannel, "nodeChg_{$channelid}"));
     vB::getUserContext()->rebuildGroupAccess();
     vB_Channel::rebuildChannelTypes();
     // clear follow cache
     vB_Api::instanceInternal('follow')->clearFollowCache(array($input['userid']));
     return $result['nodeid'];
 }
Ejemplo n.º 3
0
 /**
  * Moves nodes to a new parent
  *
  * @param	array	Node ids
  * @param	int	New parent node id
  * @param	bool	Make topic
  * @param	bool	New title
  * @param	bool	Mod log
  * @param	array	Information to leave a thread redirect. If empty, no redirect is created.
  *			If not empty, should contain these items:
  *				redirect (string) - perm|expires	Permanent or expiring redirect
  *				frame (string) - h|d|w|m|y	Hours, days, weeks, months, years (valid only for expiring redirects)
  *				period (int) - 1-10	How many hours, days, weeks etc, for the expiring redirect
  *
  * @return
  */
 public function moveNodes($nodeids, $to_parent, $makeTopic = false, $newtitle = false, $modlog = true, array $leaveRedirectData = array())
 {
     $movedNodes = array();
     $oldnodeInfo = array();
     $to_parent = $this->assertNodeidStr($to_parent);
     $userContext = vB::getUserContext();
     $currentUserid = vB::getCurrentSession()->get('userid');
     $channelAPI = vB_Api::instanceInternal('content_channel');
     $newparent = $this->getNode($to_parent);
     // If all the nodes to be moved are content nodes and are currently in the same
     // channel, then we are only merging posts/topics and need to check different permissions.
     // To detemine this, we iterate through all the nodes to be moved and get all the "starter"
     // nodeids. We then iterate through all the starters and check if they all have the same
     // parentid, which is the channel they are in.
     $isTopicMerge = false;
     $checkNodes = $this->getNodes(array_merge((array) $nodeids, (array) $to_parent));
     $skipCheck = false;
     $checkStarterIds = array();
     foreach ($checkNodes as $checkNode) {
         if (empty($checkNode['starter'])) {
             // we can skip this check because one of the nodes is a channel
             $skipCheck = true;
             break;
         } else {
             $checkStarterIds[] = $checkNode['starter'];
         }
     }
     if (!$skipCheck) {
         $checkStarters = $this->getNodes($checkStarterIds);
         $starterParents = array();
         foreach ($checkStarters as $checkStarter) {
             $starterParents[$checkStarter['parentid']] = $checkStarter['parentid'];
         }
         if (count($starterParents) === 1) {
             // the parent node of all the starters is the same, so we are
             // only moving topics / posts around inside the same channel,
             // this is likely a topic merge request and we can check a separate
             // permission below
             $isTopicMerge = true;
         }
         unset($checkStarters, $checkStarter, $starterParents);
     }
     unset($checkNode, $checkStarterIds, $skipCheck);
     //If the current user has can moderator canmove on the current nodes, or if the user can create in
     //the new channel and is the owner of the moved nodes and has forum canmove, then they can move
     if (!$userContext->getChannelPermission('forumpermissions', 'canmove', $to_parent) and !$userContext->getChannelPermission('moderatorpermissions', 'canmassmove', $to_parent) and (!$isTopicMerge or !$userContext->getChannelPermission('moderatorpermissions', 'canmanagethreads', $to_parent))) {
         throw new vB_Exception_Api('no_permission');
     }
     $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)), 'nodeid');
     $needRebuild = false;
     $firstTitle = false;
     $loginfo = array();
     $parent = $this->getNodeFullContent($to_parent);
     $parent = $parent[$to_parent];
     $cacheEvents = array($to_parent);
     $oldparents = array();
     $channelTypeid = vB_Types::instance()->getContentTypeId('vBForum_Channel');
     $infractionTypeid = vB_Types::instance()->getContentTypeId('vBForum_Infraction');
     foreach ($nodes as $node) {
         if ($node['contenttypeid'] == $infractionTypeid) {
             throw new vB_Exception_Api('cannot_move_infraction_nodes');
         }
         if ($node['contenttypeid'] == $channelTypeid) {
             // If any of the moved nodes are channels, the target must be a channel.
             if ($newparent['contenttypeid'] != $channelTypeid) {
                 throw new vB_Exception_Api('invalid_request');
             }
             // We should not allow the moving of channels from one root channel to another.
             if ($channelAPI->getTopLevelChannel($newparent['nodeid']) != $channelAPI->getTopLevelChannel($node['nodeid'])) {
                 throw new vB_Exception_Api('cant_change_top_level');
             }
         }
         //Only channels can be moved to categories, UI shouldn't allow this
         if ($parent['contenttypeid'] == $channelTypeid) {
             $newrouteid = vB_Api::instanceInternal('route')->getChannelConversationRoute($to_parent);
             if ($node['contenttypeid'] != $channelTypeid and (empty($newrouteid) or !empty($parent['category']))) {
                 // The node we want to move is not a channel and the parent cannot have conversations
                 // (e.g. categories, the root blog channel, the root forum channel)
                 throw new vB_Exception_Api('invalid_request');
             }
         }
         if ($node['contenttypeid'] == vB_Types::instance()->getContentTypeID('vBForum_Channel')) {
             $needRebuild = true;
         }
         if ($userContext->getChannelPermission('moderatorpermissions', 'canmassmove', $node['nodeid']) or $currentUserid == $node['userid'] and $userContext->getChannelPermission('forumpermissions', 'canmove', $node['nodeid'], false, $node['parentid']) or $isTopicMerge and $userContext->getChannelPermission('moderatorpermissions', 'canmanagethreads', $to_parent)) {
             if (empty($movedNodes)) {
                 if (empty($node['title']) and !empty($node['starter'])) {
                     $starter = vB_Library::instance('node')->getNodeBare($node['starter']);
                     $firstTitle = $starter['title'];
                 } else {
                     $firstTitle = $node['title'];
                 }
             }
             $movedNodes[] = $node['nodeid'];
             $oldnodeInfo[$node['nodeid']] = $node;
             $oldparents[$node['nodeid']] = $node['parentid'];
             $this->contentLibs[$node['nodeid']] = vB_Library::instance('Content_' . vB_Types::instance()->getContentTypeClass($node['contenttypeid']));
             if ($modlog) {
                 $oldparent = $this->getNode($node['parentid']);
                 $extra = array('fromnodeid' => $oldparent['nodeid'], 'fromtitle' => $oldparent['title'], 'tonodeid' => $newparent['nodeid'], 'totitle' => $newparent['title']);
                 $loginfo[] = array('nodeid' => $node['nodeid'], 'nodetitle' => $node['title'], 'nodeusername' => $node['authorname'], 'nodeuserid' => $node['userid'], 'action' => $extra);
             }
             if (!in_array($node['parentid'], $cacheEvents)) {
                 $cacheEvents[] = $node['parentid'];
             }
             if (!in_array($node['starter'], $cacheEvents) and intval($node['starter'])) {
                 $cacheEvents[] = $node['starter'];
             }
         } else {
             throw new vB_Exception_Api('no_permission');
         }
     }
     if (empty($movedNodes)) {
         return false;
     }
     //can't move a node to its decendant, we like proper trees.
     $db = vB::getDbAssertor();
     $row = $db->getRow('vBForum:closure', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'parent' => $movedNodes, 'child' => $to_parent, vB_Db_Query::PARAM_LIMIT => 1));
     if (!empty($row)) {
         throw new vB_Exception_Api('move_node_to_child');
     }
     //back out counts for the nodes about to be moved.
     //keep track of the parentids to so we can update the last content after
     //we've moved things around.
     $lastContentParents = array();
     foreach ($movedNodes as $nodeid) {
         $node = $this->getNode($nodeid);
         $movedNodeParents = $this->getParents($nodeid);
         $parentids = array();
         foreach ($movedNodeParents as $movedNodeParent) {
             if ($movedNodeParent['nodeid'] != $nodeid) {
                 $parentids[] = $movedNodeParent['nodeid'];
                 $lastContentParents[] = $movedNodeParent['nodeid'];
             }
         }
         $this->updateAddRemovedNodeParentCounts($node, $node, $node['showpublished'], false, $parentids);
     }
     if ($parent['contenttypeid'] == $channelTypeid and $makeTopic) {
         if (empty($newtitle)) {
             if (!empty($firstTitle)) {
                 $newtitle = $firstTitle;
             } else {
                 throw new vB_Exception_Api('notitle');
             }
         }
         $newchildid = $movedNodes[0];
         $this->moveNodesInternal(array($newchildid), $newparent);
         // We need to promote give the new node the correct title
         vB::getDbAssertor()->assertQuery('vBForum:node', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE, 'routeid' => vB_Api::instanceInternal('route')->getChannelConversationRoute($to_parent), 'title' => $newtitle, 'htmltitle' => vB_String::htmlSpecialCharsUni(vB_String::stripTags($newtitle), false), 'urlident' => vB_String::getUrlIdent($newtitle), 'description' => $newtitle, vB_dB_Query::CONDITIONS_KEY => array('nodeid' => $movedNodes[0])));
         if (count($movedNodes) > 1) {
             $grandchildren = array_slice($movedNodes, 1);
             $this->moveNodesInternal($grandchildren, $checkNodes[$newchildid]);
         }
         //moving the grandchildren under the first node may have changed it's last child info
         $db->assertQuery('vBForum:updateLastData', array('parentid' => $newchildid, 'timenow' => vB::getRequest()->getTimeNow()));
         $node = $this->getNode($newchildid);
         $this->updateSubTreePublishStatus($node, $newparent['showpublished']);
     } else {
         $this->moveNodesInternal($movedNodes, $newparent);
         foreach ($movedNodes as $nodeid) {
             $node = $this->getNode($nodeid);
             $this->updateSubTreePublishStatus($node, $newparent['showpublished']);
         }
     }
     //dedup the array (so we don't update a node more than once) but we need to
     //do so in a particular way.  We always want to keep the *last* occurance
     //of any id in the array.  This ensures that a node is not updated before
     //any of its decendants (which could cause bad results).
     $seen = array();
     foreach ($lastContentParents as $key => $parentid) {
         if (isset($seen[$parentid])) {
             unset($lastContentParents[$seen[$parentid]]);
         }
         $seen[$parentid] = $key;
     }
     //we can't do this before we move the nodes because the parent/child relationships haven't
     //changed yet.
     foreach ($lastContentParents as $parentid) {
         $this->fixNodeLast($parentid);
     }
     $userid = vB::getCurrentSession()->get('userid');
     // afterMove requires some ancestors info which we just changed above, let's clear cache before updating
     $searchAPI = vB_Api::instanceInternal('search');
     foreach ($movedNodes as $nodeid) {
         vB_Cache::instance()->allCacheEvent('nodeChg_' . $nodeid);
         //some search information may have changed, let's check
         $searchAPI->attributeChanged($nodeid);
     }
     // Leave a thread redirect if required
     // Note: UI only allows leaving a redirect when moving a thread which is one node
     if (!empty($leaveRedirectData) and count($movedNodes) == 1 and count($nodes) == 1) {
         $node = reset($nodes);
         $redirectData = array('title' => $node['title'], 'urlident' => $node['urlident'], 'parentid' => $node['parentid'], 'tonodeid' => $node['nodeid'], 'userid' => $node['userid'], 'publishdate' => $node['publishdate'], 'created' => $node['created']);
         // handle expiring redirects
         if (isset($leaveRedirectData['redirect']) and $leaveRedirectData['redirect'] == 'expires') {
             $period = (int) isset($leaveRedirectData['period']) ? $leaveRedirectData['period'] : 1;
             $frame = (string) isset($leaveRedirectData['frame']) ? $leaveRedirectData['frame'] : 'm';
             $period = max(min($period, 10), 1);
             $frame = in_array($frame, array('h', 'd', 'w', 'm', 'y'), true) ? $frame : 'm';
             $frames = array('h' => 3600, 'd' => 86400, 'w' => 86400 * 7, 'm' => 86400 * 30, 'y' => 86400 * 365);
             $redirectData['unpublishdate'] = vB::getRequest()->getTimeNow() + $period * $frames[$frame];
         }
         // skip any text spam checks, because a redirect has no text to check.
         vB_Library::instance('content_redirect')->add($redirectData, array('skipSpamCheck' => true));
     }
     vB_Api::instance('Search')->purgeCacheForCurrentUser();
     vB_Library_Admin::logModeratorAction($loginfo, 'node_moved_by_x');
     $cacheEvents = array_unique(array_merge($movedNodes, $cacheEvents, array($to_parent)));
     $this->clearChildCache($cacheEvents);
     $this->clearCacheEvents($cacheEvents);
     if ($needRebuild) {
         vB::getUserContext()->rebuildGroupAccess();
         vB_Channel::rebuildChannelTypes();
     }
     return $movedNodes;
 }
Ejemplo n.º 4
0
 function delete($nodeid)
 {
     if (empty($nodeid)) {
         return false;
     }
     // prevent deleting of top level channels
     if (in_array($nodeid, vB_Api::instanceInternal('content_channel')->fetchTopLevelChannelIds())) {
         throw new vB_Exception_Api('cant_delete_top_level');
     }
     // get the direct children.
     $children_nodes = vB::getDbAssertor()->assertQuery('vBForum:getChildrenOnly', array('nodeid' => $nodeid));
     $nodeids = array();
     $children_by_type = array();
     foreach ($children_nodes as $node) {
         $children_by_type[$node['contenttypeid']][$node['nodeid']] = $node['nodeid'];
         $nodeids[] = $node['nodeid'];
     }
     foreach ($children_by_type as $contenttypeid => $nodes) {
         $contentLib = vB_Library_Content::getContentLib($contenttypeid);
         $contentLib->deleteChildren($nodes);
     }
     if (!empty($nodeids)) {
         vB_Search_Core::instance()->deleteBulk($nodeids);
     }
     // deleting the node
     $success = parent::delete($nodeid);
     // delete pages and routes
     $this->deleteChannelPages($nodeid);
     vB_Cache::instance()->event('vB_ChannelStructure_chg');
     vB::getUserContext()->rebuildGroupAccess();
     vB_Channel::rebuildChannelTypes();
     return $success;
 }