Beispiel #1
0
 public function getCanonicalRoute()
 {
     if (!isset($this->canonicalRoute)) {
         if (empty($this->arguments['nodeid'])) {
             throw new vB_Exception_NodePermission();
         }
         $nodeApi = vB_Api::instanceInternal('node');
         try {
             // this method will return an error if the user does not have permission
             $node = $nodeApi->getNode($this->arguments['nodeid']);
         } catch (vB_Exception_Api $ex) {
             // throw the proper NodePermission exception to return a 403 status instead of a 500 internal error
             if ($ex->has_errors('no_permission')) {
                 throw new vB_Exception_NodePermission($this->arguments['nodeid']);
             } else {
                 // otherwise, just let the caller catch the exception
                 throw $ex;
             }
         }
         $contentApi = vB_Api_Content::getContentApi($node['contenttypeid']);
         if (!$contentApi->validate($node, vB_Api_Content::ACTION_VIEW, $node['nodeid'], array($node['nodeid'] => $node))) {
             throw new vB_Exception_NodePermission($node['nodeid']);
         }
         $parent = $nodeApi->getNode($node['starter']);
         $parent['innerPost'] = $this->arguments['nodeid'];
         $this->canonicalRoute = self::getRoute($node['routeid'], $parent, $this->queryParameters);
     }
     return $this->canonicalRoute;
 }
Beispiel #2
0
 /**
  * This was a function wrapper for listPendingPosts but used for current user.
  * Now returns different information due to post processing steps.
  *
  */
 public function listPendingPostsForCurrentUser($options = array())
 {
     $result = $this->listPendingPosts(vB::getCurrentSession()->get('userid'), $options);
     if (isset($result['totalcount'])) {
         $totalCount = intval($result['totalcount']);
     }
     if (isset($result['pageInfo'])) {
         $pageInfo = $result['pageInfo'];
     }
     $contenttypes = array();
     $nodes = array();
     foreach ($result['nodes'] as $node) {
         $contenttypeid = $node['contenttypeid'];
         $nodeid = $node['nodeid'];
         if (!isset($contenttypes[$contenttypeid])) {
             $contenttypes[$contenttypeid] = array();
         }
         $contenttypes[$contenttypeid][] = $nodeid;
         $nodes[$nodeid] = $node;
     }
     //For each type, get the content detail.
     foreach ($contenttypes as $contenttypeid => $nodeList) {
         if (!empty($nodes)) {
             $contentApi = vB_Api_Content::getContentApi($contenttypeid);
             $contentList = $contentApi->getFullContent($nodeList);
             foreach ($nodes as $nodeid => $node) {
                 foreach ($contentList as $key => $content) {
                     if ($content['nodeid'] == $nodeid) {
                         $nodes[$nodeid]['content'] = $content;
                         break;
                     }
                 }
             }
         }
     }
     $userApi = vB_Api::instanceInternal('user');
     $pmContentType = vB_Types::instance()->getContentTypeId('vBForum_PrivateMessage');
     //We need a list of parents for nodes that are neither starters nor replies.
     $parents = array();
     //add parent, visitormessage, and author information
     foreach ($nodes as $nodeid => $node) {
         if ($node['content']['starter'] != $node['content']['nodeid'] and $node['content']['starter'] != $node['content']['parentid']) {
             $parents[$nodeid] = $node['content']['parentid'];
         }
         $nodes[$nodeid]['isVisitorMessage'] = $nodes[$nodeid]['content']['isVisitorMessage'] = !empty($node['content']['setfor']);
         $nodes[$nodeid]['userinfo'] = array('avatar' => $userApi->fetchAvatar($node['content']['userid'], array('avatar'), $node['content']['userinfo']), 'userid' => $node['content']['userid'], 'username' => $node['content']['userinfo']['username']);
     }
     //See if we need to add some parent information
     if (!empty($parents)) {
         $parentInfo = vB_Api::instanceInternal('node')->getNodes($parents);
         foreach ($parents as $nodeid => $parentid) {
             foreach ($parentInfo as $info) {
                 if ($info['nodeid'] == $parentid) {
                     $nodes[$nodeid]['parent'] = $info;
                 }
             }
         }
     }
     $this->addOptionalContentInfo($nodes, $options);
     $this->markSubscribed($nodes);
     $return = array('nodes' => $nodes);
     if (isset($totalCount)) {
         $return['totalcount'] = $totalCount;
     } else {
         $return['totalcount'] = count($nodes);
     }
     if (isset($pageInfo) and !empty($pageInfo)) {
         $return['pageInfo'] = $pageInfo;
     }
     return $return;
 }
