'notice_profile_id_idx' => array('profile_id', 'created', 'id'),
'notice_repeat_of_created_id_idx' => array('repeat_of', 'created', 'id'),
'notice_conversation_created_id_idx' => array('conversation', 'created', 'id'),
+ 'notice_verb_idx' => array('verb'),
'notice_replyto_idx' => array('reply_to')
)
);
public function getRendered()
{
+ if (is_null($this->rendered) || $this->rendered === '') {
+ // update to include rendered content on-the-fly, so we don't have to have a fix-up script in upgrade.php
+ common_debug('Rendering notice '.$this->getID().' as it had no rendered HTML content.');
+ $orig = clone($this);
+ $this->rendered = common_render_content($this->getContent(),
+ $this->getProfile(),
+ $this->hasParent() ? $this->getParent() : null);
+ $this->update($orig);
+ }
return $this->rendered;
}
// The risk is we start having empty urls and non-http uris...
// and we can't really handle any other protocol right now.
switch (true) {
+ case $this->isLocal():
+ return common_local_url('shownotice', array('notice' => $this->getID()), null, null, false);
case common_valid_http_url($this->url): // should we allow non-http/https URLs?
return $this->url;
- case !$this->isLocal() && common_valid_http_url($this->uri): // Sometimes we only have the URI for remote posts.
+ case common_valid_http_url($this->uri): // Sometimes we only have the URI for remote posts.
return $this->uri;
- case $this->isLocal() || $fallback:
+ case $fallback:
// let's generate a valid link to our locally available notice on demand
- return common_local_url('shownotice', array('notice' => $this->id), null, null, false);
+ return common_local_url('shownotice', array('notice' => $this->getID()), null, null, false);
default:
- common_debug('No URL available for notice: id='.$this->id);
+ common_debug('No URL available for notice: id='.$this->getID());
throw new InvalidUrlException($this->url);
}
}
$content = $actobj->content ?: $actobj->summary;
}
$stored->rendered = $actor->isLocal() ? $content : common_purify($content);
+ // yeah, just don't use getRendered() here since it's not inserted yet ;)
$stored->content = common_strip_html($stored->rendered);
// Maybe a missing act-time should be fatal if the actor is not local?
throw new ServerException('StartNoticeSave did not give back a Notice');
}
- // Save per-notice metadata...
- $mentions = array();
- $group_ids = array();
-
- // This event lets plugins filter out non-local recipients (attentions we don't care about)
- // Used primarily for OStatus (and if we don't federate, all attentions would be local anyway)
- Event::handle('GetLocalAttentions', array($actor, $act->context->attention, &$mentions, &$group_ids));
-
// Only save 'attention' and metadata stuff (URLs, tags...) stuff if
// the activityverb is a POST (since stuff like repeat, favorite etc.
// reasonably handle notifications themselves.
if (ActivityUtils::compareVerbs($stored->verb, array(ActivityVerb::POST))) {
- if (!empty($mentions)) {
- $stored->saveKnownReplies($mentions);
- } else {
- $stored->saveReplies();
- }
+
+ $stored->saveAttentions($act->context->attention);
if (!empty($tags)) {
$stored->saveKnownTags($tags);
// to avoid errors on duplicates.
// Note: groups should always be set.
- $stored->saveKnownGroups($group_ids);
-
if (!empty($urls)) {
$stored->saveKnownUrls($urls);
} else {
return true;
}
+ function saveAttentions(array $uris)
+ {
+ foreach ($uris as $uri=>$type) {
+ try {
+ $target = Profile::fromUri($uri);
+ } catch (UnknownUriException $e) {
+ common_log(LOG_WARNING, "Unable to determine profile for URI '$uri'");
+ continue;
+ }
+
+ $this->saveAttention($target);
+ }
+ }
+
+ function saveAttention(Profile $target, $reason=null)
+ {
+ if ($target->isGroup()) {
+ // FIXME: Make sure we check that users are in the groups they send to!
+ } else {
+ if ($target->hasBlocked($this->getProfile())) {
+ common_log(LOG_INFO, "Not saving reply to profile {$target->id} ($uri) from sender {$sender->id} because of a block.");
+ return false;
+ }
+ }
+
+ if ($target->isLocal()) {
+ // is local user
+ $this->saveReply($target->getID()); // since we still have the Reply table which some apparently use!
+ }
+
+ try {
+ $att = Attention::saveNew($this, $target, $reason);
+ } catch (AlreadyFulfilledException $e) {
+ common_debug('Could not save Attention: '.$e->getMessage());
+ } catch (Exception $e) {
+ common_log(LOG_ERR, 'Could not save Attention: '.$e->getMessage());
+ }
+
+ self::blow('reply:stream:%d', $target->getID());
+ return true;
+ }
+
/**
* Save reply records indicating that this notice needs to be
* delivered to the local users with the given URIs.
$mentions = common_find_mentions($this->content, $sender, $parent);
- // store replied only for first @ (what user/notice what the reply directed,
- // we assume first @ is it)
-
foreach ($mentions as $mention) {
foreach ($mention['mentioned'] as $mentioned) {
}
// Don't save replies from blocked profile to local user
-
- $mentioned_user = User::getKV('id', $mentioned->id);
- if ($mentioned_user instanceof User && $mentioned_user->hasBlocked($sender)) {
+ if ($mentioned->hasBlocked($sender)) {
continue;
}
return $reply;
}
+ protected $_attentionids = array();
+
+ /**
+ * Pull the complete list of known activity context attentions for this notice.
+ *
+ * @return array of integer profile ids (also group profiles)
+ */
+ function getAttentionProfileIDs()
+ {
+ if (!isset($this->_attentionids[$this->getID()])) {
+ $atts = Attention::multiGet('notice_id', array($this->getID()));
+ // (array)null means empty array
+ $this->_attentionids[$this->getID()] = (array)$atts->fetchAll('profile_id');
+ }
+ return $this->_attentionids[$this->getID()];
+ }
+
protected $_replies = array();
/**
*/
function getAttentionProfiles()
{
- $ids = array_unique(array_merge($this->getReplies(), $this->getGroupProfileIDs()));
+ $ids = array_unique(array_merge($this->getReplies(), $this->getGroupProfileIDs(), $this->getAttentionProfileIDs()));
- $profiles = Profile::multiGet('id', $ids);
+ $profiles = Profile::multiGet('id', (array)$ids);
return $profiles->fetchAll();
}
// The notice is probably a share or similar, which don't
// have a representational URL of their own.
}
- $act->content = common_xml_safe_str($this->rendered);
+ $act->content = common_xml_safe_str($this->getRendered());
$profile = $this->getProfile();
$object->id = $this->getUri();
//FIXME: = $object->title ?: sprintf(... because we might get a title from StartActivityObjectFromNotice
$object->title = sprintf('New %1$s by %2$s', ActivityObject::canonicalType($object->type), $this->getProfile()->getNickname());
- $object->content = $this->rendered;
+ $object->content = $this->getRendered();
$object->link = $this->getUrl();
$object->extra[] = array('status_net', array('notice_id' => $this->id));
// If there's a failure, we want to _force_
// distribution at this point.
try {
+ $json = json_encode((object)array('id' => $this->getID(),
+ 'type' => 'Notice',
+ ));
$qm = QueueManager::get();
- $qm->enqueue($this, 'distrib');
+ $qm->enqueue($json, 'distrib');
} catch (Exception $e) {
// If the exception isn't transient, this
// may throw more exceptions as DQH does