function postNote($activity) { $note = $activity->objects[0]; // Use summary as fallback for content if (!empty($note->content)) { $sourceContent = $note->content; } else { if (!empty($note->summary)) { $sourceContent = $note->summary; } else { if (!empty($note->title)) { $sourceContent = $note->title; } else { // @fixme fetch from $sourceUrl? // TRANS: Client error displayed when posting a notice without content through the API. // TRANS: %d is the notice ID (number). $this->clientError(sprintf(_('No content for notice %d.'), $note->id)); return; } } } // Get (safe!) HTML and text versions of the content $rendered = $this->purify($sourceContent); $content = html_entity_decode(strip_tags($rendered), ENT_QUOTES, 'UTF-8'); $shortened = $this->auth_user->shortenLinks($content); $options = array('is_local' => Notice::LOCAL_PUBLIC, 'rendered' => $rendered, 'replies' => array(), 'groups' => array(), 'tags' => array(), 'urls' => array()); // accept remote URI (not necessarily a good idea) common_debug("Note ID is {$note->id}"); if (!empty($note->id)) { $notice = Notice::staticGet('uri', trim($note->id)); if (!empty($notice)) { // TRANS: Client error displayed when using another format than AtomPub. // TRANS: %s is the notice URI. $this->clientError(sprintf(_('Notice with URI "%s" already exists.'), $note->id)); return; } common_log(LOG_NOTICE, "Saving client-supplied notice URI '{$note->id}'"); $options['uri'] = $note->id; } // accept remote create time (also maybe not such a good idea) if (!empty($activity->time)) { common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}"); $options['created'] = common_sql_date($activity->time); } // Check for optional attributes... if (!empty($activity->context)) { foreach ($activity->context->attention as $uri) { $profile = Profile::fromURI($uri); if (!empty($profile)) { $options['replies'][] = $uri; } else { $group = User_group::staticGet('uri', $uri); if (!empty($group)) { $options['groups'][] = $group->id; } else { // @fixme: hook for discovery here common_log(LOG_WARNING, sprintf('AtomPub post with unknown attention URI %s', $uri)); } } } // Maintain direct reply associations // @fixme what about conversation ID? if (!empty($activity->context->replyToID)) { $orig = Notice::staticGet('uri', $activity->context->replyToID); if (!empty($orig)) { $options['reply_to'] = $orig->id; } } $location = $activity->context->location; if ($location) { $options['lat'] = $location->lat; $options['lon'] = $location->lon; if ($location->location_id) { $options['location_ns'] = $location->location_ns; $options['location_id'] = $location->location_id; } } } // Atom categories <-> hashtags foreach ($activity->categories as $cat) { if ($cat->term) { $term = common_canonical_tag($cat->term); if ($term) { $options['tags'][] = $term; } } } // Atom enclosures -> attachment URLs foreach ($activity->enclosures as $href) { // @fixme save these locally or....? $options['urls'][] = $href; } $saved = Notice::saveNew($this->user->id, $content, 'atompub', $options); return $saved; }
function moveActivity($act, $sink, $user, $remote) { if (empty($user)) { throw new Exception(sprintf(_("No such user %s."), $act->actor->id)); } switch ($act->verb) { case ActivityVerb::FAVORITE: $this->log(LOG_INFO, "Moving favorite of {$act->objects[0]->id} by " . "{$act->actor->id} to {$remote->nickname}."); // push it, then delete local $sink->postActivity($act); $notice = Notice::staticGet('uri', $act->objects[0]->id); if (!empty($notice)) { $fave = Fave::pkeyGet(array('user_id' => $user->id, 'notice_id' => $notice->id)); $fave->delete(); } break; case ActivityVerb::POST: $this->log(LOG_INFO, "Moving notice {$act->objects[0]->id} by " . "{$act->actor->id} to {$remote->nickname}."); // XXX: send a reshare, not a post $sink->postActivity($act); $notice = Notice::staticGet('uri', $act->objects[0]->id); if (!empty($notice)) { $notice->delete(); } break; case ActivityVerb::JOIN: $this->log(LOG_INFO, "Moving group join of {$act->objects[0]->id} by " . "{$act->actor->id} to {$remote->nickname}."); $sink->postActivity($act); $group = User_group::staticGet('uri', $act->objects[0]->id); if (!empty($group)) { Group_member::leave($group->id, $user->id); } break; case ActivityVerb::FOLLOW: if ($act->actor->id == $user->uri) { $this->log(LOG_INFO, "Moving subscription to {$act->objects[0]->id} by " . "{$act->actor->id} to {$remote->nickname}."); $sink->postActivity($act); $other = Profile::fromURI($act->objects[0]->id); if (!empty($other)) { Subscription::cancel($user->getProfile(), $other); } } else { $otherUser = User::staticGet('uri', $act->actor->id); if (!empty($otherUser)) { $this->log(LOG_INFO, "Changing sub to {$act->objects[0]->id}" . "by {$act->actor->id} to {$remote->nickname}."); $otherProfile = $otherUser->getProfile(); Subscription::start($otherProfile, $remote); Subscription::cancel($otherProfile, $user->getProfile()); } else { $this->log(LOG_NOTICE, "Not changing sub to {$act->objects[0]->id}" . "by remote {$act->actor->id} " . "to {$remote->nickname}."); } } break; } }
/** * Save reply records indicating that this notice needs to be * delivered to the local users with the given URIs. * * Since this is expected to be used when saving foreign-sourced * messages, we won't deliver to any remote targets as that's the * source service's responsibility. * * Mail notifications etc will be handled later. * * @param array of unique identifier URIs for recipients */ function saveKnownReplies($uris) { if (empty($uris)) { return; } $sender = Profile::staticGet($this->profile_id); foreach (array_unique($uris) as $uri) { $profile = Profile::fromURI($uri); if (empty($profile)) { common_log(LOG_WARNING, "Unable to determine profile for URI '{$uri}'"); continue; } if ($profile->hasBlocked($sender)) { common_log(LOG_INFO, "Not saving reply to profile {$profile->id} ({$uri}) from sender {$sender->id} because of a block."); continue; } $this->saveReply($profile->id); self::blow('reply:stream:%d', $profile->id); } return; }
/** * Save reply records indicating that this notice needs to be * delivered to the local users with the given URIs. * * Since this is expected to be used when saving foreign-sourced * messages, we won't deliver to any remote targets as that's the * source service's responsibility. * * Mail notifications etc will be handled later. * * @param array of unique identifier URIs for recipients */ function saveKnownReplies($uris) { if (empty($uris)) { return; } $sender = Profile::staticGet($this->profile_id); foreach (array_unique($uris) as $uri) { $profile = Profile::fromURI($uri); if (empty($profile)) { common_log(LOG_WARNING, "Unable to determine profile for URI '{$uri}'"); continue; } if ($profile->hasBlocked($sender)) { common_log(LOG_INFO, "Not saving reply to profile {$profile->id} ({$uri}) from sender {$sender->id} because of a block."); continue; } $reply = new Reply(); $reply->notice_id = $this->id; $reply->profile_id = $profile->id; common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$this->id} to profile {$profile->id}"); $id = $reply->insert(); } return; }
/** * Save a bookmark from an activity * * @param Activity $activity Activity to save * @param Profile $profile Profile to use as author * @param array $options Options to pass to bookmark-saving code * * @return Notice resulting notice */ function saveNoticeFromActivity($activity, $profile, $options = array()) { $bookmark = $activity->objects[0]; $relLinkEls = ActivityUtils::getLinks($bookmark->element, 'related'); if (count($relLinkEls) < 1) { // TRANS: Client exception thrown when a bookmark is formatted incorrectly. throw new ClientException(_m('Expected exactly 1 link ' . 'rel=related in a Bookmark.')); } if (count($relLinkEls) > 1) { common_log(LOG_WARNING, "Got too many link rel=related in a Bookmark."); } $linkEl = $relLinkEls[0]; $url = $linkEl->getAttribute('href'); $tags = array(); foreach ($activity->categories as $category) { $tags[] = common_canonical_tag($category->term); } if (!empty($activity->time)) { $options['created'] = common_sql_date($activity->time); } // Fill in location if available $location = $activity->context->location; if ($location) { $options['lat'] = $location->lat; $options['lon'] = $location->lon; if ($location->location_id) { $options['location_ns'] = $location->location_ns; $options['location_id'] = $location->location_id; } } $replies = $activity->context->attention; $options['groups'] = array(); $options['replies'] = array(); foreach ($replies as $replyURI) { $other = Profile::fromURI($replyURI); if (!empty($other)) { $options['replies'][] = $replyURI; } else { $group = User_group::staticGet('uri', $replyURI); if (!empty($group)) { $options['groups'][] = $replyURI; } } } // Maintain direct reply associations // @fixme what about conversation ID? if (!empty($activity->context->replyToID)) { $orig = Notice::staticGet('uri', $activity->context->replyToID); if (!empty($orig)) { $options['reply_to'] = $orig->id; } } return Bookmark::saveNew($profile, $bookmark->title, $url, $tags, $bookmark->summary, $options); }