Beispiel #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);
 }
Beispiel #4
0
 /**
  * Cleans the input in the $data array, directly updating $data.
  *
  * Note: This is called from the cleanInput method in the text API for
  * all the attachments to the text node.
  *
  * @param mixed      Array of fieldname => data pairs, passed by reference.
  * @param (int|bool) Nodeid of the node being edited, false if creating new
  */
 public function cleanInput(&$data, $nodeid = false)
 {
     parent::cleanInput($data, $nodeid);
     $data['filedataid'] = intval(isset($data['filedataid']) ? $data['filedataid'] : 0);
     $cleaner = vB::getCleaner();
     $data['filename'] = $cleaner->clean($data['filename'], vB_Cleaner::TYPE_NOHTML);
     // clean and serialize settings
     $data['settings'] = isset($data['settings']) ? $data['settings'] : '';
     if (!empty($data['parentid'])) {
         $nodeid = $data['parentid'];
     }
     $data['settings'] = $this->cleanSettings($data['settings'], $nodeid);
 }
Beispiel #5
0
 /**
  * validates that the current can do something with a node with these values
  *
  * @param  mixed  Array of field => value pairs which define the record.
  * @param  string Parameters to be checked for permission
  * @param  int    (optional) Node ID
  * @param  array  (optional) Nodes
  *
  * @return bool
  */
 public function validate(&$data, $action = self::ACTION_ADD, $nodeid = false, $nodes = false)
 {
     //One extra check. If the node would otherwise be viewable but viewperms is zero for an album, the the current user
     //is the owner or follows the owner, they can see it.
     if (parent::validate($data, $action, $nodeid, $nodes)) {
         return true;
     }
     if (empty($data) and !empty($nodeid)) {
         $data = vB_Library::instance('node')->getNodeBare($nodeid);
     }
     if ($action == self::ACTION_VIEW and isset($data['nodeid']) and isset($data['userid']) and isset($data['parentid']) and isset($data['viewperms']) and $data['viewperms'] != 2 and !empty($data['showapproved']) and !empty($data['showpublished'])) {
         $gallery = vB_Library::instance('node')->getNodeBare($data['parentid']);
         return vB_Api::instanceInternal('content_gallery')->validate($gallery, $action, $data['parentid']);
         return true;
     }
     return false;
 }
Beispiel #6
0
 /**
  * Get the nodes from a search resultId
  *
  * @param  int   $resultId id of the search result
  * @param  int   $perpage pagination - the number of results per page
  * @param  int   $pagenumber pagination - the page number
  *
  * @return array List of nodes in the resultId
  */
 public function getMoreResults($resultId, $perpage = false, $pagenumber = false, $getStarterInfo = false)
 {
     $return_structure = $this->getMoreNodes($resultId, $perpage, $pagenumber);
     $return_structure['results'] = vB_Library::instance('Node')->getFullContentforNodes($return_structure['nodeIds'], array('withParent' => $getStarterInfo, 'showVM' => 1));
     //note that getFullContentforNodes returns an element ['content']['permissions']['canviewthreads']
     $userContext = vB::getUserContext();
     foreach ($return_structure['results'] as $key => $result) {
         vB_Api_Content::getContentApi($result['contenttypeid'])->cleanPreviewContent($return_structure['results'][$key]);
     }
     return $return_structure;
 }
