X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Factivityhandlerplugin.php;h=b105bf21f23493c7111815de35207072efb93f4a;hb=e6a342b2a2edfcc9f276e172170fc0b3eb07b61d;hp=6e9e23422edbd2d7229d9edc75626d43dda1d27a;hpb=38bea345620738f0095b9d7f8fc6e2fe1774116a;p=quix0rs-gnu-social.git diff --git a/lib/activityhandlerplugin.php b/lib/activityhandlerplugin.php index 6e9e23422e..b105bf21f2 100644 --- a/lib/activityhandlerplugin.php +++ b/lib/activityhandlerplugin.php @@ -31,6 +31,15 @@ if (!defined('GNUSOCIAL')) { exit(1); } */ abstract class ActivityHandlerPlugin extends Plugin { + /** + * Returns a key string which represents this activity in HTML classes, + * ids etc, as when offering selection of what type of post to make. + * In MicroAppPlugin, this is paired with the user-visible localizable appTitle(). + * + * @return string (compatible with HTML classes) + */ + abstract function tag(); + /** * Return a list of ActivityStreams object type IRIs * which this micro-app handles. Default implementations @@ -40,8 +49,6 @@ abstract class ActivityHandlerPlugin extends Plugin * * An empty list means any type is ok. (Favorite verb etc.) * - * All micro-app classes must override this method. - * * @return array of strings */ abstract function types(); @@ -57,7 +64,7 @@ abstract class ActivityHandlerPlugin extends Plugin * * @return array of strings */ - function verbs() { + public function verbs() { return array(ActivityVerb::POST); } @@ -109,19 +116,9 @@ abstract class ActivityHandlerPlugin extends Plugin * 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 + * (which instead turns to saveObjectFromActivity). * * @param Activity $activity * @param Profile $actor @@ -129,7 +126,68 @@ abstract class ActivityHandlerPlugin extends Plugin * * @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 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 + */ + protected 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. + */ + 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 @@ -165,6 +223,11 @@ abstract class ActivityHandlerPlugin extends Plugin */ abstract function deleteRelated(Notice $notice); + protected function notifyMentioned(Notice $stored, array &$mentioned_ids) + { + // pass through silently by default + } + /** * Called when generating Atom XML ActivityStreams output from an * ActivityObject belonging to this plugin. Gives the plugin @@ -213,11 +276,28 @@ abstract class ActivityHandlerPlugin extends Plugin */ function onNoticeDeleteRelated(Notice $notice) { - if (!$this->isMyNotice($notice)) { + if ($this->isMyNotice($notice)) { + $this->deleteRelated($notice); + } + + // Always continue this event in our activity handling plugins. + return true; + } + + /** + * @param Notice $stored The notice being distributed + * @param array &$mentioned_ids List of profiles (from $stored->getReplies()) + */ + public function onStartNotifyMentioned(Notice $stored, array &$mentioned_ids) + { + if (!$this->isMyNotice($stored)) { return true; } - $this->deleteRelated($notice); + $this->notifyMentioned($stored, $mentioned_ids); + + // If it was _our_ notice, only we should do anything with the mentions. + return false; } /** @@ -234,7 +314,11 @@ abstract class ActivityHandlerPlugin extends Plugin return true; } - $object = $this->activityObjectFromNotice($notice); + try { + $object = $this->activityObjectFromNotice($notice); + } catch (NoResultException $e) { + $object = null; // because getKV returns null on failure + } return false; } @@ -242,22 +326,18 @@ abstract class ActivityHandlerPlugin extends Plugin * 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]; @@ -266,8 +346,11 @@ abstract class ActivityHandlerPlugin extends Plugin 'is_local' => Notice::REMOTE, 'source' => 'ostatus'); - // $actor is an ostatus_profile - $notice = $this->saveNoticeFromActivity($activity, $actor->localProfile(), $options); + if (!isset($this->oldSaveNew)) { + $notice = Notice::saveActivity($activity, $profile, $options); + } else { + $notice = $this->saveNoticeFromActivity($activity, $profile, $options); + } return false; } @@ -289,22 +372,27 @@ abstract class ActivityHandlerPlugin extends Plugin $this->log(LOG_INFO, "Checking {$activity->id} as a valid Salmon slap."); - if ($target instanceof User_group) { + if ($target instanceof User_group || $target->isGroup()) { $uri = $target->getUri(); if (!array_key_exists($uri, $activity->context->attention)) { // @todo FIXME: please document (i18n). // TRANS: Client exception thrown when ... throw new ClientException(_('Object not posted to this group.')); } - } else if ($target instanceof User) { - $uri = $target->uri; + } elseif ($target instanceof Profile && $target->isLocal()) { $original = null; + // FIXME: Shouldn't favorites show up with a 'target' activityobject? + if (!ActivityUtils::compareTypes($activity->verb, array(ActivityVerb::POST)) && isset($activity->objects[0])) { + // If this is not a post, it's a verb targeted at something (such as a Favorite attached to a note) + if (!empty($activity->objects[0]->id)) { + $activity->context->replyToID = $activity->objects[0]->id; + } + } if (!empty($activity->context->replyToID)) { $original = Notice::getKV('uri', $activity->context->replyToID); } - if (!array_key_exists($uri, $activity->context->attention) && - (empty($original) || - $original->profile_id != $target->id)) { + if ((!$original instanceof Notice || $original->profile_id != $target->id) + && !array_key_exists($target->getUri(), $activity->context->attention)) { // @todo FIXME: Please document (i18n). // TRANS: Client exception when ... throw new ClientException(_('Object not posted to this user.')); @@ -314,17 +402,26 @@ abstract class ActivityHandlerPlugin extends Plugin throw new ServerException(_('Do not know how to handle this kind of target.')); } - $actor = Ostatus_profile::ensureActivityObjectProfile($activity->actor); + $oactor = Ostatus_profile::ensureActivityObjectProfile($activity->actor); + $actor = $oactor->localProfile(); - $object = $activity->objects[0]; + // FIXME: will this work in all cases? I made it work for Favorite... + if (ActivityUtils::compareTypes($activity->verb, array(ActivityVerb::POST))) { + $object = $activity->objects[0]; + } else { + $object = $activity; + } $options = array('uri' => $object->id, 'url' => $object->link, 'is_local' => Notice::REMOTE, 'source' => 'ostatus'); - // $actor is an ostatus_profile - $this->saveNoticeFromActivity($activity, $actor->localProfile(), $options); + if (!isset($this->oldSaveNew)) { + $notice = Notice::saveActivity($activity, $actor, $options); + } else { + $notice = $this->saveNoticeFromActivity($activity, $actor, $options); + } return false; } @@ -428,4 +525,88 @@ abstract class ActivityHandlerPlugin extends Plugin } return true; } + + public function onStartOpenNoticeListItemElement(NoticeListItem $nli) + { + if (!$this->isMyNotice($nli->notice)) { + return true; + } + + $this->openNoticeListItemElement($nli); + + Event::handle('EndOpenNoticeListItemElement', array($nli)); + return false; + } + + public function onStartCloseNoticeListItemElement(NoticeListItem $nli) + { + if (!$this->isMyNotice($nli->notice)) { + return true; + } + + $this->closeNoticeListItemElement($nli); + + Event::handle('EndCloseNoticeListItemElement', array($nli)); + return false; + } + + protected function openNoticeListItemElement(NoticeListItem $nli) + { + $id = (empty($nli->repeat)) ? $nli->notice->id : $nli->repeat->id; + $class = 'h-entry notice ' . $this->tag(); + if ($nli->notice->scope != 0 && $nli->notice->scope != 1) { + $class .= ' limited-scope'; + } + $nli->out->elementStart('li', array('class' => $class, + 'id' => 'notice-' . $id)); + } + + protected function closeNoticeListItemElement(NoticeListItem $nli) + { + $nli->out->elementEnd('li'); + } + + + // FIXME: This is overriden in MicroAppPlugin but shouldn't have to be + public function onStartShowNoticeItem(NoticeListItem $nli) + { + if (!$this->isMyNotice($nli->notice)) { + return true; + } + + try { + $this->showNoticeListItem($nli); + } catch (Exception $e) { + $nli->out->element('p', 'error', 'Error showing notice: '.htmlspecialchars($e->getMessage())); + } + + Event::handle('EndShowNoticeItem', array($nli)); + return false; + } + + protected function showNoticeListItem(NoticeListItem $nli) + { + $nli->showNotice(); + $nli->showNoticeAttachments(); + $nli->showNoticeInfo(); + $nli->showNoticeOptions(); + + $nli->showNoticeLink(); + $nli->showNoticeSource(); + $nli->showNoticeLocation(); + $nli->showContext(); + $nli->showRepeat(); + + $nli->showNoticeOptions(); + } + + public function onStartShowNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null) + { + if (!$this->isMyNotice($stored)) { + return true; + } + + $out->text($stored->getContent()); + return false; + } }