OStatus: save categories from the Atom entry as hashtags.

This commit is contained in:
Brion Vibber 2010-02-25 11:26:33 -08:00
parent 39a8e9d8e6
commit 79c0d52daa
4 changed files with 106 additions and 18 deletions

View File

@ -121,6 +121,9 @@ class Notice extends Memcached_DataObject
$result = parent::delete(); $result = parent::delete();
} }
/**
* Extract #hashtags from this notice's content and save them to the database.
*/
function saveTags() function saveTags()
{ {
/* extract all #hastags */ /* extract all #hastags */
@ -129,14 +132,22 @@ class Notice extends Memcached_DataObject
return true; return true;
} }
/* Add them to the database */
return $this->saveKnownTags($match[1]);
}
/**
* Record the given set of hash tags in the db for this notice.
* Given tag strings will be normalized and checked for dupes.
*/
function saveKnownTags($hashtags)
{
//turn each into their canonical tag //turn each into their canonical tag
//this is needed to remove dupes before saving e.g. #hash.tag = #hashtag //this is needed to remove dupes before saving e.g. #hash.tag = #hashtag
$hashtags = array(); for($i=0; $i<count($hashtags); $i++) {
for($i=0; $i<count($match[1]); $i++) { $hashtags[$i] = common_canonical_tag($hashtags[$i]);
$hashtags[] = common_canonical_tag($match[1][$i]);
} }
/* Add them to the database */
foreach(array_unique($hashtags) as $hashtag) { foreach(array_unique($hashtags) as $hashtag) {
/* elide characters we don't want in the tag */ /* elide characters we don't want in the tag */
$this->saveTag($hashtag); $this->saveTag($hashtag);
@ -145,6 +156,10 @@ class Notice extends Memcached_DataObject
return true; return true;
} }
/**
* Record a single hash tag as associated with this notice.
* Tag format and uniqueness must be validated by caller.
*/
function saveTag($hashtag) function saveTag($hashtag)
{ {
$tag = new Notice_tag(); $tag = new Notice_tag();
@ -194,6 +209,8 @@ class Notice extends Memcached_DataObject
* place of extracting @-replies from content. * place of extracting @-replies from content.
* array 'groups' list of group IDs to deliver to, in place of * array 'groups' list of group IDs to deliver to, in place of
* extracting ! tags from content * extracting ! tags from content
* array 'tags' list of hashtag strings to save with the notice
* in place of extracting # tags from content
* @fixme tag override * @fixme tag override
* *
* @return Notice * @return Notice
@ -343,6 +360,8 @@ class Notice extends Memcached_DataObject
$notice->blowOnInsert(); $notice->blowOnInsert();
// Save per-notice metadata...
if (isset($replies)) { if (isset($replies)) {
$notice->saveKnownReplies($replies); $notice->saveKnownReplies($replies);
} else { } else {
@ -355,6 +374,16 @@ class Notice extends Memcached_DataObject
$notice->saveGroups(); $notice->saveGroups();
} }
if (isset($tags)) {
$notice->saveKnownTags($tags);
} else {
$notice->saveTags();
}
// @fixme pass in data for URLs too?
$notice->saveUrls();
// Prepare inbox delivery, may be queued to background.
$notice->distribute(); $notice->distribute();
return $notice; return $notice;

View File

@ -859,6 +859,7 @@ class Activity
public $content; // HTML content of activity public $content; // HTML content of activity
public $id; // ID of the activity public $id; // ID of the activity
public $title; // title of the activity public $title; // title of the activity
public $categories = array(); // list of AtomCategory objects
/** /**
* Turns a regular old Atom <entry> into a magical activity * Turns a regular old Atom <entry> into a magical activity
@ -947,6 +948,14 @@ class Activity
$this->summary = ActivityUtils::childContent($entry, 'summary'); $this->summary = ActivityUtils::childContent($entry, 'summary');
$this->id = ActivityUtils::childContent($entry, 'id'); $this->id = ActivityUtils::childContent($entry, 'id');
$this->content = ActivityUtils::getContent($entry); $this->content = ActivityUtils::getContent($entry);
$catEls = $entry->getElementsByTagNameNS(self::ATOM, 'category');
if ($catEls) {
for ($i = 0; $i < $catEls->length; $i++) {
$catEl = $catEls->item($i);
$this->categories[] = new AtomCategory($catEl);
}
}
} }
/** /**
@ -1011,6 +1020,10 @@ class Activity
$xs->raw($this->target->asString('activity:target')); $xs->raw($this->target->asString('activity:target'));
} }
foreach ($this->categories as $cat) {
$xs->raw($cat->asString());
}
$xs->elementEnd('entry'); $xs->elementEnd('entry');
return $xs->getString(); return $xs->getString();
@ -1020,4 +1033,50 @@ class Activity
{ {
return ActivityUtils::child($element, $tag, $namespace); return ActivityUtils::child($element, $tag, $namespace);
} }
} }
class AtomCategory
{
public $term;
public $scheme;
public $label;
function __construct($element=null)
{
if ($element && $element->attributes) {
$this->term = $this->extract($element, 'term');
$this->scheme = $this->extract($element, 'scheme');
$this->label = $this->extract($element, 'label');
}
}
protected function extract($element, $attrib)
{
$node = $element->attributes->getNamedItemNS(Activity::ATOM, $attrib);
if ($node) {
return trim($node->textContent);
}
$node = $element->attributes->getNamedItem($attrib);
if ($node) {
return trim($node->textContent);
}
return null;
}
function asString()
{
$attribs = array();
if ($this->term !== null) {
$attribs['term'] = $this->term;
}
if ($this->scheme !== null) {
$attribs['scheme'] = $this->scheme;
}
if ($this->label !== null) {
$attribs['label'] = $this->label;
}
$xs = new XMLStringer();
$xs->element('category', $attribs);
return $xs->asString();
}
}

View File

@ -62,24 +62,12 @@ class DistribQueueHandler
{ {
// XXX: do we need to change this for remote users? // XXX: do we need to change this for remote users?
try {
$notice->saveTags();
} catch (Exception $e) {
$this->logit($notice, $e);
}
try { try {
$notice->addToInboxes(); $notice->addToInboxes();
} catch (Exception $e) { } catch (Exception $e) {
$this->logit($notice, $e); $this->logit($notice, $e);
} }
try {
$notice->saveUrls();
} catch (Exception $e) {
$this->logit($notice, $e);
}
try { try {
Event::handle('EndNoticeSave', array($notice)); Event::handle('EndNoticeSave', array($notice));
// Enqueue for other handlers // Enqueue for other handlers

View File

@ -638,7 +638,9 @@ class Ostatus_profile extends Memcached_DataObject
'uri' => $sourceUri, 'uri' => $sourceUri,
'rendered' => $rendered, 'rendered' => $rendered,
'replies' => array(), 'replies' => array(),
'groups' => array()); 'groups' => array(),
'tags' => array());
// Check for optional attributes... // Check for optional attributes...
@ -673,6 +675,16 @@ class Ostatus_profile extends Memcached_DataObject
} }
} }
// Atom categories <-> hashtags
foreach ($activity->categories as $cat) {
if ($cat->term) {
$term = common_canonical_tag($cat->term);
if ($term) {
$options['tags'][] = $term;
}
}
}
try { try {
$saved = Notice::saveNew($oprofile->profile_id, $saved = Notice::saveNew($oprofile->profile_id,
$content, $content,