* gets to figure out how to actually save it into a notice
* and any additional data structures you require.
*
- * This will handle things received via AtomPub, OStatus
- * (PuSH and Salmon transports), or ActivityStreams-based
- * backup/restore of account data.
- *
- * You should be able to accept as input the output from your
- * $this->activityObjectFromNotice(). Where applicable, try to
- * use existing ActivityStreams structures and object types,
- * and be liberal in accepting input from what might be other
- * compatible apps.
- *
- * All micro-app classes must override this method.
- *
- * @fixme are there any standard options?
+ * This function is deprecated and in the future, Notice::saveActivity
+ * should be called from onStartHandleFeedEntryWithProfile in this class.
*
* @param Activity $activity
* @param Profile $actor
*
* @return Notice the resulting notice
*/
- abstract function saveNoticeFromActivity(Activity $activity, Profile $actor, array $options=array());
+ public function saveNoticeFromActivity(Activity $activity, Profile $actor, array $options=array())
+ {
+ // Any plugin which has not implemented saveObjectFromActivity _must_
+ // override this function (which will be deleted when all plugins are migrated).
+
+ if (isset($this->oldSaveNew)) {
+ throw new ServerException('A function has been called for new saveActivity functionality, but is still set with an oldSaveNew configuration');
+ }
+
+ return Notice::saveActivity($activity, $actor, $options);
+ }
+
+ /*
+ * This usually gets called from Notice::saveActivity after a Notice object has been created,
+ * so it contains a proper id and a uri for the object to be saved.
+ */
+ public function onStoreActivityObject(Activity $act, Notice $stored, array $options=array(), &$object) {
+ // $this->oldSaveNew is there during a migration period of plugins, to start using
+ // Notice::saveActivity instead of Notice::saveNew
+ if (!$this->isMyActivity($act) || isset($this->oldSaveNew)) {
+ return true;
+ }
+ $object = $this->saveObjectFromActivity($act, $stored, $options);
+ try {
+ $act->context->attention = array_merge($act->context->attention, $object->getAttentionArray());
+ } catch (Exception $e) {
+ common_debug('WARNING: Could not get attention list from object '.get_class($object).'!');
+ }
+ return false;
+ }
/**
* Given an existing Notice object, your plugin gets to
* Handle a posted object from PuSH
*
* @param Activity $activity activity to handle
- * @param Ostatus_profile $oprofile Profile for the feed
+ * @param Profile $actor Profile for the feed
*
* @return boolean hook value
*/
- function onStartHandleFeedEntryWithProfile(Activity $activity, $oprofile, &$notice)
+ function onStartHandleFeedEntryWithProfile(Activity $activity, Profile $profile, &$notice)
{
if (!$this->isMyActivity($activity)) {
return true;
}
- $actor = $oprofile->checkAuthorship($activity);
-
- if (!$actor instanceof Ostatus_profile) {
- // TRANS: Client exception thrown when no author for an activity was found.
- throw new ClientException(_('Cannot get author for activity.'));
- }
+ // We are guaranteed to get a Profile back from checkAuthorship (or it throws an exception)
+ $profile = ActivityUtils::checkAuthorship($activity, $profile);
$object = $activity->objects[0];
'is_local' => Notice::REMOTE,
'source' => 'ostatus');
- // $actor is an ostatus_profile
- $notice = $this->saveNoticeFromActivity($activity, $actor->localProfile(), $options);
+ $notice = $this->saveNoticeFromActivity($activity, $profile, $options);
return false;
}
}
return $object;
}
+
+ // Check authorship by supplying a Profile as a default and letting plugins
+ // set it to something else if the activity's author is actually someone
+ // else (like with a group or peopletag feed as handled in OStatus).
+ //
+ // NOTE: Returned is not necessarily the supplied profile! For example,
+ // the "feed author" may be a group, but the "activity author" is a person!
+ static function checkAuthorship(Activity $activity, Profile $profile)
+ {
+ if (Event::handle('CheckActivityAuthorship', array($activity, &$profile))) {
+ // if (empty($activity->actor)), then we generated this Activity ourselves and can trust $profile
+
+ $actor_uri = $profile->getUri();
+
+ if (!in_array($actor_uri, array($activity->actor->id, $activity->actor->link))) {
+ // A mismatch between our locally stored URI and the supplied author?
+ // Probably not more than a blog feed or something (with multiple authors or so)
+ // but log it for future inspection.
+ common_log(LOG_WARNING, "Got an actor '{$activity->actor->title}' ({$activity->actor->id}) on single-user feed for " . $actor_uri);
+ } elseif (empty($activity->actor->id)) {
+ // Plain <author> without ActivityStreams actor info.
+ // We'll just ignore this info for now and save the update under the feed's identity.
+ }
+ }
+
+ if (!$profile instanceof Profile) {
+ throw new ServerException('Could not get an author Profile for activity');
+ }
+
+ return $profile;
+ }
}
class BlogPlugin extends MicroAppPlugin
{
+
+ var $oldSaveNew = true;
+
/**
* Database schema setup
*
const VERSION = '0.1';
const IMPORTDELICIOUS = 'BookmarkPlugin:IMPORTDELICIOUS';
+ var $oldSaveNew = true;
+
/**
* Authorization for importing delicious bookmarks
*
class GNUsocialPhotoPlugin extends MicroAppPlugin
{
+ var $oldSaveNew = true;
+
function onCheckSchema()
{
$schema = Schema::get();
class GNUsocialVideoPlugin extends MicroAppPlugin
{
+ var $oldSaveNew = true;
+
function onCheckSchema()
{
$schema = Schema::get();
{
list($mentions, $groups) = Ostatus_profile::filterAttention($actor, $attention_uris);
}
+
+ // FIXME: Maybe this shouldn't be so authoritative that it breaks other remote profile lookups?
+ static public function onCheckActivityAuthorship(Activity $activity, Profile &$profile)
+ {
+ try {
+ $oprofile = Ostatus_profile::getFromProfile($profile);
+ $oprofile = $oprofile->checkAuthorship($activity);
+ $profile = $oprofile->localProfile();
+ } catch (Exception $e) {
+ common_log(LOG_ERR, 'Could not get a profile or check authorship ('.get_class($e).': "'.$e->getMessage().'")');
+ $profile = null;
+ return false;
+ }
+ return true;
+ }
}
// The "WithProfile" events were added later.
- if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this, &$notice)) &&
+ if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this->localProfile(), &$notice)) &&
Event::handle('StartHandleFeedEntry', array($activity))) {
switch ($activity->verb) {
{
$notice = null;
- $oprofile = $this->checkAuthorship($activity);
-
- if (!$oprofile instanceof Ostatus_profile) {
- common_log(LOG_INFO, "No author matched share activity");
+ try {
+ $profile = ActivityUtils::checkAuthorship($activity, $this->localProfile());
+ } catch (ServerException $e) {
return null;
}
if ($activity->context) {
// TODO: context->attention
list($options['groups'], $options['replies'])
- = self::filterAttention($oprofile->localProfile(), $activity->context->attention);
+ = self::filterAttention($profile, $activity->context->attention);
// Maintain direct reply associations
// @todo FIXME: What about conversation ID?
$options['urls'][] = $href;
}
- $notice = Notice::saveNew($oprofile->profile_id,
+ $notice = Notice::saveNew($profile->id,
$content,
'ostatus',
$options);
{
$notice = null;
- $oprofile = $this->checkAuthorship($activity);
-
- if (!$oprofile instanceof Ostatus_profile) {
- return null;
- }
+ $profile = $this->checkAuthorship($activity, $this->localProfile());
// It's not always an ActivityObject::NOTE, but... let's just say it is.
if ($activity->context) {
// TODO: context->attention
list($options['groups'], $options['replies'])
- = self::filterAttention($oprofile->localProfile(), $activity->context->attention);
+ = self::filterAttention($profile, $activity->context->attention);
// Maintain direct reply associations
// @todo FIXME: What about conversation ID?
}
try {
- $saved = Notice::saveNew($oprofile->profile_id,
+ $saved = Notice::saveNew($profile->id,
$content,
'ostatus',
$options);
return null;
}
- // Is it a known Ostatus profile?
- $oprofile = Ostatus_profile::getKV('profile_id', $profile->id);
- if ($oprofile instanceof Ostatus_profile) {
+ try {
+ $oprofile = self::getFromProfile($profile);
+ // We found the profile, return it!
return $oprofile;
- }
-
- // Is it a local user?
- $user = User::getKV('id', $profile->id);
- if ($user instanceof User) {
- // @todo i18n FIXME: use sprintf and add i18n (?)
- throw new OStatusShadowException($profile, "'$profile_url' is the profile for local user '{$user->nickname}'.");
+ } catch (NoResultException $e) {
+ // Could not find an OStatus profile, is it instead a local user?
+ $user = User::getKV('id', $profile->id);
+ if ($user instanceof User) {
+ // @todo i18n FIXME: use sprintf and add i18n (?)
+ throw new OStatusShadowException($profile, "'$profile_url' is the profile for local user '{$user->nickname}'.");
+ }
}
// Continue discovery; it's a remote profile
return null;
}
+ static function getFromProfile(Profile $profile)
+ {
+ $oprofile = new Ostatus_profile();
+ $oprofile->profile_id = $profile->id;
+ if (!$oprofile->find(true)) {
+ throw new NoResultException($oprofile);
+ }
+ return $oprofile;
+ }
+
/**
* Look up and if necessary create an Ostatus_profile for remote entity
* with the given update feed. This should never return null -- you will
return $oprofile;
}
- function checkAuthorship($activity)
+ public function checkAuthorship(Activity $activity)
{
if ($this->isGroup() || $this->isPeopletag()) {
// A group or propletag feed will contain posts from multiple authors.
$oprofile = $this;
}
- return $oprofile;
+ return $oprofile->localProfile();
}
}
const POLL_OBJECT = 'http://activityschema.org/object/poll';
const POLL_RESPONSE_OBJECT = 'http://activityschema.org/object/poll-response';
+ var $oldSaveNew = true;
+
/**
* Database schema setup
*
*/
class QnAPlugin extends MicroAppPlugin
{
+
+ var $oldSaveNew = true;
+
/**
* Set up our tables (question and answer)
*