Beispiel #7
0
 /**
  *	This gets a content record based on nodeid including channel and starter information.
  *
  *	@param	int $nodeid
  *	@param	bool	$contenttypeid optional, defaults to false
  *	@param	array optional	Options flags:
  *		showVm => appends visitor message node info.
  *				Such as isVisitorMessage flag indicating if node is visitor message and vm_userInfo from the user the visitor message was posted for.
  *	withParent => appends information from the parent. This info will append the 'parentConversation' info if the node is a comment.
  *
  *	@return array node list ($nodeid=>node record) will only have one item
  *
  ***/
 public function getNodeFullContent($nodeid, $contenttypeid = false, $options = array())
 {
     if (!is_numeric($nodeid)) {
         throw new vB_Exception_Api('invalid_data');
     }
     $nodeid = intval($nodeid);
     $result = $this->library->getNodeFullContent($nodeid, $contenttypeid, $options);
     //Can happen with a damaged node
     if (empty($result) or empty($result[$nodeid]) or empty($result[$nodeid]['nodeid'])) {
         return array();
     }
     foreach ($result as $key => $node) {
         $contentApi = vB_Api_Content::getContentApi($node['contenttypeid']);
         if (!$contentApi->validate($node, vB_Api_Content::ACTION_VIEW, $node['nodeid'], array($node['nodeid'] => $node))) {
             throw new vB_Exception_Api('no_permission');
         }
     }
     $this->library->removePrivateDataFromNodeList($result);
     return $result;
 }
 public function __construct($routeInfo, $matches, $queryString = '', $anchor = '')
 {
     parent::__construct($routeInfo, $matches, $queryString, $anchor);
     if (isset($this->arguments['channelid'])) {
         $cache = vB_Cache::instance(vB_Cache::CACHE_FAST);
         $hashKey = 'vbRouteChannelInfo_' . $this->arguments['channelid'];
         $channelInfo = $cache->read($hashKey);
         if (empty($channelInfo)) {
             // check if we need to force a styleid
             $channel = vB_Library::instance('Content_Channel')->getBareContent($this->arguments['channelid']);
             $channel = array_pop($channel);
             $channelInfo['styleid'] = $channel['styleid'];
             $channelInfo['options'] = $channel['options'];
             $channelInfo['routeid'] = $channel['routeid'];
             $channelInfo['rss_enabled'] = $channel['rss_enabled'];
             $channelInfo['rss_route'] = $channel['rss_route'];
             $channelInfo['title'] = $channel['title'];
             $cache->write($hashKey, $channelInfo, 1440, array('routeChg_' . $channelInfo['routeid'], 'nodeChg_' . $channelInfo['routeid']));
         }
         if (!empty($channelInfo['styleid'])) {
             if ($channelInfo['options']['styleoverride']) {
                 // the channel must force the style
                 $this->arguments['forceStyleId'] = $channelInfo['styleid'];
             } else {
                 // the channel suggests to use this style
                 $this->arguments['routeStyleId'] = $channelInfo['styleid'];
             }
         }
         // rss info
         $this->arguments['rss_enabled'] = $channelInfo['rss_enabled'];
         $this->arguments['rss_route'] = $channelInfo['rss_route'];
         $this->arguments['rss_title'] = $channelInfo['title'];
         $this->setPageKey('pageid', 'channelid', 'nodeid');
     }
     if (isset($this->arguments['nodeid'])) {
         if (!empty($this->arguments['userid']) && !empty($this->arguments['contenttypeid']) && !empty($this->arguments['title']) && !empty($this->arguments['parentid'])) {
             $node['userid'] = $this->arguments['userid'];
             $node['contenttypeid'] = $this->arguments['contenttypeid'];
             $node['title'] = $this->arguments['title'];
             $node['parentid'] = $this->arguments['parentid'];
         } else {
             try {
                 $node = vB_Library::instance('node')->getNodeBare($this->arguments['nodeid']);
             } catch (vB_Exception_Api $e) {
                 if ($e->has_error('invalid_node_id')) {
                     // the node does not exist, send a 404
                     throw new vB_Exception_404('invalid_page_url');
                 } else {
                     // rethrow exception
                     throw $e;
                 }
             }
         }
         // privacy check
         $albumChannel = vB_Api::instance('node')->fetchAlbumChannel($node['nodeid']);
         if ($node['parentid'] == $albumChannel) {
             $userInfo = vB_Api::instance('user')->fetchProfileInfo($node['userid']);
             if ($node['contenttypeid'] == vB_Types::instance()->getContentTypeID('vBForum_Video') and !$userInfo['showVideos'] or $node['contenttypeid'] == vB_Types::instance()->getContentTypeID('vBForum_Gallery') and (!$userInfo['showPhotos'] or !vB::getUserContext()->hasPermission('albumpermissions', 'canviewalbum'))) {
                 throw new vB_Exception_NodePermission($node['nodeid']);
             }
         }
         $contentApi = vB_Api_Content::getContentApi($node['contenttypeid']);
         if (!$contentApi->validate($node, vB_Api_Content::ACTION_VIEW, $node['nodeid'], array($node['nodeid'] => $node)) and empty($node['public_preview'])) {
             throw new vB_Exception_NodePermission($node['nodeid']);
         }
         if (!empty($this->queryParameters)) {
             $this->arguments['noindex'] = 1;
         }
         if (!empty($node['description'])) {
             $this->arguments['metadescription'] = $node['description'];
         }
         // set user action
         $this->setUserAction('viewing_topic_x', $node['title'], $this->getFullUrl('fullurl'));
         // set last crumb
         $this->breadcrumbs[] = array('title' => $node['title'], 'url' => '');
     }
     $this->arguments['pageSchema'] = 'http://schema.org/ItemPage';
 }
