]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch 'activityhooks' into 0.9.x
authorEvan Prodromou <evan@status.net>
Tue, 3 Aug 2010 23:01:18 +0000 (16:01 -0700)
committerEvan Prodromou <evan@status.net>
Tue, 3 Aug 2010 23:01:18 +0000 (16:01 -0700)
Conflicts:
classes/Notice.php

1  2 
classes/Notice.php
classes/Profile.php
plugins/OStatus/OStatusPlugin.php

diff --combined classes/Notice.php
index 399879e7911c51c8e5f24b417bfb178d54348b7b,b849225fdb6af58fed4bbc625f8d586ba1fc8221..20c9c951815cf685cfdd1d50d3d0b877ce1ca99b
@@@ -93,9 -93,7 +93,9 @@@ class Notice extends Memcached_DataObje
          $profile = Profile::staticGet('id', $this->profile_id);
  
          if (empty($profile)) {
 -            throw new ServerException(sprintf(_('No such profile (%d) for notice (%d)'), $this->profile_id, $this->id));
 +            // TRANS: Server exception thrown when a user profile for a notice cannot be found.
 +            // TRANS: %1$d is a profile ID (number), %2$d is a notice ID (number).
 +            throw new ServerException(sprintf(_('No such profile (%1$d) for notice (%2$d).'), $this->profile_id, $this->id));
          }
  
          return $profile;
          $final = common_shorten_links($content);
  
          if (Notice::contentTooLong($final)) {
 +            // TRANS: Client exception thrown if a notice contains too many characters.
              throw new ClientException(_('Problem saving notice. Too long.'));
          }
  
          if (empty($profile)) {
 +            // TRANS: Client exception thrown when trying to save a notice for an unknown user.
              throw new ClientException(_('Problem saving notice. Unknown user.'));
          }
  
          if (common_config('throttle', 'enabled') && !Notice::checkEditThrottle($profile_id)) {
              common_log(LOG_WARNING, 'Excessive posting by profile #' . $profile_id . '; throttled.');
 +            // TRANS: Client exception thrown when a user tries to post too many notices in a given time frame.
              throw new ClientException(_('Too many notices too fast; take a breather '.
                                          'and post again in a few minutes.'));
          }
  
          if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) {
              common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
 +            // TRANS: Client exception thrown when a user tries to post too many duplicate notices in a given time frame.
              throw new ClientException(_('Too many duplicate messages too quickly;'.
                                          ' take a breather and post again in a few minutes.'));
          }
  
          if (!$profile->hasRight(Right::NEWNOTICE)) {
              common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $profile->nickname);
 -            throw new ClientException(_('You are banned from posting notices on this site.'));
 +
 +            // TRANS: Client exception thrown when a user tries to post while being banned.
 +            throw new ClientException(_('You are banned from posting notices on this site.'), 403);
          }
  
          $notice = new Notice();
  
              if (!$id) {
                  common_log_db_error($notice, 'INSERT', __FILE__);
 +                // TRANS: Server exception thrown when a notice cannot be saved.
                  throw new ServerException(_('Problem saving notice.'));
              }
  
              if ($changed) {
                  if (!$notice->update($orig)) {
                      common_log_db_error($notice, 'UPDATE', __FILE__);
 +                    // TRANS: Server exception thrown when a notice cannot be updated.
                      throw new ServerException(_('Problem saving notice.'));
                  }
              }
      function saveKnownGroups($group_ids)
      {
          if (!is_array($group_ids)) {
 -            throw new ServerException("Bad type provided to saveKnownGroups");
 +            // TRANS: Server exception thrown when no array is provided to the method saveKnownGroups().
 +            throw new ServerException(_("Bad type provided to saveKnownGroups"));
          }
  
          $groups = array();
  
              if (!$result) {
                  common_log_db_error($gi, 'INSERT', __FILE__);
 +                // TRANS: Server exception thrown when an update for a group inbox fails.
                  throw new ServerException(_('Problem saving group inbox.'));
              }
  
  
                  if (!$id) {
                      common_log_db_error($reply, 'INSERT', __FILE__);
 -                    throw new ServerException("Couldn't save reply for {$this->id}, {$mentioned->id}");
 +                    // TRANS: Server exception thrown when a reply cannot be saved.
 +                    // TRANS: %1$d is a notice ID, %2$d is the ID of the mentioned user.
 +                    throw new ServerException(sprintf(_("Could not save reply for %1$d, %2$d."), $this->id, $mentioned->id));
                  } else {
                      $replied[$mentioned->id] = 1;
                      self::blow('reply:stream:%d', $mentioned->id);
          return $groups;
      }
  
+     // This has gotten way too long. Needs to be sliced up into functional bits
+     // or ideally exported to a utility class.
      function asAtomEntry($namespace=false, $source=false, $author=true, $cur=null)
      {
          $profile = $this->getProfile();
              $attrs = array();
          }
  
-         $xs->elementStart('entry', $attrs);
+         if (Event::handle('StartActivityStart', array(&$this, &$xs, &$attrs))) {
+             $xs->elementStart('entry', $attrs);
+             Event::handle('EndActivityStart', array(&$this, &$xs, &$attrs));
+         }
+         if (Event::handle('StartActivitySource', array(&$this, &$xs))) {
  
-         if ($source) {
-             $xs->elementStart('source');
-             $xs->element('id', null, $profile->profileurl);
-             $xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
-             $xs->element('link', array('href' => $profile->profileurl));
-             $user = User::staticGet('id', $profile->id);
-             if (!empty($user)) {
-                 $atom_feed = common_local_url('ApiTimelineUser',
-                                               array('format' => 'atom',
-                                                     'id' => $profile->nickname));
-                 $xs->element('link', array('rel' => 'self',
-                                            'type' => 'application/atom+xml',
-                                            'href' => $profile->profileurl));
-                 $xs->element('link', array('rel' => 'license',
-                                            'href' => common_config('license', 'url')));
+             if ($source) {
+                 $atom_feed = $profile->getAtomFeed();
+                 if (!empty($atom_feed)) {
+                     $xs->elementStart('source');
+                     // XXX: we should store the actual feed ID
+                     $xs->element('id', null, $atom_feed);
+                     // XXX: we should store the actual feed title
+                     $xs->element('title', null, $profile->getBestName());
+                     $xs->element('link', array('rel' => 'alternate',
+                                                'type' => 'text/html',
+                                                'href' => $profile->profileurl));
+                     $xs->element('link', array('rel' => 'self',
+                                                'type' => 'application/atom+xml',
+                                                'href' => $atom_feed));
+                     $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
+                     $notice = $profile->getCurrentNotice();
+                     if (!empty($notice)) {
+                         $xs->element('updated', null, self::utcDate($notice->created));
+                     }
+                     $user = User::staticGet('id', $profile->id);
+                     if (!empty($user)) {
+                         $xs->element('link', array('rel' => 'license',
+                                                    'href' => common_config('license', 'url')));
+                     }
+                     $xs->elementEnd('source');
+                 }
              }
+             Event::handle('EndActivitySource', array(&$this, &$xs));
+         }
+         $title = common_xml_safe_str($this->content);
  
-             $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
-             $xs->element('updated', null, common_date_w3dtf($this->created));
+         if (Event::handle('StartActivityTitle', array(&$this, &$xs, &$title))) {
+             $xs->element('title', null, $title);
+             Event::handle('EndActivityTitle', array($this, &$xs, $title));
          }
  
-         if ($source) {
-             $xs->elementEnd('source');
+         $atomAuthor = '';
+         if ($author) {
+             $atomAuthor = $profile->asAtomAuthor($cur);
          }
  
-         $xs->element('title', null, common_xml_safe_str($this->content));
+         if (Event::handle('StartActivityAuthor', array(&$this, &$xs, &$atomAuthor))) {
+             if (!empty($atomAuthor)) {
+                 $xs->raw($atomAuthor);
+                 Event::handle('EndActivityAuthor', array(&$this, &$xs, &$atomAuthor));
+             }
+         }
+         $actor = '';
  
          if ($author) {
-             $xs->raw($profile->asAtomAuthor($cur));
-             $xs->raw($profile->asActivityActor());
+             $actor = $profile->asActivityActor();
          }
  
-         $xs->element('link', array('rel' => 'alternate',
-                                    'type' => 'text/html',
-                                    'href' => $this->bestUrl()));
+         if (Event::handle('StartActivityActor', array(&$this, &$xs, &$actor))) {
+             if (!empty($actor)) {
+                 $xs->raw($actor);
+                 Event::handle('EndActivityActor', array(&$this, &$xs, &$actor));
+             }
+         }
  
-         $xs->element('id', null, $this->uri);
+         $url = $this->bestUrl();
  
-         $xs->element('published', null, common_date_w3dtf($this->created));
-         $xs->element('updated', null, common_date_w3dtf($this->created));
+         if (Event::handle('StartActivityLink', array(&$this, &$xs, &$url))) {
+             $xs->element('link', array('rel' => 'alternate',
+                                        'type' => 'text/html',
+                                        'href' => $url));
+             Event::handle('EndActivityLink', array(&$this, &$xs, $url));
+         }
  
-         $source = null;
+         $id = $this->uri;
  
-         $ns = $this->getSource();
+         if (Event::handle('StartActivityId', array(&$this, &$xs, &$id))) {
+             $xs->element('id', null, $id);
+             Event::handle('EndActivityId', array(&$this, &$xs, $id));
+         }
  
-         if ($ns) {
-             if (!empty($ns->name) && !empty($ns->url)) {
-                 $source = '<a href="'
-                   . htmlspecialchars($ns->url)
-                   . '" rel="nofollow">'
-                   . htmlspecialchars($ns->name)
-                    . '</a>';
-             } else {
-                 $source = $ns->code;
+         $published = self::utcDate($this->created);
+         if (Event::handle('StartActivityPublished', array(&$this, &$xs, &$published))) {
+             $xs->element('published', null, $published);
+             Event::handle('EndActivityPublished', array(&$this, &$xs, $published));
+         }
+         $updated = $published; // XXX: notices are usually immutable
+         if (Event::handle('StartActivityUpdated', array(&$this, &$xs, &$updated))) {
+             $xs->element('updated', null, $updated);
+             Event::handle('EndActivityUpdated', array(&$this, &$xs, $updated));
+         }
+         $content = common_xml_safe_str($this->rendered);
+         if (Event::handle('StartActivityContent', array(&$this, &$xs, &$content))) {
+             $xs->element('content', array('type' => 'html'), $content);
+             Event::handle('EndActivityContent', array(&$this, &$xs, $content));
+         }
+         // Most of our notices represent POSTing a NOTE. This is the default verb
+         // for activity streams, so we normally just leave it out.
+         $verb = ActivityVerb::POST;
+         if (Event::handle('StartActivityVerb', array(&$this, &$xs, &$verb))) {
+             $xs->element('activity:verb', null, $verb);
+             Event::handle('EndActivityVerb', array(&$this, &$xs, $verb));
+         }
+         // We use the default behavior for activity streams: if there's no activity:object,
+         // then treat the entry itself as the object. Here, you can set the type of that object,
+         // which is normally a NOTE.
+         $type = ActivityObject::NOTE;
+         if (Event::handle('StartActivityDefaultObjectType', array(&$this, &$xs, &$type))) {
+             $xs->element('activity:object-type', null, $type);
+             Event::handle('EndActivityDefaultObjectType', array(&$this, &$xs, $type));
+         }
+         // Since we usually use the entry itself as an object, we don't have an explicit
+         // object. Some extensions may want to add them (for photo, event, music, etc.).
+         $objects = array();
+         if (Event::handle('StartActivityObjects', array(&$this, &$xs, &$objects))) {
+             foreach ($objects as $object) {
+                 $xs->raw($object->asString());
              }
+             Event::handle('EndActivityObjects', array(&$this, &$xs, $objects));
          }
  
-         $noticeInfoAttr = array(
-             'local_id'   => $this->id, // local notice ID (useful to clients for ordering)
-             'source'     => $source,   // the client name (source attribution)
-         );
+         $noticeInfoAttr = array('local_id' => $this->id); // local notice ID (useful to clients for ordering)
  
          $ns = $this->getSource();
-         if ($ns) {
+         if (!empty($ns)) {
+             $noticeInfoAttr['source'] =  $ns->code;
              if (!empty($ns->url)) {
                  $noticeInfoAttr['source_link'] = $ns->url;
+                 if (!empty($ns->name)) {
+                     $noticeInfoAttr['source'] =  '<a href="'
+                       . htmlspecialchars($ns->url)
+                         . '" rel="nofollow">'
+                       . htmlspecialchars($ns->name)
+                         . '</a>';
+                 }
              }
          }
  
              $noticeInfoAttr['repeat_of'] = $this->repeat_of;
          }
  
-         $xs->element('statusnet:notice_info', $noticeInfoAttr, null);
+         if (Event::handle('StartActivityNoticeInfo', array(&$this, &$xs, &$noticeInfoAttr))) {
+             $xs->element('statusnet:notice_info', $noticeInfoAttr, null);
+             Event::handle('EndActivityNoticeInfo', array(&$this, &$xs, $noticeInfoAttr));
+         }
+         $replyNotice = null;
  
          if ($this->reply_to) {
-             $reply_notice = Notice::staticGet('id', $this->reply_to);
-             if (!empty($reply_notice)) {
+             $replyNotice = Notice::staticGet('id', $this->reply_to);
+         }
+         if (Event::handle('StartActivityInReplyTo', array(&$this, &$xs, &$replyNotice))) {
+             if (!empty($replyNotice)) {
                  $xs->element('link', array('rel' => 'related',
-                                            'href' => $reply_notice->bestUrl()));
+                                            'href' => $replyNotice->bestUrl()));
                  $xs->element('thr:in-reply-to',
-                              array('ref' => $reply_notice->uri,
-                                    'href' => $reply_notice->bestUrl()));
+                              array('ref' => $replyNotice->uri,
+                                    'href' => $replyNotice->bestUrl()));
+                 Event::handle('EndActivityInReplyTo', array(&$this, &$xs, $replyNotice));
              }
          }
  
-         if (!empty($this->conversation)) {
+         $conv = null;
  
+         if (!empty($this->conversation)) {
              $conv = Conversation::staticGet('id', $this->conversation);
+         }
  
+         if (Event::handle('StartActivityConversation', array(&$this, &$xs, &$conv))) {
              if (!empty($conv)) {
-                 $xs->element(
-                     'link', array(
-                         'rel' => 'ostatus:conversation',
-                         'href' => $conv->uri
-                     )
-                 );
+                 $xs->element('link', array('rel' => 'ostatus:conversation',
+                                            'href' => $conv->uri));
              }
+             Event::handle('EndActivityConversation', array(&$this, &$xs, $conv));
          }
  
+         $replyProfiles = array();
          $reply_ids = $this->getReplies();
  
          foreach ($reply_ids as $id) {
              $profile = Profile::staticGet('id', $id);
-            if (!empty($profile)) {
-                // XXX: Deprecate this for 'mentioned'
-                 $xs->element(
-                     'link', array(
-                         'rel' => 'ostatus:attention',
-                         'href' => $profile->getUri()
-                     )
-                 );
-                 $xs->element(
-                     'link', array(
-                         'rel' => 'mentioned',
-                         'href' => $profile->getUri()
-                     )
-                 );
+             if (!empty($profile)) {
+                 $replyProfiles[] = $profile;
+             }
+         }
+         if (Event::handle('StartActivityAttentionProfiles', array(&$this, &$xs, &$replyProfiles))) {
+             foreach ($replyProfiles as $profile) {
+                 $xs->element('link', array('rel' => 'ostatus:attention',
+                                            'href' => $profile->getUri()));
              }
+             Event::handle('EndActivityAttentionProfiles', array(&$this, &$xs, $replyProfiles));
          }
  
          $groups = $this->getGroups();
  
-         foreach ($groups as $group) {
-             // XXX: Deprecate this for 'mentioned'
-             $xs->element(
-                 'link', array(
-                     'rel' => 'ostatus:attention',
-                     'href' => $group->permalink()
-                 )
-             );
-             $xs->element(
-                 'link', array(
-                     'rel' => 'mentioned',
-                     'href' => $group->permalink()
-                 )
-             );
+         if (Event::handle('StartActivityAttentionGroups', array(&$this, &$xs, &$groups))) {
+             foreach ($groups as $group) {
+                 $xs->element('link', array('rel' => 'ostatus:attention',
+                                            'href' => $group->permalink()));
+             }
+             Event::handle('EndActivityAttentionGroups', array(&$this, &$xs, $groups));
          }
  
+         $repeat = null;
          if (!empty($this->repeat_of)) {
              $repeat = Notice::staticGet('id', $this->repeat_of);
+         }
+         if (Event::handle('StartActivityForward', array(&$this, &$xs, &$repeat))) {
              if (!empty($repeat)) {
-                 $xs->element(
-                     'ostatus:forward',
-                      array('ref' => $repeat->uri, 'href' => $repeat->bestUrl())
-                 );
+                 $xs->element('ostatus:forward',
+                              array('ref' => $repeat->uri,
+                                    'href' => $repeat->bestUrl()));
              }
+             Event::handle('EndActivityForward', array(&$this, &$xs, $repeat));
          }
  
-         $xs->element(
-             'content',
-             array('type' => 'html'),
-             common_xml_safe_str($this->rendered)
-         );
+         $tags = $this->getTags();
  
-         $tag = new Notice_tag();
-         $tag->notice_id = $this->id;
-         if ($tag->find()) {
-             while ($tag->fetch()) {
-                 $xs->element('category', array('term' => $tag->tag));
+         if (Event::handle('StartActivityCategories', array(&$this, &$xs, &$tags))) {
+             foreach ($tags as $tag) {
+                 $xs->element('category', array('term' => $tag));
              }
+             Event::handle('EndActivityCategories', array(&$this, &$xs, $tags));
          }
-         $tag->free();
  
-         # Enclosures
+         // Enclosures
+         $enclosures = array();
          $attachments = $this->attachments();
-         if($attachments){
-             foreach($attachments as $attachment){
-                 $enclosure=$attachment->getEnclosure();
-                 if ($enclosure) {
-                     $attributes = array('rel'=>'enclosure','href'=>$enclosure->url,'type'=>$enclosure->mimetype,'length'=>$enclosure->size);
-                     if($enclosure->title){
-                         $attributes['title']=$enclosure->title;
-                     }
-                     $xs->element('link', $attributes, null);
+         foreach ($attachments as $attachment) {
+             $enclosure = $attachment->getEnclosure();
+             if ($enclosure) {
+                 $enclosures[] = $enclosure;
+             }
+         }
+         if (Event::handle('StartActivityEnclosures', array(&$this, &$xs, &$enclosures))) {
+             foreach ($enclosures as $enclosure) {
+                 $attributes = array('rel' => 'enclosure',
+                                     'href' => $enclosure->url,
+                                     'type' => $enclosure->mimetype,
+                                     'length' => $enclosure->size);
+                 if ($enclosure->title) {
+                     $attributes['title'] = $enclosure->title;
                  }
+                 $xs->element('link', $attributes, null);
              }
+             Event::handle('EndActivityEnclosures', array(&$this, &$xs, $enclosures));
          }
  
-         if (!empty($this->lat) && !empty($this->lon)) {
-             $xs->element('georss:point', null, $this->lat . ' ' . $this->lon);
+         $lat = $this->lat;
+         $lon = $this->lon;
+         if (Event::handle('StartActivityGeo', array(&$this, &$xs, &$lat, &$lon))) {
+             if (!empty($lat) && !empty($lon)) {
+                 $xs->element('georss:point', null, $lat . ' ' . $lon);
+             }
+             Event::handle('EndActivityGeo', array(&$this, &$xs, $lat, $lon));
          }
  
-         $xs->elementEnd('entry');
+         if (Event::handle('StartActivityEnd', array(&$this, &$xs))) {
+             $xs->elementEnd('entry');
+             Event::handle('EndActivityEnd', array(&$this, &$xs));
+         }
  
          return $xs->getString();
      }
                  $this->is_local == Notice::LOCAL_NONPUBLIC);
      }
  
+     public function getTags()
+     {
+         $tags = array();
+         $tag = new Notice_tag();
+         $tag->notice_id = $this->id;
+         if ($tag->find()) {
+             while ($tag->fetch()) {
+                 $tags[] = $tag->tag;
+             }
+         }
+         $tag->free();
+         return $tags;
+     }
+     static private function utcDate($dt)
+     {
+         $dateStr = date('d F Y H:i:s', strtotime($dt));
+         $d = new DateTime($dateStr, new DateTimeZone('UTC'));
+         return $d->format(DATE_W3C);
+     }
  }
diff --combined classes/Profile.php
index 3b1e54c4d2b4c3d2086aa7b8ff80dbc042700859,abd6eb0315aa67df7e0a201928e17132c9b84537..0d0463b730564179e7f890921fa3da24844394db
@@@ -152,17 -152,16 +152,16 @@@ class Profile extends Memcached_DataObj
       *
       * @return mixed Notice or null
       */
      function getCurrentNotice()
      {
-         $notice = new Notice();
-         $notice->profile_id = $this->id;
-         // @fixme change this to sort on notice.id only when indexes are updated
-         $notice->orderBy('created DESC, notice.id DESC');
-         $notice->limit(1);
-         if ($notice->find(true)) {
+         $notice = $this->getNotices(0, 1);
+         if ($notice->fetch()) {
              return $notice;
+         } else {
+             return null;
          }
-         return null;
      }
  
      function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
                                              'role' => $name));
  
          if (empty($role)) {
 -            throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; does not exist.');
 +            // TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist.
 +            // TRANS: %1$s is the role name, %2$s is the user ID (number).
 +            throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),$name, $this->id));
          }
  
          $result = $role->delete();
  
          if (!$result) {
              common_log_db_error($role, 'DELETE', __FILE__);
 -            throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; database error.');
 +            // TRANS: Exception thrown when trying to revoke a role for a user with a failing database query.
 +            // TRANS: %1$s is the role name, %2$s is the user ID (number).
 +            throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; database error.'),$name, $this->id));
          }
  
          return true;
  
          return $result;
      }
+     function getAtomFeed()
+     {
+         $feed = null;
+         if (Event::handle('StartProfileGetAtomFeed', array($this, &$feed))) {
+             $user = User::staticGet('id', $this->id);
+             if (!empty($user)) {
+                 $feed = common_local_url('ApiTimelineUser', array('id' => $user->id,
+                                                                   'format' => 'atom'));
+             }
+             Event::handle('EndProfileGetAtomFeed', array($this, $feed));
+         }
+         return $feed;
+     }
  }
index c735c02db35443fac34f0a490b1df47c2565d217,4fc9d4108820f4807915c6f5b60690252a45a8b5..70971c5b34dab4e29afe5f37320f3a880e4d5d36
@@@ -158,9 -158,6 +158,9 @@@ class OStatusPlugin extends Plugi
  
              // Also, we'll add in the salmon link
              $salmon = common_local_url($salmonAction, array('id' => $id));
 +            $feed->addLink($salmon, array('rel' => Salmon::REL_SALMON));
 +
 +            // XXX: these are deprecated
              $feed->addLink($salmon, array('rel' => Salmon::NS_REPLIES));
              $feed->addLink($salmon, array('rel' => Salmon::NS_MENTIONS));
          }
          }
          return false;
      }
+     public function onStartProfileGetAtomFeed($profile, &$feed)
+     {
+         $oprofile = Ostatus_profile::staticGet('profile_id', $profile->id);
+         if (empty($oprofile)) {
+             return true;
+         }
+         $feed = $oprofile->feeduri;
+         return false;
+     }
  }