Пример #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'];
 }
Пример #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'];
 }
Пример #3
0
 /**
  * Permanently deletes a node
  *
  * @param  integer The nodeid of the record to be deleted
  *
  * @return boolean
  */
 public function delete($nodeid)
 {
     $nodecontent = $this->getContent($nodeid);
     if (isset($nodecontent[$nodeid])) {
         $nodecontent = $nodecontent[$nodeid];
     } else {
         throw new vB_Exception_Api('invalid_node_id');
     }
     // Note: The library delete has a check to prevent top level channels from being deleted, but
     // that excludes channels like the root channel, or the special, privatemessage or vm channels.
     $guids = vB_Channel::getProtectedChannelGuids();
     if (in_array($nodecontent['guid'], array_values($guids))) {
         throw new vB_Exception_Api('can_not_remove_default_channel');
     }
     // the reason there is no permission check in this function is because the parent (vB_Api_Content) performs the checks
     return parent::delete($nodeid);
 }
Пример #4
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;
 }
Пример #5
0
 print_submit_row($vbphrase['rebuild_thread_information']);
 print_form_header('misc', 'updateforum');
 print_table_header($vbphrase['rebuild_forum_information'], 2, 0);
 print_input_row($vbphrase['number_of_forums_to_process_per_cycle'], 'perpage', 100);
 print_submit_row($vbphrase['rebuild_forum_information']);
 print_form_header('misc', 'lostusers');
 print_table_header($vbphrase['fix_broken_user_profiles']);
 print_description_row($vbphrase['finds_users_without_complete_entries']);
 print_submit_row($vbphrase['fix_broken_user_profiles'], NULL);
 if ($maintainAll) {
     print_form_header('misc', 'doindextypes');
     print_table_header($vbphrase['rebuild_search_index'], 2, 0);
     print_description_row(construct_phrase($vbphrase['note_reindexing_empty_indexes_x'], vB::getCurrentSession()->get('sessionurl')));
     //don't use array_merge, it will (incorrectly) assume that the keys are index values
     //instead of meaningful numeric keys and renumber them.
     $channelTypes = vB_Channel::getChannelTypes();
     $types = array(0 => $vbphrase['all']);
     foreach ($channelTypes as $nodeId => $type) {
         $types[$nodeId] = $vbphrase[$type['label']];
     }
     print_select_row($vbphrase['search_content_type_to_index'], 'indextypes', $types);
     print_input_row($vbphrase['search_items_batch'], 'perpage', 250);
     print_input_row($vbphrase['search_start_item_id'], 'startat', 0);
     print_yes_no_row($vbphrase['include_automatic_javascript_redirect'], 'autoredirect', 1);
     print_description_row($vbphrase['note_server_intensive']);
     print_submit_row($vbphrase['rebuild_search_index']);
 }
 print_form_header('misc', 'truncatesigcache');
 print_table_header($vbphrase['empty_signature_cache']);
 print_description_row($vbphrase['change_output_signatures_empty_cache']);
 print_submit_row($vbphrase['empty_signature_cache'], NULL);
Пример #6
0
 /**
  * Returns a channel record based on its node guid
  *
  * @param	string	GUID
  *
  * @return	array	Channel information
  */
 public function fetchChannelByGUID($guid)
 {
     $cache = vB_Cache::instance(vB_Cache::CACHE_FAST);
     $channel = $cache->read('vbChannelGUID_' . $guid);
     if (!empty($channel)) {
         return $channel;
     }
     $parentChannelGUIDs = vB_Channel::getDefaultGUIDs();
     $parentChannels = vB::getDbAssertor()->assertQuery('vBForum:channel', array('guid' => $parentChannelGUIDs));
     $channel = array();
     foreach ($parentChannels as $parentChannel) {
         $cache->write('vbChannelGUID_' . $parentChannel['guid'], $parentChannel, 1440, 'nodeChg_' . $parentChannel['nodeid']);
         if ($parentChannel['guid'] == $guid) {
             $channel = $parentChannel;
         }
     }
     return $channel;
 }