* and any additional data structures you require.
*
* This function is deprecated and in the future, Notice::saveActivity
- * should be called from onStartHandleFeedEntryWithProfile in this class.
+ * should be called from onStartHandleFeedEntryWithProfile in this class
+ * (which instead turns to saveObjectFromActivity).
*
* @param Activity $activity
* @param Profile $actor
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).
+ // override this function until they are migrated (this function will
+ // be deleted when all plugins are migrated to saveObjectFromActivity).
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);
}
+ /**
+ * Given a parsed ActivityStreams activity, your plugin gets
+ * to figure out itself how to store the additional data into
+ * the database, besides the base data stored by the core.
+ *
+ * This will handle just about all events where an activity
+ * object gets saved, whether it is 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 an
+ * asActivity() call on the stored object. 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?
+ *
+ * @param Activity $activity
+ * @param Profile $actor
+ * @param array $options=array()
+ *
+ * @return Notice the resulting notice
+ */
+ public function saveObjectFromActivity(Activity $activity, Notice $stored, array $options=array())
+ {
+ throw new ServerException('This function should be abstract when all plugins have migrated to saveObjectFromActivity');
+ }
+
/*
* 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.
return true;
}
- $object = $this->activityObjectFromNotice($notice);
+ try {
+ $object = $this->activityObjectFromNotice($notice);
+ } catch (NoResultException $e) {
+ $object = null; // because getKV returns null on failure
+ }
return false;
}
{
}
+ // FIXME: Set this to abstract public when all plugins have migrated!
+ public function saveObjectFromActivity(Activity $activity, Notice $stored, array $options=array())
+ {
+ assert($this->isMyActivity($act));
+ $actor = $stored->getProfile();
+ $uris = array();
+ if (count($act->objects) != 1) {
+ // TRANS: Exception thrown when a favor activity has anything but 1 object
+ throw new ClientException(_('Favoring activites can only be done one at a time'));
+ }
+
+ $obj = $act->objects[0];
+ $type = isset($obj->type) ? ActivityUtils::resolveUri($obj->type, true) : ActivityObject::NOTE;
+ $uris = $obj->getIdentifiers();
+ try {
+ $local = ActivityUtils::findLocalObject($uris, $type);
+ } catch (Exception $e) {
+ // TODO: if it's not available locally, we should import the favorited object!
+ common_debug('Could not find favored notice locally: '.var_export($uris,true));
+ return null;
+ }
+
+ if (!empty($act->time)) {
+ // This should reasonably mean that it was created on our instance.
+ $options['created'] = common_sql_date($act->time);
+ }
+
+ $options['uri'] = !empty($act->id) ? $act->id : $act->selfLink;
+ $object = Fave::saveNew($actor, $local, $type, $options);
+ return $object;
+ }
+
+
public function activityObjectFromNotice(Notice $notice)
{
+ $fave = Fave::fromStored($notice);
+ return $fave->asActivityObject();
}
public function deleteRelated(Notice $notice)
{
+ try {
+ $fave = Fave::fromStored($notice);
+ $fave->delete();
+ } catch (NoResultException $e) {
+ // Cool, no problem. We wanted to get rid of it anyway.
+ }
}
// API stuff
{
parent::onNoticeDeleteRelated($notice);
- // The below algorithm is because we have faves not stored as
- // proper activities in Notice from legacy versions of SN/GNU social
+ // The below algorithm is because we want to delete fave
+ // activities on any notice which _has_ faves, and not as
+ // in the parent function only ones that _are_ faves.
$fave = new Fave();
$fave->notice_id = $notice->id;
if ($fave->find()) {
while ($fave->fetch()) {
- Fave::blowCacheForProfileId($fave->user_id);
$fave->delete();
}
}
/**
* Table Definition for fave
*/
-require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Fave extends Managed_DataObject
{
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
public $__table = 'fave'; // table name
public $notice_id; // int(4) primary_key not_null
public $user_id; // int(4) primary_key not_null
public $uri; // varchar(255)
+ public $created; // datetime multiple_key not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
public static function schemaDef()
{
return array(
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the favorite'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who likes this notice'),
'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
'primary key' => array('notice_id', 'user_id'),
$fave->user_id = $profile->id;
$fave->notice_id = $notice->id;
+ $fave->created = common_sql_now();
$fave->modified = common_sql_now();
- $fave->uri = self::newURI($fave->user_id,
- $fave->notice_id,
- $fave->modified);
- if (!$fave->insert()) {
+ $fave->uri = self::newURI($profile,
+ $notice,
+ $fave->created);
+
+ try {
+ $fave->insert();
+ } catch (ServerException $e) {
common_log_db_error($fave, 'INSERT', __FILE__);
return false;
}
return $fave;
}
- function delete($useWhere=false)
+ // exception throwing takeover!
+ public function insert() {
+ if (!parent::insert()) {
+ throw new ServerException(sprintf(_m('Could not store new object of type %s'), get_called_class()));
+ }
+ self::blowCacheForProfileId($this->user_id);
+ self::blowCacheForNoticeId($this->notice_id);
+ return $this;
+ }
+
+ public function delete($useWhere=false)
{
$profile = Profile::getKV('id', $this->user_id);
$notice = Notice::getKV('id', $this->notice_id);
return $cnt;
}
- function getURI()
- {
- if (!empty($this->uri)) {
- return $this->uri;
- } else {
- return self::newURI($this->user_id, $this->notice_id, $this->modified);
- }
- }
-
- static function newURI($profile_id, $notice_id, $modified)
- {
- return TagURI::mint('favor:%d:%d:%s',
- $profile_id,
- $notice_id,
- common_date_iso8601($modified));
- }
-
-
static protected $_faves = array();
/**
$cache->delete(Cache::key('fave:list-ids:notice_id:'.$notice_id));
}
}
+
+ // Remember that we want the _activity_ notice here, not faves applied
+ // to the supplied Notice (as with byNotice)!
+ static public function fromStored(Notice $stored) {
+ $class = get_called_class();
+ $object = new $class;
+ $object->uri = $stored->uri;
+ if (!$object->find(true)) {
+ throw new NoResultException($object);
+ }
+ return $object;
+ }
+
+ static public function verbToTitle($verb) {
+ return ucfirst($verb);
+ }
+
+ static public function object_type()
+ {
+ return 'activity';
+ }
+
+ public function asActivityObject(Profile $scoped=null) {
+ $actobj = new ActivityObject();
+ $actobj->id = $this->getUri();
+ $actobj->type = ActivityUtils::resolveUri(ActivityObject::ACTIVITY);
+ $actobj->actor = $this->getActorObject();
+ $actobj->objects = array(clone($actobj->target));
+ $actobj->title = Stored_ActivityVerb::verbToTitle($this->verb);
+ //$actobj->verb = $this->verb;
+ //$actobj->target = $this->getTargetObject();
+ return $actobj;
+ }
+
+ static public function parseActivityObject(ActivityObject $actobj, Notice $stored) {
+ $actor = $stored->getProfile();
+ $object = new Fave();
+ $object->user_id = $actor->id;
+ $object->notice_id = $stored->id;
+ $object->object_uri = $stored->uri;
+ $object->created = $stored->created;
+ return $object;
+ }
+
+ static function saveActivityObject(ActivityObject $actobj, Notice $stored) {
+ $object = self::parseActivityObject($actobj, $stored);
+ $object->insert(); // exception throwing!
+ return $object;
+ }
+
+
+ public function getTarget() {
+ // throws exception on failure
+ return ActivityUtils::findLocalObject(array($this->uri), $this->type);
+ }
+
+ public function getTargetObject() {
+ return $this->getTarget()->asActivityObject();
+ }
+
+ protected $_stored = array();
+
+ public function getStored() {
+ if (!isset($this->_stored[$this->uri])) {
+ $stored = new Notice();
+ $stored->uri = $this->uri;
+ if (!$stored->find(true)) {
+ throw new NoResultException($stored);
+ }
+ $this->_stored[$this->uri] = $stored;
+ }
+ return $this->_stored[$this->uri];
+ }
+
+ public function getActor() {
+ $profile = new Profile();
+ $profile->id = $this->user_id;
+ if (!$profile->find(true)) {
+ throw new NoResultException($profile);
+ }
+ return $profile;
+ }
+
+ public function getActorObject() {
+ return $this->getActor()->asActivityObject();
+ }
+
+ public function getURI()
+ {
+ if (!empty($this->uri)) {
+ return $this->uri;
+ }
+
+ // We (should've in this case) created it ourselves, so we tag it ourselves
+ return self::newURI($this->getActor(), $this->getTarget(), $this->created);
+ }
+
+ static function newURI(Profile $actor, Managed_DataObject $target, $created=null)
+ {
+ if (is_null($created)) {
+ $created = common_sql_now();
+ }
+ return TagURI::mint(strtolower(get_called_class()).':%d:%s:%d:%s',
+ $actor->id,
+ ActivityUtils::resolveUri(self::object_type(), true),
+ $target->id,
+ common_date_iso8601($created));
+ }
}