Beispiel #9
0
 /**
  * Cleans the input in the $data array, directly updating $data.
  *
  * @param mixed     Array of fieldname => data pairs, passed by reference.
  * @param int|false Nodeid of the node being edited, false if creating new
  */
 public function cleanInput(&$data, $nodeid = false)
 {
     parent::cleanInput($data, $nodeid);
     $canUseHtml = vB::getUserContext()->getChannelPermission('forumpermissions2', 'canusehtml', (empty($nodeid) and isset($data['parentid'])) ? $data['parentid'] : $nodeid);
     if (isset($data['htmlstate'])) {
         if ($canUseHtml) {
             switch ($data['htmlstate']) {
                 case 'on':
                 case 'on_nl2br':
                 case 'off':
                     // We're ok, don't do anything.
                     break;
                 default:
                     $data['htmlstate'] = 'off';
                     break;
             }
         } else {
             // User can't use HTML.
             $data['htmlstate'] = 'off';
         }
     }
     // ** clean attachment related data **
     // this calls the attach api to clean attachment data for this
     // text (or other content type) node. Only text content (and
     // subclasses) can have attachments, so this is the appropriate
     // place for this (not in the parent class)
     if (!empty($data['attachments'])) {
         if (is_array($data['attachments'])) {
             // use instanceInternal so we can pass by reference
             $attachApi = vB_Api::instanceInternal('Content_Attach');
             foreach ($data['attachments'] as $k => $v) {
                 // passed by reference and cleaned
                 $data['attachments'][$k]['parentid'] = $data['parentid'];
                 $attachApi->cleanInput($data['attachments'][$k]);
             }
         } else {
             $data['attachments'] = array();
         }
     }
     // Similar to above, but for gallery photos
     if (!empty($data['photos'])) {
         if (is_array($data['photos'])) {
             // use instanceInternal so we can pass by reference
             // Note, photoAPI actually doesn't have its own cleaner, so it just goes through this cleaner. But just in case we add its own, keep using
             // the photo API reference below.
             $photoApi = vB_Api::instanceInternal('Content_Photo');
             foreach ($data['photos'] as $k => $v) {
                 // passed by reference and cleaned
                 $data['photos'][$k]['parentid'] = $data['parentid'];
                 $photoApi->cleanInput($data['photos'][$k], $nodeid);
             }
         } else {
             $data['photos'] = array();
         }
     }
     if (!empty($data['removeattachments'])) {
         if (is_array($data['removeattachments'])) {
             $removeattachments = array();
             foreach ($data['removeattachments'] as $k => $v) {
                 $removeattachments[intval($k)] = intval($v);
             }
             $data['removeattachments'] = $removeattachments;
         } else {
             $data['removeattachments'] = array();
         }
     }
 }
 /**
  * Returns an array of all users participating in a discussion
  *
  * @param  int   the nodeid of the discussion
  *
  * @return array of user information
  *               * following -- is the participant a follower of the current user (may be NULL)
  *               * userid -- ID of the participant
  *               * username -- Name of the participant
  *               * avatarurl -- Url for the participant's avatar
  *               * starter -- ID of the starter for $nodeid
  */
 public function fetchParticipants($nodeid)
 {
     if (!intval($nodeid)) {
         throw new vB_Exception_Api('invalid_data');
     }
     $currentUser = vB::getCurrentSession()->get('userid');
     //We always should have something in $exclude.
     $exclude = array('-1');
     if (intval($currentUser)) {
         $options = vB::getDatastore()->get_value('options');
         if (trim($options['globalignore']) != '') {
             $exclude = preg_split('#\\s+#s', $options['globalignore'], -1, PREG_SPLIT_NO_EMPTY);
         }
     }
     $node = vB_Api::instanceInternal('node')->getNode($nodeid);
     $contentApi = vB_Api_Content::getContentApi($node['contenttypeid']);
     $valid = $contentApi->validate($node, vB_Api_Content::ACTION_VIEW, $node['nodeid'], array($node['nodeid'] => $node));
     //if the user can't see the node, then don't allow them to see the participants.
     if (!$valid) {
         throw new vB_Exception_Api('no_permission');
     }
     $nodeCTClass = vB_Types::instance()->getContentTypeClass($node['contenttypeid']);
     switch ($nodeCTClass) {
         case self::PARTICIPANTS_PM:
             $queryPart = 'vBForum:getPMRecipientsForMessageOverlay';
             $params = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_STORED, 'nodeid' => $nodeid);
             break;
         case self::PARTICIPANTS_POLL:
             // this seems a bit sketchy. This works (I think) because polls are always the starter due to
             // frontend restrictions, and no current notification will expect anything different when
             // calling this on a poll post, but if we have poll replies, and a notification called this function
             // expecting to get the thread participants, NOT poll voters, this would be a bug...
             $queryPart = 'vBForum:getNotificationPollVoters';
             $params = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_STORED, 'nodeid' => $nodeid);
             break;
             //for a channel we will quietly fail.  Trying to look up the participants is too expensive, is a potential DOS
             //and we don't really need it.
         //for a channel we will quietly fail.  Trying to look up the participants is too expensive, is a potential DOS
         //and we don't really need it.
         case self::PARTICIPANTS_CHANNEL:
             return array();
             break;
         default:
             // private messages should've been caught by the first case. At this point, we should only be concerned with content
             // nodes (excluding polls)
             $queryPart = 'vBForum:fetchParticipants';
             $params = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_STORED, 'nodeid' => $nodeid, 'currentuser' => $currentUser, 'exclude' => $exclude);
             break;
     }
     $members = vB::getDbAssertor()->getRows($queryPart, $params);
     $participants = array();
     foreach ($members as $member) {
         if (isset($participants[$member['userid']])) {
             continue;
         }
         $participants[$member['userid']] = $member;
     }
     $userApi = vB_Api::instanceInternal('user');
     foreach ($participants as $uid => $participant) {
         $participants[$uid]['avatarurl'] = $userApi->fetchAvatar($uid, true, $participant);
     }
     return $participants;
 }