forked from GNUsocial/gnu-social
Added saveActivity method to Notice class
saveActivity will accept an Activity which gets parsed and saved through plugins. So when an ActivityHandlerPlugin (such as Favorite will be soon) gets a feed to save, this will be the function called instead of saveNew.
This commit is contained in:
parent
687f8ab42c
commit
acb07ef52f
@ -627,41 +627,13 @@ class Notice extends Managed_DataObject
|
||||
$notice->object_type = $object_type;
|
||||
}
|
||||
|
||||
if (is_null($scope)) { // 0 is a valid value
|
||||
if (!empty($reply)) {
|
||||
if (is_null($scope) && $reply instanceof Notice) {
|
||||
$notice->scope = $reply->scope;
|
||||
} else {
|
||||
$notice->scope = self::defaultScope();
|
||||
}
|
||||
} else {
|
||||
$notice->scope = $scope;
|
||||
}
|
||||
|
||||
// For private streams
|
||||
|
||||
try {
|
||||
$user = $profile->getUser();
|
||||
|
||||
if ($user->private_stream &&
|
||||
($notice->scope == Notice::PUBLIC_SCOPE ||
|
||||
$notice->scope == Notice::SITE_SCOPE)) {
|
||||
$notice->scope |= Notice::FOLLOWER_SCOPE;
|
||||
}
|
||||
} catch (NoSuchUserException $e) {
|
||||
// Cannot handle private streams for remote profiles
|
||||
}
|
||||
|
||||
// Force the scope for private groups
|
||||
|
||||
foreach ($groups as $groupId) {
|
||||
$group = User_group::getKV('id', $groupId);
|
||||
if ($group instanceof User_group) {
|
||||
if ($group->force_scope) {
|
||||
$notice->scope |= Notice::GROUP_SCOPE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$notice->scope = self::figureOutScope($profile, $groups, $notice->scope);
|
||||
|
||||
if (Event::handle('StartNoticeSave', array(&$notice))) {
|
||||
|
||||
@ -749,6 +721,252 @@ class Notice extends Managed_DataObject
|
||||
return $notice;
|
||||
}
|
||||
|
||||
static function saveActivity(Activity $act, Profile $actor, array $options=array()) {
|
||||
|
||||
// First check if we're going to let this Activity through from the specific actor
|
||||
if (!$actor->hasRight(Right::NEWNOTICE)) {
|
||||
common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $actor->getNickname());
|
||||
|
||||
// TRANS: Client exception thrown when a user tries to post while being banned.
|
||||
throw new ClientException(_m('You are banned from posting notices on this site.'), 403);
|
||||
}
|
||||
if (common_config('throttle', 'enabled') && !self::checkEditThrottle($actor->id)) {
|
||||
common_log(LOG_WARNING, 'Excessive posting by profile #' . $actor->id . '; throttled.');
|
||||
// TRANS: Client exception thrown when a user tries to post too many notices in a given time frame.
|
||||
throw new ClientException(_m('Too many notices too fast; take a breather '.
|
||||
'and post again in a few minutes.'));
|
||||
}
|
||||
|
||||
// Get ActivityObject properties
|
||||
$actobj = count($act->objects)==1 ? $act->objects[0] : null;
|
||||
if (!is_null($actobj) && $actobj->id) {
|
||||
$options['uri'] = $actobj->id;
|
||||
if ($actobj->link) {
|
||||
$options['url'] = $actobj->link;
|
||||
} elseif ($act->link) {
|
||||
$options['url'] = $act->link;
|
||||
} elseif (preg_match('!^https?://!', $actobj->id)) {
|
||||
$options['url'] = $actobj->id;
|
||||
}
|
||||
} else {
|
||||
// implied object
|
||||
$options['uri'] = $act->id;
|
||||
$options['url'] = $act->link;
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'groups' => array(),
|
||||
'is_local' => self::LOCAL_PUBLIC,
|
||||
'mentions' => array(),
|
||||
'reply_to' => null,
|
||||
'repeat_of' => null,
|
||||
'scope' => null,
|
||||
'source' => 'unknown',
|
||||
'tags' => array(),
|
||||
'uri' => null,
|
||||
'url' => null,
|
||||
'urls' => array(),
|
||||
'distribute' => true);
|
||||
|
||||
// options will have default values when nothing has been supplied
|
||||
$options = array_merge($defaults, $options);
|
||||
foreach (array_keys($defaults) as $key) {
|
||||
// Only convert the keynames we specify ourselves from 'defaults' array into variables
|
||||
$$key = $options[$key];
|
||||
}
|
||||
extract($options, EXTR_SKIP);
|
||||
|
||||
$stored = new Notice();
|
||||
if (!empty($uri)) {
|
||||
$stored->uri = $uri;
|
||||
if ($stored->find()) {
|
||||
common_debug('cannot create duplicate Notice URI: '.$stored->uri);
|
||||
throw new Exception('Notice URI already exists');
|
||||
}
|
||||
}
|
||||
|
||||
$stored->profile_id = $actor->id;
|
||||
$stored->source = $source;
|
||||
$stored->uri = $uri;
|
||||
$stored->url = $url;
|
||||
$stored->verb = $act->verb;
|
||||
|
||||
$autosource = common_config('public', 'autosource');
|
||||
|
||||
// Sandboxed are non-false, but not 1, either
|
||||
if (!$actor->hasRight(Right::PUBLICNOTICE) ||
|
||||
($source && $autosource && in_array($source, $autosource))) {
|
||||
$stored->is_local = Notice::LOCAL_NONPUBLIC;
|
||||
}
|
||||
|
||||
// Maybe a missing act-time should be fatal if the actor is not local?
|
||||
if (!empty($act->time)) {
|
||||
$stored->created = common_sql_date($act->time);
|
||||
} else {
|
||||
$stored->created = common_sql_now();
|
||||
}
|
||||
|
||||
$reply = null;
|
||||
if ($act->context instanceof ActivityContext && !empty($act->context->replyToID)) {
|
||||
$reply = self::getKV('uri', $act->context->replyToID);
|
||||
}
|
||||
if (!$reply instanceof Notice && $act->target instanceof ActivityObject) {
|
||||
$reply = self::getKV('uri', $act->target->id);
|
||||
}
|
||||
|
||||
if ($reply instanceof Notice) {
|
||||
if (!$reply->inScope($actor)) {
|
||||
// TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
|
||||
// TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
|
||||
throw new ClientException(sprintf(_m('%1$s has no right to reply to notice %2$d.'), $actor->getNickname(), $reply->id), 403);
|
||||
}
|
||||
|
||||
$stored->reply_to = $reply->id;
|
||||
$stored->conversation = $reply->conversation;
|
||||
|
||||
// If the original is private to a group, and notice has no group specified,
|
||||
// make it to the same group(s)
|
||||
if (empty($groups) && ($reply->scope & Notice::GROUP_SCOPE)) {
|
||||
$groups = array();
|
||||
$replyGroups = $reply->getGroups();
|
||||
foreach ($replyGroups as $group) {
|
||||
if ($actor->isMember($group)) {
|
||||
$groups[] = $group->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($scope)) {
|
||||
$scope = $reply->scope;
|
||||
}
|
||||
}
|
||||
|
||||
if ($act->context instanceof ActivityContext) {
|
||||
$location = $act->context->location;
|
||||
if ($location) {
|
||||
$stored->lat = $location->lat;
|
||||
$stored->lon = $location->lon;
|
||||
if ($location->location_id) {
|
||||
$stored->location_ns = $location->location_ns;
|
||||
$stored->location_id = $location->location_id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$act->context = new ActivityContext();
|
||||
}
|
||||
|
||||
$stored->scope = self::figureOutScope($actor, $groups, $scope);
|
||||
|
||||
foreach ($act->categories as $cat) {
|
||||
if ($cat->term) {
|
||||
$term = common_canonical_tag($cat->term);
|
||||
if (!empty($term)) {
|
||||
$tags[] = $term;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($act->enclosures as $href) {
|
||||
// @todo FIXME: Save these locally or....?
|
||||
$urls[] = $href;
|
||||
}
|
||||
|
||||
if (Event::handle('StartNoticeSave', array(&$stored))) {
|
||||
// XXX: some of these functions write to the DB
|
||||
|
||||
try {
|
||||
$stored->insert(); // throws exception on error
|
||||
|
||||
$object = null;
|
||||
Event::handle('StoreActivityObject', array($act, $stored, $options, &$object));
|
||||
if (empty($object)) {
|
||||
throw new ServerException('No object from StoreActivityObject '.$stored->uri . ': '.$act->asString());
|
||||
}
|
||||
$orig = clone($stored);
|
||||
$stored->object_type = ActivityUtils::resolveUri($object->type, true);
|
||||
$stored->update($orig);
|
||||
} catch (Exception $e) {
|
||||
if (empty($stored->id)) {
|
||||
common_debug('Failed to save stored object entry in database ('.$e->getMessage().')');
|
||||
} else {
|
||||
common_debug('Failed to store activity object in database ('.$e->getMessage().'), deleting notice id '.$stored->id);
|
||||
$stored->delete();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Save per-notice metadata...
|
||||
$mentions = array();
|
||||
$groups = 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, &$groups));
|
||||
|
||||
if (!empty($mentions)) {
|
||||
$stored->saveKnownReplies($mentions);
|
||||
} else {
|
||||
$stored->saveReplies();
|
||||
}
|
||||
|
||||
if (!empty($tags)) {
|
||||
$stored->saveKnownTags($tags);
|
||||
} else {
|
||||
$stored->saveTags();
|
||||
}
|
||||
|
||||
// Note: groups may save tags, so must be run after tags are saved
|
||||
// to avoid errors on duplicates.
|
||||
// Note: groups should always be set.
|
||||
|
||||
$stored->saveKnownGroups($groups);
|
||||
|
||||
if (!empty($urls)) {
|
||||
$stored->saveKnownUrls($urls);
|
||||
} else {
|
||||
$stored->saveUrls();
|
||||
}
|
||||
|
||||
if ($distribute) {
|
||||
// Prepare inbox delivery, may be queued to background.
|
||||
$stored->distribute();
|
||||
}
|
||||
|
||||
return $stored;
|
||||
}
|
||||
|
||||
static public function figureOutScope(Profile $actor, array $groups, $scope=null) {
|
||||
if (is_null($scope)) {
|
||||
$scope = self::defaultScope();
|
||||
}
|
||||
|
||||
// For private streams
|
||||
try {
|
||||
$user = $actor->getUser();
|
||||
// FIXME: We can't do bit comparison with == (Legacy StatusNet thing. Let's keep it for now.)
|
||||
if ($user->private_stream && ($scope == Notice::PUBLIC_SCOPE || $scope == Notice::SITE_SCOPE)) {
|
||||
$scope |= Notice::FOLLOWER_SCOPE;
|
||||
}
|
||||
} catch (NoSuchUserException $e) {
|
||||
// TODO: Not a local user, so we don't know about scope preferences... yet!
|
||||
}
|
||||
|
||||
// Force the scope for private groups
|
||||
foreach ($groups as $group_id) {
|
||||
$group = User_group::staticGet('id', $group_id);
|
||||
if ($group instanceof User_group) {
|
||||
if ($group->force_scope) {
|
||||
$scope |= Notice::GROUP_SCOPE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
function blowOnInsert($conversation = false)
|
||||
{
|
||||
$this->blowStream('profile:notice_ids:%d', $this->profile_id);
|
||||
|
@ -1360,4 +1360,9 @@ class OStatusPlugin extends Plugin
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onGetLocalAttentions(Profile $actor, array $attention_uris, array &$mentions, array &$groups)
|
||||
{
|
||||
list($mentions, $groups) = Ostatus_profile::filterAttention($actor, $attention_uris);
|
||||
}
|
||||
}
|
||||
|
@ -670,7 +670,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
if ($activity->context) {
|
||||
// TODO: context->attention
|
||||
list($options['groups'], $options['replies'])
|
||||
= $this->filterAttention($oprofile, $activity->context->attention);
|
||||
= self::filterAttention($oprofile->localProfile(), $activity->context->attention);
|
||||
|
||||
// Maintain direct reply associations
|
||||
// @todo FIXME: What about conversation ID?
|
||||
@ -839,7 +839,7 @@ class Ostatus_profile extends Managed_DataObject
|
||||
if ($activity->context) {
|
||||
// TODO: context->attention
|
||||
list($options['groups'], $options['replies'])
|
||||
= $this->filterAttention($oprofile, $activity->context->attention);
|
||||
= self::filterAttention($oprofile->localProfile(), $activity->context->attention);
|
||||
|
||||
// Maintain direct reply associations
|
||||
// @todo FIXME: What about conversation ID?
|
||||
@ -913,11 +913,11 @@ class Ostatus_profile extends Managed_DataObject
|
||||
|
||||
/**
|
||||
* Filters a list of recipient ID URIs to just those for local delivery.
|
||||
* @param Ostatus_profile local profile of sender
|
||||
* @param Profile local profile of sender
|
||||
* @param array in/out &$attention_uris set of URIs, will be pruned on output
|
||||
* @return array of group IDs
|
||||
*/
|
||||
protected function filterAttention($sender, array $attention)
|
||||
static public function filterAttention(Profile $sender, array $attention)
|
||||
{
|
||||
common_log(LOG_DEBUG, "Original reply recipients: " . implode(', ', array_keys($attention)));
|
||||
$groups = array();
|
||||
@ -937,16 +937,11 @@ class Ostatus_profile extends Managed_DataObject
|
||||
if ($id) {
|
||||
$group = User_group::getKV('id', $id);
|
||||
if ($group instanceof User_group) {
|
||||
try {
|
||||
// Deliver to all members of this local group if allowed.
|
||||
$profile = $sender->localProfile();
|
||||
if ($profile->isMember($group)) {
|
||||
if ($sender->isMember($group)) {
|
||||
$groups[] = $group->id;
|
||||
} else {
|
||||
common_log(LOG_DEBUG, "Skipping reply to local group $group->nickname as sender $profile->id is not a member");
|
||||
}
|
||||
} catch (NoProfileException $e) {
|
||||
// Sender has no profile! Do some garbage collection, please.
|
||||
common_log(LOG_DEBUG, sprintf('Skipping reply to local group %s as sender %d is not a member', $group->getNickname(), $sender->id));
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user