/** * Retrieves the cluster object * * @since 1.3.8 * @access public * @param string * @return */ public function getCluster() { if (!$this->isCluster()) { return false; } // Get the cluster object $cluster = FD::cluster($this->cluster_type, $this->cluster_id); return $cluster; }
/** * Triggered to prepare the stream item * * @since 1.0 * @access public * @param string * @return */ public function onPrepareStream(SocialStreamItem &$stream, $includePrivacy = true) { // If this is not it's context, we don't want to do anything here. if ($stream->context != 'story') { return; } $uid = $stream->uid; $my = FD::user(); $privacy = FD::privacy($my->id); if ($stream->cluster_id) { // Group access checking $cluster = FD::cluster($stream->cluster_type, $stream->cluster_id); if (!$cluster) { return; } if (!$cluster->canViewItem()) { return; } // Allow editing of the stream item $stream->editable = $my->isSiteAdmin() || $cluster->isAdmin() || $stream->actor->id == $my->id; } else { // Allow editing of the stream item $stream->editable = $my->isSiteAdmin() || $stream->actor->id == $my->id; } // we stil need to check for the privacy because the context might come from the 'repost' if ($includePrivacy && !$privacy->validate('story.view', $uid, SOCIAL_TYPE_STORY, $stream->actor->id)) { return; } // Actor of this stream $actor = $stream->actor; $target = count($stream->targets) > 0 ? $stream->targets[0] : ''; $stream->display = SOCIAL_STREAM_DISPLAY_FULL; $stream->color = '#16a085'; $stream->fonticon = 'ies-pencil-2'; $stream->label = FD::_('APP_USER_STORY_UPDATES_STREAM_TOOLTIP', true); if ($stream->cluster_id) { if ($stream->cluster_type == SOCIAL_TYPE_GROUP) { $stream->color = '#303229'; $stream->fonticon = 'ies-users'; $stream->label = FD::_('APP_USER_STORY_GROUPS_STREAM_TOOLTIP', true); } if ($stream->cluster_type == SOCIAL_TYPE_EVENT) { $stream->color = '#f06050'; $stream->fonticon = 'ies-calendar'; $stream->label = FD::_('APP_USER_STORY_EVENTS_STREAM_TOOLTIP', true); } } $appGroup = SOCIAL_APPS_GROUP_USER; if ($stream->cluster_id) { if ($stream->cluster_type == SOCIAL_TYPE_EVENT) { $appGroup = SOCIAL_APPS_GROUP_EVENT; } else { $appGroup = SOCIAL_APPS_GROUP_GROUP; } } // Apply likes on the stream $likes = FD::likes(); $likes->get($stream->uid, $stream->context, $stream->verb, $appGroup, $stream->uid); $stream->likes = $likes; // Apply comments on the stream $comments = FD::comments($stream->uid, $stream->context, $stream->verb, $appGroup, array('url' => FRoute::stream(array('layout' => 'item', 'id' => $stream->uid))), $stream->uid); $stream->comments = $comments; // Apply repost on the stream $repost = FD::get('Repost', $stream->uid, SOCIAL_TYPE_STREAM, $appGroup); $stream->repost = $repost; // If this is a group type, and the viewer is not a member of the group, we need to hide these data if ($stream->cluster_id) { $cluster = FD::cluster($stream->cluster_type, $stream->cluster_id); if (!$cluster->isMember()) { $stream->commentLink = false; $stream->repost = false; $stream->commentForm = false; } // Sharing only show in public group if (!$cluster->isOpen()) { $stream->sharing = false; } } // Get application params $params = $this->getParams(); $this->set('params', $params); $this->set('actor', $actor); $this->set('target', $target); $this->set('stream', $stream); if ($stream->cluster_id) { $clusterReg = FD::registry($stream->params); $object = $clusterReg->get($stream->cluster_type); $cluster = FD::cluster($stream->cluster_type); if ($object) { // If have the object only bind $cluster->bind($object); } else { $cluster = $stream->getCluster(); } $this->set('cluster', $cluster); } $titleFileName = $stream->cluster_type ? $stream->cluster_type . '.' . $stream->verb : $stream->verb; $stream->title = parent::display('streams/title.' . $titleFileName); $stream->content = parent::display('streams/content.' . $stream->verb); $stream->opengraph->addDescription($stream->content); if ($includePrivacy) { $stream->privacy = $privacy->form($uid, SOCIAL_TYPE_STORY, $stream->actor->id, 'story.view', false, $stream->uid); } return true; }
/** * Creates a new stream item * * @since 1.0 * @access public * @param string * @return */ public function create($args = array()) { // The content of the story $content = isset($args['content']) ? $args['content'] : ''; // Context ids, and type that are related to the story $contextIds = isset($args['contextIds']) ? $args['contextIds'] : ''; $contextType = isset($args['contextType']) ? $args['contextType'] : ''; // The person that created this new story $actorId = isset($args['actorId']) ? $args['actorId'] : ''; // If the object is posting on another object, the target object id should be passed in here. $targetId = isset($args['targetId']) ? $args['targetId'] : null; // If the story is associated with a location, it should be processed. $location = isset($args['location']) ? $args['location'] : null; // If the story is being tagged with other users. $with = isset($args['with']) ? $args['with'] : null; // If the content of the story contains mentions using @ and # tags. $mentions = isset($args['mentions']) ? $args['mentions'] : array(); // If the story belongs in a cluster $cluster = isset($args['cluster']) ? $args['cluster'] : ''; $clusterType = isset($args['clusterType']) ? $args['clusterType'] : SOCIAL_TYPE_GROUP; // If the story contains a mood $mood = isset($args['mood']) ? $args['mood'] : null; // Store this into the stream now. $stream = FD::stream(); // Ensure that context ids are always array $contextIds = FD::makeArray($contextIds); // Determines which trigger group to call $group = $cluster ? $clusterType : SOCIAL_TYPE_USER; // Load apps FD::apps()->load($group); // Load up the dispatcher so that we can trigger this. $dispatcher = FD::dispatcher(); // This is to satisfy the setContext method. $contextId = isset($contextIds[0]) ? $contextIds[0] : 0; // Get the stream template $template = $stream->getTemplate(); $template->setActor($actorId, $this->type); $template->setContext($contextId, $contextType); $template->setContent($content); $verb = $contextType == 'photos' ? 'share' : 'create'; $template->setVerb($verb); $privacyRule = isset($args['privacyRule']) ? $args['privacyRule'] : null; $privacyValue = isset($args['privacyValue']) ? $args['privacyValue'] : null; $privacyCustom = isset($args['privacyCustom']) ? $args['privacyCustom'] : null; if (!$privacyRule) { $privacyRule = $contextType == 'photos' ? 'photos.view' : 'story.view'; } if ($privacyValue && is_string($privacyValue)) { $privacyValue = FD::privacy()->toValue($privacyValue); } if ($privacyCustom) { $privacyCustom = explode(',', $privacyCustom); } // Set this stream to be public $template->setAccess($privacyRule, $privacyValue, $privacyCustom); // Set mentions $template->setMentions($mentions); // Set the users tagged in the stream. $template->setWith($with); // Set the location of the stream $template->setLocation($location); // Set the mood if (!is_null($mood)) { $template->setMood($mood); } // If there's a target, we want it to appear on their stream too if ($targetId) { $template->setTarget($targetId); } if ($contextType == 'photos') { if (count($contextIds) > 0) { foreach ($contextIds as $photoId) { $template->setChild($photoId); } } } if ($cluster) { $clusterObj = FD::cluster($clusterType, $cluster); if ($clusterObj) { // Set the params to cache the group data $registry = FD::registry(); $registry->set($clusterType, $clusterObj); // Set the params to cache the group data $template->setParams($registry); $template->setCluster($cluster, $clusterType, $clusterObj->type); } else { $template->setCluster($cluster, $clusterType, 1); } } // Build the arguments for the trigger $args = array(&$template, &$stream, &$content); // @trigger onBeforeStorySave $dispatcher->trigger($group, 'onBeforeStorySave', $args); // Create the new stream item. $streamItem = $stream->add($template); // Store link items $this->storeLinks($stream, $streamItem, $template); // Set the notification type $notificationType = SOCIAL_TYPE_STORY; // Construct our new arguments $args = array(&$stream, &$streamItem, &$template); // @trigger onAfterStorySave $dispatcher->trigger($group, 'onAfterStorySave', $args); // Send a notification to the recipient if needed. if ($targetId && $actorId != $targetId) { $this->notify($targetId, $streamItem, $template->content, $contextIds, $contextType, $notificationType); } // Send a notification alert if there are mentions if ($mentions && !empty($mentions)) { $this->notifyMentions($streamItem, $mentions, $contextType, $contextIds, $template->content, $targetId); } return $streamItem; }
/** * Formats a stream item with the necessary data. * * Example: * <code> * </code> * * @since 1.0 * @access public * @param Array * */ public function format($items, $context = 'all', $viewer = null, $loadCoreAction = true, $defaultEvent = 'onPrepareStream', $options = array()) { // Get the current user $my = is_null($viewer) ? FD::user() : FD::user($viewer); // Basic display options $commentLink = isset($options['commentLink']) && $options['commentLink'] || !isset($options['commentLink']) ? true : false; $commentForm = isset($options['commentForm']) && $options['commentForm'] || !isset($options['commentForm']) ? true : false; // Default the event to onPrepareStream if (!$defaultEvent) { $defaultEvent = 'onPrepareStream'; } // Determines if this is a stream $isStream = false; if ($defaultEvent == 'onPrepareStream') { $isStream = true; } // If there's no items, skip formatting this because it's pointless to run after this. if (!$items) { return $items; } // Prepare default data $data = array(); $activeUser = FD::user(); // Get stream model $model = FD::model('Stream'); //current user being view. $targetUser = JRequest::getInt('id', ''); if (empty($targetUser)) { $targetUser = $my->id; } if ($targetUser && strpos($targetUser, ':')) { $tmp = explode(':', $targetUser); $targetUser = $tmp[0]; } // Get template configuration $templateConfig = FD::themes()->getConfig(); // Get the site configuration $config = FD::config(); // Link options // We only have to do this once instead of putting inside the loop. $linkOptions = array('target' => '_blank'); if ($config->get('stream.content.nofollow')) { $linkOptions['rel'] = 'nofollow'; } // Format items with appropriate objects. foreach ($items as &$row) { // Get the uid $uid = $row->id; // Get the last updated time $lastupdate = $row->modified; // Determines if this is a cluster $isCluster = $row->cluster_id ? true : false; // Obtain related activities for aggregation. $relatedActivities = null; if ($isStream) { $relatedActivities = $model->getRelatedActivities($uid, $row->context_type, $viewer); } else { $relatedActivities = $model->getActivityItem($uid); } $aggregatedData = $this->buildAggregatedData($relatedActivities); // Get the stream item. $streamItem = new SocialStreamItem(); if (isset($row->isNew)) { $streamItem->isNew = $row->isNew; } // Set the state $streamItem->state = $row->state; // Set the actors (Aggregated actors ) $streamItem->actors = $aggregatedData->actors; // Set the edited value $streamItem->edited = isset($row->edited) ? $row->edited : false; // Set the content $streamItem->content = $row->content; $streamItem->content_raw = $row->content; // Set the title of the stream item. $streamItem->title = $row->title; // Set the targets (Aggregated targets ) $streamItem->targets = $aggregatedData->targets; // Set the aggregated items here so 3rd party can manipulate the data. $streamItem->aggregatedItems = $relatedActivities; $streamItem->contextIds = $aggregatedData->contextIds; // Set the context params. ( Aggregated params ) $streamItem->contextParams = $aggregatedData->params; // main stream params $streamItem->params = $row->params; // Set the stream uid / activity id. $streamItem->uid = $uid; // Set stream lapsed time $streamItem->lapsed = FD::date($row->created)->toLapsed(); $streamItem->created = FD::date($row->created); // Set the actor with the user object. $streamItem->actor = FD::user($row->actor_id); // Set the context id. $streamItem->contextId = $aggregatedData->contextIds[0]; // Set the verb for this item. $streamItem->verb = $aggregatedData->verbs[0]; // Set the context type. $streamItem->context = $row->context_type; // stream display type $streamItem->display = $row->stream_type; // stream cluster_id $streamItem->cluster_id = $row->cluster_id; // stream cluster_type $streamItem->cluster_type = $row->cluster_type; // stream cluster_type $streamItem->cluster_access = $row->cluster_access; // stream privacy access $streamItem->access = $row->access; // stream privacy access $streamItem->custom_access = $row->custom_access; // Define an empty color $streamItem->color = ''; // Define an empty favicon $streamItem->icon = ''; // Always enable labels $streamItem->label = true; $streamItem->custom_label = ''; $streamItem->opengraph = FD::opengraph(); // Determines if this stream item has been bookmarked by the viewer $streamItem->bookmarked = false; if ($row->bookmarked) { $streamItem->bookmarked = true; } // Determines if this stream item has been bookmarked by the viewer $streamItem->sticky = false; if ($row->sticky) { $streamItem->sticky = true; } // @TODO: Since our stream has a unique favi on for each item. We need to get it here. // Each application is responsible to override this favicon, or stream wil use the context type. $streamItem->favicon = $row->context_type; $streamItem->type = $row->context_type; $streamDateDisplay = $templateConfig->get('stream_datestyle'); $streamItem->friendlyDate = $streamItem->lapsed; if ($streamDateDisplay == 'datetime') { $streamItem->friendlyDate = $streamItem->created->toFormat($templateConfig->get('stream_dateformat_format', 'Y-m-d H:i')); } // getting the the with and mention tagging for the stream, only if the item is a stream. $streamItem->with = array(); $streamItem->mention = array(); if ($isStream) { $streamItem->with = $this->getStreamTagWith($uid); $streamItem->tags = $this->getTags($uid); } // Format the mood if (!empty($row->mood_id)) { $mood = FD::table('Mood'); $mood->id = $row->md_id; $mood->namespace = $row->md_namespace; $mood->namespace_uid = $row->md_namespace_uid; $mood->icon = $row->md_icon; $mood->verb = $row->md_verb; $mood->subject = $row->md_subject; $mood->custom = $row->md_custom; $mood->text = $row->md_text; $mood->user_id = $row->md_user_id; $mood->created = $row->md_created; $streamItem->mood = $mood; } // Format the users that are tagged in this stream. if (!empty($row->location_id)) { $location = FD::table('Location'); //$location->load( $row->location_id ); // lets assign the values into location jtable. $location->id = $row->loc_id; $location->uid = $row->loc_uid; $location->type = $row->loc_type; $location->user_id = $row->loc_user_id; $location->created = $row->loc_created; $location->short_address = $row->loc_short_address; $location->address = $row->loc_address; $location->latitude = $row->loc_latitude; $location->longitude = $row->loc_longitude; $location->params = $row->loc_params; $streamItem->location = $location; } // target user. this target user is different from the targets. this is the user who are being viewed currently. $streamItem->targetUser = $targetUser; // privacy $streamItem->privacy = null; // Check if the content is not empty. We need to perform some formatings if (isset($streamItem->content) && !empty($streamItem->content)) { $content = $streamItem->content; // Format mentions $content = $this->formatMentions($streamItem); // Apply e-mail replacements $content = FD::string()->replaceEmails($content); // Apply bbcode $content = FD::string()->parseBBCode($content, array('escape' => false, 'links' => true, 'code' => true)); // Some app might want the raw contents $streamItem->content_raw = $streamItem->content; $streamItem->content = $content; } // Stream meta $streamItem->meta = ''; if (!empty($streamItem->with) || !empty($streamItem->location) || !empty($streamItem->mood)) { $theme = FD::themes(); $theme->set('stream', $streamItem); $streamItem->meta = $theme->output('site/stream/meta'); } // Determines if the stream item is deleteable $streamItem->deleteable = false; // Determines if the stream item is editable $streamItem->editable = false; // Group stream should allow cluster admins to delete if ($streamItem->cluster_id) { $cluster = FD::cluster($streamItem->cluster_type, $streamItem->cluster_id); if ($cluster->isAdmin() || FD::user()->isSiteAdmin() || FD::user()->getAccess()->allowed('stream.delete', false) && FD::user()->id == $streamItem->actor->id) { $streamItem->deleteable = true; } } else { if (FD::user()->getAccess()->allowed('stream.delete', false) && FD::user()->id == $streamItem->actor->id) { $streamItem->deleteable = true; } } if (FD::user()->isSiteAdmin()) { $streamItem->deleteable = true; } // streams actions. $streamItem->comments = $defaultEvent == 'onPrepareStream' ? true : false; $streamItem->likes = $defaultEvent == 'onPrepareStream' ? true : false; $streamItem->repost = $defaultEvent == 'onPrepareStream' ? true : false; // @trigger onPrepareStream / onPrepareActivity $includePrivacy = $isCluster ? false : true; $result = $this->{$defaultEvent}($streamItem, $includePrivacy); // Allow app to stop loading / generating the stream and // if there is still no title, we need to skip this stream altogether. if ($result === false || !$streamItem->title) { continue; } // Set the plain content here. if (empty($streamItem->opengraph->properties['description'])) { $streamItem->opengraph->addDescription(strip_tags($streamItem->content)); } // This mean the plugin did not set any privacy. lets use the stream / activity. if (is_null($streamItem->privacy) && !$isCluster) { $privacyObj = FD::privacy($activeUser->id); $privacy = isset($row->privacy) ? $row->privacy : null; $pUid = $uid; $tmpStreamId = $defaultEvent == 'onPrepareActivityLog' ? $row->uid : $row->id; $sModel = FD::model('Stream'); $aItem = $sModel->getActivityItem($tmpStreamId, 'uid'); if (count($streamItem->contextIds) == 1 && is_null($privacy)) { if ($aItem) { $pUid = $aItem[0]->id; } } if (!$privacyObj->validate('core.view', $pUid, SOCIAL_TYPE_ACTIVITY, $streamItem->actor->id)) { continue; } $tmpStreamId = $streamItem->aggregatedItems[0]->uid; if ($defaultEvent == 'onPrepareActivityLog') { $tmpStreamId = count($aItem) > 1 ? '' : $tmpStreamId; } $streamItem->privacy = $privacyObj->form($pUid, SOCIAL_TYPE_ACTIVITY, $streamItem->actor->id, null, false, $tmpStreamId); } $itemGroup = $streamItem->cluster_id ? $streamItem->cluster_type : SOCIAL_APPS_GROUP_USER; if ($streamItem->display != SOCIAL_STREAM_DISPLAY_MINI) { $canComment = true; // comments if (isset($streamItem->comments) && $streamItem->comments) { if (!$streamItem->comments instanceof SocialCommentBlock) { $streamItem->comments = FD::comments($streamItem->contextId, $streamItem->context, $streamItem->verb, $itemGroup, array('url' => FRoute::stream(array('layout' => 'item', 'id' => $streamItem->uid))), $streamItem->uid); } // for comments, we need to check against the actor privacy and see if the current viewer allow to // post comments on their stream items or not. if (!$isCluster) { $privacyObj = FD::privacy($activeUser->id); if (!$privacyObj->validate('story.post.comment', $streamItem->actor->id, SOCIAL_TYPE_USER)) { $canComment = false; } } } // Set comment option the streamid if ($streamItem->comments) { $streamItem->comments->setOption('streamid', $streamItem->uid); } // If comments link is meant to be disabled, hide it if (!$commentLink) { $streamItem->commentLink = false; } // If comments is meant to be disabled, hide it. if ($streamItem->comments && (isset($streamItem->commentForm) && !$streamItem->commentForm || !$commentForm || !$canComment)) { $streamItem->comments->setOption('hideForm', true); } //likes if (isset($streamItem->likes) && $streamItem->likes) { if (!$streamItem->likes instanceof SocialLikes) { $likes = FD::likes(); $likes->get($streamItem->contextId, $streamItem->context, $streamItem->verb, $itemGroup, $streamItem->uid); $streamItem->likes = $likes; } } //set likes option the streamid if ($streamItem->likes) { $streamItem->likes->setOption('streamid', $streamItem->uid); } // Build repost links if (isset($streamItem->repost) && $streamItem->repost) { if (!$streamItem->repost instanceof SocialRepost) { $repost = FD::get('Repost', $streamItem->uid, SOCIAL_TYPE_STREAM, $itemGroup); $streamItem->repost = $repost; } } // set cluseter into repost if ($isCluster && $streamItem->repost) { $streamItem->repost->setCluster($streamItem->cluster_id, $streamItem->cluster_type); } // Enable sharing on the stream if ($config->get('stream.sharing.enabled')) { if (!isset($streamItem->sharing) || isset($streamItem->sharing) && $streamItem->sharing !== false && !$streamItem->sharing instanceof SocialSharing) { $sharing = FD::get('Sharing', array('url' => FRoute::stream(array('layout' => 'item', 'id' => $streamItem->uid, 'external' => true), true), 'display' => 'dialog', 'text' => JText::_('COM_EASYSOCIAL_STREAM_SOCIAL'), 'css' => 'fd-small')); $streamItem->sharing = $sharing; } } // Now we have all the appropriate data, populate the actions $streamItem->actions = $this->getActions($streamItem); } else { $streamItem->comments = false; $streamItem->likes = false; $streamItem->repost = false; $streamItem->actions = ''; } // Re-assign stream item to the result list. $data[] = $streamItem; } // here we know, the result from queries contain some records but it might return empty data due to privacy. // if that is the case, then we return TRUE so that the library will go retrieve the next set of data. if (count($data) <= 0) { return true; } return $data; }
/** * Prepares the stream item for new file uploads * * @since 1.0 * @access public * @param SocialStreamItem The stream item. * @return */ private function prepareUploadedStream(&$item) { $params = FD::registry($item->params); // Get the file object $file = FD::table('File'); $exists = $file->load($params->get('file')->id); if (!$exists) { return; } // Get the actor $actor = $item->actor; $this->set('actor', $actor); $this->set('file', $file); $clusterType = ''; if ($item->cluster_id && $item->cluster_type) { $cluster = FD::cluster($item->cluster_type, $item->cluster_id); $this->set('cluster', $cluster); $clusterType = '.' . $item->cluster_type; } // Load up the contents now. $item->title = parent::display('streams/uploaded.title' . $clusterType); $item->content = parent::display('streams/uploaded.content'); }
/** * Prepares the stream item for new file uploads * * @since 1.0 * @access public * @param SocialStreamItem The stream item. * @return */ private function prepareUploadedStream(&$item) { $params = FD::registry($item->params); // Default items $files = array(); // Load the file from params $obj = $params->get('file'); // Default content $content = ''; if (is_object($obj)) { // Get the file object $file = FD::table('File'); $exists = $file->load($obj->id); if (!$exists) { return; } $files[] = $file; } else { // This is not an object and probably it's an array? $params = FD::registry($item->contextParams[0]); $fileItems = $params->get('file'); foreach ($fileItems as $fileId) { $file = FD::table('File'); $file->load((int) $fileId); $files[] = $file; } $content = $item->content; } // Get the actor $actor = $item->actor; $this->set('content', $content); $this->set('actor', $actor); $this->set('files', $files); $clusterType = ''; if ($item->cluster_id && $item->cluster_type) { $cluster = FD::cluster($item->cluster_type, $item->cluster_id); $this->set('cluster', $cluster); $clusterType = '.' . $item->cluster_type; } // Load up the contents now. $item->title = parent::display('streams/uploaded.title' . $clusterType); $item->content = parent::display('streams/uploaded.content'); }
/** * Central method to create stream for this task. * @param string $verb The verb for the stream. * @param integer $actorId The actor user id. */ public function createStream($verb, $actorId = null) { $stream = FD::stream(); $tpl = $stream->getTemplate(); $actor = FD::user($actorId); $registry = FD::registry(); // We set it to array because it is possible that 1 stream contains many tasks that are created from story form $registry->set('tasks', array($this)); $registry->set('milestone', $this->getMilestone()); if ($this->type == SOCIAL_TYPE_USER) { $user = FD::user($this->uid); // Cache the user data into the params $registry->set('user', $user); } else { // Get the cluster depending on the type $cluster = FD::cluster($this->type, $this->uid); // this is a cluster stream and it should be viewable in both cluster and user page. $tpl->setCluster($cluster->id, $this->type, $cluster->type); // Cache the cluster data into the params $registry->set($this->type, $cluster); } // Set the actor $tpl->setActor($actor->id, SOCIAL_TYPE_USER); // Set the context $tpl->setContext($this->id, 'tasks'); // Set the verb $tpl->setVerb($verb); // Set the params to cache the group data $tpl->setParams($registry); // since this is a cluster and user stream, we need to call setPublicStream // so that this stream will display in unity page as well // This stream should be visible to the public $tpl->setAccess('core.view'); $stream->add($tpl); }
/** * Determines if the stream item can be made sticky * * @since 1.3 * @access public * @param string * @return */ public function canSticky() { $my = FD::user(); $config = FD::config(); if (!$config->get('stream.pin.enabled')) { return false; } // If the stream is moderated, it shouldn't be allowed to be stickied if ($this->isModerated()) { return false; } if ($my->isSiteAdmin()) { return true; } if ($this->isCluster()) { $cluster = FD::cluster($this->cluster_type, $this->cluster_id); // if user is not the cluster owner or the admin, then dont alllow to sticky if (!$cluster->isOwner() && !$cluster->isAdmin()) { return false; } } else { if (!$this->isOwner()) { return false; } } return true; }
public function getParent() { if (empty($this->parent_id) || empty($this->parent_type)) { return false; } return FD::cluster($this->parent_type, $this->parent_id); }