Merge branch '1.0.x' of gitorious.org:statusnet/mainline into 1.0.x
This commit is contained in:
@@ -135,6 +135,9 @@ class Activity
|
||||
} else if ($entry->namespaceURI == Activity::RSS &&
|
||||
$entry->localName == 'item') {
|
||||
$this->_fromRssItem($entry, $feed);
|
||||
} else if ($entry->namespaceURI == Activity::SPEC &&
|
||||
$entry->localName == 'object') {
|
||||
$this->_fromAtomEntry($entry, $feed);
|
||||
} else {
|
||||
// Low level exception. No need for i18n.
|
||||
throw new Exception("Unknown DOM element: {$entry->namespaceURI} {$entry->localName}");
|
||||
@@ -168,14 +171,22 @@ class Activity
|
||||
// XXX: do other implied stuff here
|
||||
}
|
||||
|
||||
$objectEls = $entry->getElementsByTagNameNS(self::SPEC, self::OBJECT);
|
||||
// get immediate object children
|
||||
|
||||
if ($objectEls->length > 0) {
|
||||
for ($i = 0; $i < $objectEls->length; $i++) {
|
||||
$objectEl = $objectEls->item($i);
|
||||
$this->objects[] = new ActivityObject($objectEl);
|
||||
$objectEls = ActivityUtils::children($entry, self::OBJECT, self::SPEC);
|
||||
|
||||
if (count($objectEls) > 0) {
|
||||
foreach ($objectEls as $objectEl) {
|
||||
// Special case for embedded activities
|
||||
$objectType = ActivityUtils::childContent($objectEl, self::OBJECTTYPE, self::SPEC);
|
||||
if (!empty($objectType) && $objectType == ActivityObject::ACTIVITY) {
|
||||
$this->objects[] = new Activity($objectEl);
|
||||
} else {
|
||||
$this->objects[] = new ActivityObject($objectEl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// XXX: really?
|
||||
$this->objects[] = new ActivityObject($entry);
|
||||
}
|
||||
|
||||
@@ -431,7 +442,13 @@ class Activity
|
||||
} else {
|
||||
$activity['object'] = array();
|
||||
foreach($this->objects as $object) {
|
||||
$activity['object'][] = $object->asArray();
|
||||
$oa = $object->asArray();
|
||||
if ($object instanceof Activity) {
|
||||
// throw in a type
|
||||
// XXX: hackety-hack
|
||||
$oa['objectType'] = 'activity';
|
||||
}
|
||||
$activity['object'][] = $oa;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +512,7 @@ class Activity
|
||||
return $xs->getString();
|
||||
}
|
||||
|
||||
function outputTo($xs, $namespace=false, $author=true, $source=false)
|
||||
function outputTo($xs, $namespace=false, $author=true, $source=false, $tag='entry')
|
||||
{
|
||||
if ($namespace) {
|
||||
$attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||
@@ -510,9 +527,13 @@ class Activity
|
||||
$attrs = array();
|
||||
}
|
||||
|
||||
$xs->elementStart('entry', $attrs);
|
||||
$xs->elementStart($tag, $attrs);
|
||||
|
||||
if ($this->verb == ActivityVerb::POST && count($this->objects) == 1) {
|
||||
if ($tag != 'entry') {
|
||||
$xs->element('activity:object-type', null, ActivityObject::ACTIVITY);
|
||||
}
|
||||
|
||||
if ($this->verb == ActivityVerb::POST && count($this->objects) == 1 && $tag == 'entry') {
|
||||
|
||||
$obj = $this->objects[0];
|
||||
$obj->outputTo($xs, null);
|
||||
@@ -558,9 +579,13 @@ class Activity
|
||||
$this->actor->outputTo($xs, 'activity:actor');
|
||||
}
|
||||
|
||||
if ($this->verb != ActivityVerb::POST || count($this->objects) != 1) {
|
||||
if ($this->verb != ActivityVerb::POST || count($this->objects) != 1 || $tag != 'entry') {
|
||||
foreach($this->objects as $object) {
|
||||
$object->outputTo($xs, 'activity:object');
|
||||
if ($object instanceof Activity) {
|
||||
$object->outputTo($xs, false, true, true, 'activity:object');
|
||||
} else {
|
||||
$object->outputTo($xs, 'activity:object');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,7 +719,7 @@ class Activity
|
||||
$xs->element($tag, $attrs, $content);
|
||||
}
|
||||
|
||||
$xs->elementEnd('entry');
|
||||
$xs->elementEnd($tag);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ class ActivityObject
|
||||
const PLACE = 'http://activitystrea.ms/schema/1.0/place';
|
||||
const COMMENT = 'http://activitystrea.ms/schema/1.0/comment';
|
||||
// ^^^^^^^^^^ tea!
|
||||
const ACTIVITY = 'http://activitystrea.ms/schema/1.0/activity';
|
||||
|
||||
// Atom elements we snarf
|
||||
|
||||
|
||||
@@ -145,6 +145,34 @@ class ActivityUtils
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all immediate child elements with the given tag
|
||||
*
|
||||
* @param DOMElement $element element to pick at
|
||||
* @param string $tag tag to look for
|
||||
* @param string $namespace Namespace to look under
|
||||
*
|
||||
* @return array found element or null
|
||||
*/
|
||||
|
||||
static function children(DOMNode $element, $tag, $namespace=self::ATOM)
|
||||
{
|
||||
$results = array();
|
||||
|
||||
$els = $element->childNodes;
|
||||
|
||||
if (!empty($els) && $els->length > 0) {
|
||||
for ($i = 0; $i < $els->length; $i++) {
|
||||
$el = $els->item($i);
|
||||
if ($el->localName == $tag && $el->namespaceURI == $namespace) {
|
||||
$results[] = $el;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab the text content of a DOM element child of the current element
|
||||
*
|
||||
|
||||
251
lib/atompubclient.php
Normal file
251
lib/atompubclient.php
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Client class for AtomPub
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Cache
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Client class for AtomPub
|
||||
*
|
||||
* @category General
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class AtomPubClient
|
||||
{
|
||||
public $url;
|
||||
private $user, $pass;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $url collection feed URL
|
||||
* @param string $user auth username
|
||||
* @param string $pass auth password
|
||||
*/
|
||||
function __construct($url, $user, $pass)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->user = $user;
|
||||
$this->pass = $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up an HTTPClient with auth for our resource.
|
||||
*
|
||||
* @param string $method
|
||||
* @return HTTPClient
|
||||
*/
|
||||
private function httpClient($method='GET')
|
||||
{
|
||||
$client = new HTTPClient($this->url);
|
||||
$client->setMethod($method);
|
||||
$client->setAuth($this->user, $this->pass);
|
||||
return $client;
|
||||
}
|
||||
|
||||
function get()
|
||||
{
|
||||
$client = $this->httpClient('GET');
|
||||
$response = $client->send();
|
||||
if ($response->isOk()) {
|
||||
return $response->getBody();
|
||||
} else {
|
||||
throw new Exception("Bogus return code: " . $response->getStatus() . ': ' . $response->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new resource by POSTing it to the collection.
|
||||
* If successful, will return the URL representing the
|
||||
* canonical location of the new resource. Neat!
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $type defaults to Atom entry
|
||||
* @return string URL to the created resource
|
||||
*
|
||||
* @throws exceptions on failure
|
||||
*/
|
||||
function post($data, $type='application/atom+xml;type=entry')
|
||||
{
|
||||
$client = $this->httpClient('POST');
|
||||
$client->setHeader('Content-Type', $type);
|
||||
// optional Slug header not used in this case
|
||||
$client->setBody($data);
|
||||
$response = $client->send();
|
||||
|
||||
if ($response->getStatus() != '201') {
|
||||
throw new Exception("Expected HTTP 201 on POST, got " . $response->getStatus() . ': ' . $response->getBody());
|
||||
}
|
||||
$loc = $response->getHeader('Location');
|
||||
$contentLoc = $response->getHeader('Content-Location');
|
||||
|
||||
if (empty($loc)) {
|
||||
throw new Exception("AtomPub POST response missing Location header.");
|
||||
}
|
||||
if (!empty($contentLoc)) {
|
||||
if ($loc != $contentLoc) {
|
||||
throw new Exception("AtomPub POST response Location and Content-Location headers do not match.");
|
||||
}
|
||||
|
||||
// If Content-Location and Location match, that means the response
|
||||
// body is safe to interpret as the resource itself.
|
||||
if ($type == 'application/atom+xml;type=entry') {
|
||||
self::validateAtomEntry($response->getBody());
|
||||
}
|
||||
}
|
||||
|
||||
return $loc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that StatusNet currently doesn't allow PUT editing on notices.
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $type defaults to Atom entry
|
||||
* @return true on success
|
||||
*
|
||||
* @throws exceptions on failure
|
||||
*/
|
||||
function put($data, $type='application/atom+xml;type=entry')
|
||||
{
|
||||
$client = $this->httpClient('PUT');
|
||||
$client->setHeader('Content-Type', $type);
|
||||
$client->setBody($data);
|
||||
$response = $client->send();
|
||||
|
||||
if ($response->getStatus() != '200' && $response->getStatus() != '204') {
|
||||
throw new Exception("Expected HTTP 200 or 204 on PUT, got " . $response->getStatus() . ': ' . $response->getBody());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the resource.
|
||||
*
|
||||
* @return true on success
|
||||
*
|
||||
* @throws exceptions on failure
|
||||
*/
|
||||
function delete()
|
||||
{
|
||||
$client = $this->httpClient('DELETE');
|
||||
$client->setBody($data);
|
||||
$response = $client->send();
|
||||
|
||||
if ($response->getStatus() != '200' && $response->getStatus() != '204') {
|
||||
throw new Exception("Expected HTTP 200 or 204 on DELETE, got " . $response->getStatus() . ': ' . $response->getBody());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the given string is a parseable Atom entry.
|
||||
*
|
||||
* @param string $str
|
||||
* @return boolean
|
||||
* @throws Exception on invalid input
|
||||
*/
|
||||
static function validateAtomEntry($str)
|
||||
{
|
||||
if (empty($str)) {
|
||||
throw new Exception('Bad Atom entry: empty');
|
||||
}
|
||||
$dom = new DOMDocument;
|
||||
if (!$dom->loadXML($str)) {
|
||||
throw new Exception('Bad Atom entry: XML is not well formed.');
|
||||
}
|
||||
|
||||
$activity = new Activity($dom->documentRoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
static function entryEditURL($str) {
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadXML($str);
|
||||
$path = new DOMXPath($dom);
|
||||
$path->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
|
||||
|
||||
$links = $path->query('/atom:entry/atom:link[@rel="edit"]', $dom->documentRoot);
|
||||
if ($links && $links->length) {
|
||||
if ($links->length > 1) {
|
||||
throw new Exception('Bad Atom entry; has multiple rel=edit links.');
|
||||
}
|
||||
$link = $links->item(0);
|
||||
$url = $link->getAttribute('href');
|
||||
return $url;
|
||||
} else {
|
||||
throw new Exception('Atom entry lists no rel=edit link.');
|
||||
}
|
||||
}
|
||||
|
||||
static function entryId($str) {
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadXML($str);
|
||||
$path = new DOMXPath($dom);
|
||||
$path->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
|
||||
|
||||
$links = $path->query('/atom:entry/atom:id', $dom->documentRoot);
|
||||
if ($links && $links->length) {
|
||||
if ($links->length > 1) {
|
||||
throw new Exception('Bad Atom entry; has multiple id entries.');
|
||||
}
|
||||
$link = $links->item(0);
|
||||
$url = $link->textContent;
|
||||
return $url;
|
||||
} else {
|
||||
throw new Exception('Atom entry lists no id.');
|
||||
}
|
||||
}
|
||||
|
||||
static function getEntryInFeed($str, $id)
|
||||
{
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadXML($str);
|
||||
$path = new DOMXPath($dom);
|
||||
$path->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
|
||||
|
||||
$query = '/atom:feed/atom:entry[atom:id="'.$id.'"]';
|
||||
$items = $path->query($query, $dom->documentRoot);
|
||||
if ($items && $items->length) {
|
||||
return $items->item(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class AttachmentList extends Widget
|
||||
*/
|
||||
function show()
|
||||
{
|
||||
$att = File::getAttachments($this->notice->id);
|
||||
$att = $this->notice->attachments();
|
||||
if (empty($att)) return 0;
|
||||
$this->showListStart();
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ $default =
|
||||
'sslserver' => null,
|
||||
'shorturllength' => 30,
|
||||
'dupelimit' => 60, // default for same person saying the same thing
|
||||
'textlimit' => 140,
|
||||
'textlimit' => 0, // in chars; 0 == no limit
|
||||
'indent' => true,
|
||||
'use_x_sendfile' => false,
|
||||
'notice' => null, // site wide notice text
|
||||
|
||||
@@ -81,9 +81,16 @@ abstract class FilteringNoticeStream extends NoticeStream
|
||||
break;
|
||||
}
|
||||
|
||||
while ($raw->fetch()) {
|
||||
if ($this->filter($raw)) {
|
||||
$filtered[] = clone($raw);
|
||||
$notices = $raw->fetchAll();
|
||||
|
||||
// XXX: this should probably only be in the scoping one.
|
||||
|
||||
Notice::fillGroups($notices);
|
||||
Notice::fillReplies($notices);
|
||||
|
||||
foreach ($notices as $notice) {
|
||||
if ($this->filter($notice)) {
|
||||
$filtered[] = $notice;
|
||||
if (count($filtered) >= $total) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
define('STATUSNET_BASE_VERSION', '1.0.0');
|
||||
define('STATUSNET_LIFECYCLE', 'beta1'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
|
||||
define('STATUSNET_LIFECYCLE', 'beta2'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
|
||||
define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE);
|
||||
|
||||
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
||||
@@ -156,4 +156,5 @@ function PEAR_ErrorToPEAR_Exception($err)
|
||||
}
|
||||
throw new PEAR_Exception($err->getMessage());
|
||||
}
|
||||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'PEAR_ErrorToPEAR_Exception');
|
||||
|
||||
@@ -193,6 +193,7 @@ abstract class MicroAppPlugin extends Plugin
|
||||
function isMyActivity($activity) {
|
||||
$types = $this->types();
|
||||
return (count($activity->objects) == 1 &&
|
||||
($activity->objects[0] instanceof ActivityObject) &&
|
||||
in_array($activity->objects[0]->type, $types));
|
||||
}
|
||||
|
||||
@@ -345,7 +346,7 @@ abstract class MicroAppPlugin extends Plugin
|
||||
*
|
||||
* @return boolean hook value
|
||||
*/
|
||||
function onStartHandleFeedEntryWithProfile($activity, $oprofile)
|
||||
function onStartHandleFeedEntryWithProfile($activity, $oprofile, &$notice)
|
||||
{
|
||||
if ($this->isMyActivity($activity)) {
|
||||
|
||||
@@ -364,7 +365,7 @@ abstract class MicroAppPlugin extends Plugin
|
||||
'source' => 'ostatus');
|
||||
|
||||
// $actor is an ostatus_profile
|
||||
$this->saveNoticeFromActivity($activity, $actor->localProfile(), $options);
|
||||
$notice = $this->saveNoticeFromActivity($activity, $actor->localProfile(), $options);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -446,9 +447,9 @@ abstract class MicroAppPlugin extends Plugin
|
||||
$options = array('source' => 'atompub');
|
||||
|
||||
// $user->getProfile() is a Profile
|
||||
$this->saveNoticeFromActivity($activity,
|
||||
$user->getProfile(),
|
||||
$options);
|
||||
$notice = $this->saveNoticeFromActivity($activity,
|
||||
$user->getProfile(),
|
||||
$options);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -83,17 +83,16 @@ class NoticeList extends Widget
|
||||
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
|
||||
$cnt++;
|
||||
|
||||
if ($cnt > NOTICES_PER_PAGE) {
|
||||
break;
|
||||
}
|
||||
$notices = $this->notice->fetchAll();
|
||||
$total = count($notices);
|
||||
$notices = array_slice($notices, 0, NOTICES_PER_PAGE);
|
||||
|
||||
self::prefill($notices);
|
||||
|
||||
foreach ($notices as $notice) {
|
||||
|
||||
try {
|
||||
$item = $this->newListItem($this->notice);
|
||||
$item = $this->newListItem($notice);
|
||||
$item->show();
|
||||
} catch (Exception $e) {
|
||||
// we log exceptions and continue
|
||||
@@ -105,7 +104,7 @@ class NoticeList extends Widget
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
return $cnt;
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,4 +121,28 @@ class NoticeList extends Widget
|
||||
{
|
||||
return new NoticeListItem($notice, $this->out);
|
||||
}
|
||||
|
||||
static function prefill(&$notices, $avatarSize=AVATAR_STREAM_SIZE)
|
||||
{
|
||||
// Prefill attachments
|
||||
Notice::fillAttachments($notices);
|
||||
// Prefill attachments
|
||||
Notice::fillFaves($notices);
|
||||
// Prefill the profiles
|
||||
$profiles = Notice::fillProfiles($notices);
|
||||
// Prefill the avatars
|
||||
Profile::fillAvatars($profiles, $avatarSize);
|
||||
|
||||
$p = Profile::current();
|
||||
|
||||
$ids = array();
|
||||
|
||||
foreach ($notices as $notice) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
if (!empty($p)) {
|
||||
Memcached_DataObject::pivotGet('Fave', 'notice_id', $ids, array('user_id' => $p->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,17 +76,18 @@ class ThreadedNoticeList extends NoticeList
|
||||
$this->out->element('h2', null, _m('HEADER','Notices'));
|
||||
$this->out->elementStart('ol', array('class' => 'notices threaded-notices xoxo'));
|
||||
|
||||
$cnt = 0;
|
||||
$notices = $this->notice->fetchAll();
|
||||
$total = count($notices);
|
||||
$notices = array_slice($notices, 0, NOTICES_PER_PAGE);
|
||||
|
||||
self::prefill($notices);
|
||||
|
||||
$conversations = array();
|
||||
while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
|
||||
$cnt++;
|
||||
|
||||
if ($cnt > NOTICES_PER_PAGE) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($notices as $notice) {
|
||||
|
||||
// Collapse repeats into their originals...
|
||||
$notice = $this->notice;
|
||||
|
||||
if ($notice->repeat_of) {
|
||||
$orig = Notice::staticGet('id', $notice->repeat_of);
|
||||
if ($orig) {
|
||||
@@ -119,7 +120,7 @@ class ThreadedNoticeList extends NoticeList
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
return $cnt;
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,6 +224,7 @@ class ThreadedNoticeListItem extends NoticeListItem
|
||||
$item = new ThreadedNoticeListMoreItem($moreCutoff, $this->out, count($notices));
|
||||
$item->show();
|
||||
}
|
||||
NoticeList::prefill($notices, AVATAR_MINI_SIZE);
|
||||
foreach (array_reverse($notices) as $notice) {
|
||||
if (Event::handle('StartShowThreadedNoticeSub', array($this, $this->notice, $notice))) {
|
||||
$item = new ThreadedNoticeListSubItem($notice, $this->notice, $this->out);
|
||||
@@ -468,9 +470,9 @@ class ThreadedNoticeListFavesItem extends NoticeListActorsItem
|
||||
{
|
||||
function getProfiles()
|
||||
{
|
||||
$fave = Fave::byNotice($this->notice->id);
|
||||
$faves = $this->notice->getFaves();
|
||||
$profiles = array();
|
||||
while ($fave->fetch()) {
|
||||
foreach ($faves as $fave) {
|
||||
$profiles[] = $fave->user_id;
|
||||
}
|
||||
return $profiles;
|
||||
|
||||
15
lib/util.php
15
lib/util.php
@@ -1127,8 +1127,11 @@ function common_tag_link($tag)
|
||||
|
||||
function common_canonical_tag($tag)
|
||||
{
|
||||
// only alphanum
|
||||
$tag = preg_replace('/[^\pL\pN]/u', '', $tag);
|
||||
$tag = mb_convert_case($tag, MB_CASE_LOWER, "UTF-8");
|
||||
return str_replace(array('-', '_', '.'), '', $tag);
|
||||
$tag = substr($tag, 0, 64);
|
||||
return $tag;
|
||||
}
|
||||
|
||||
function common_valid_profile_tag($str)
|
||||
@@ -1501,16 +1504,18 @@ function common_enqueue_notice($notice)
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast profile updates to remote subscribers.
|
||||
* Legacy function to broadcast profile updates to OMB remote subscribers.
|
||||
*
|
||||
* XXX: This probably needs killing, but there are several bits of code
|
||||
* that broadcast profile changes that need to be dealt with. AFAIK
|
||||
* this function is only used for OMB. -z
|
||||
*
|
||||
* Since this may be slow with a lot of subscribers or bad remote sites,
|
||||
* this is run through the background queues if possible.
|
||||
*/
|
||||
function common_broadcast_profile(Profile $profile)
|
||||
{
|
||||
$qm = QueueManager::get();
|
||||
$qm->enqueue($profile, "profile");
|
||||
return true;
|
||||
Event::handle('BroadcastProfile', array($profile));
|
||||
}
|
||||
|
||||
function common_profile_url($nickname)
|
||||
|
||||
Reference in New Issue
Block a user