From 3da8914edb81a1789d69ee6c32092959630e4e1c Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 11 Jun 2010 12:38:22 -0700 Subject: Fix for DB error reporting in installer (MySQL path) --- lib/installer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/installer.php b/lib/installer.php index 7936d5d5d..78461efb7 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -446,7 +446,7 @@ abstract class Installer case 'mysqli': $res = $conn->query($stmt); if ($res === false) { - $error = $conn->error(); + $error = $conn->error; } break; case 'pgsql': -- cgit v1.2.3-54-g00ecf From 327ed5b87e492380bc651ed03159ae7cd3a4a493 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 14 Jun 2010 15:51:49 -0400 Subject: fix URL regex for tags to use UTF-8 --- lib/router.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index f2b2b845f..fec229c9b 100644 --- a/lib/router.php +++ b/lib/router.php @@ -263,7 +263,7 @@ class Router $m->connect('tag', array('action' => 'publictagcloud')); $m->connect('tag/:tag/rss', array('action' => 'tagrss'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect('tag/:tag', array('action' => 'tag'), array('tag' => '[\pL\pN_\-\.]{1,64}')); @@ -749,12 +749,12 @@ class Router $m->connect('tag/:tag/rss', array('action' => 'userrss', 'nickname' => $nickname), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect('tag/:tag', array('action' => 'showstream', 'nickname' => $nickname), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect('rsd.xml', array('action' => 'rsd', @@ -815,12 +815,12 @@ class Router $m->connect(':nickname/tag/:tag/rss', array('action' => 'userrss'), array('nickname' => '[a-zA-Z0-9]{1,64}'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect(':nickname/tag/:tag', array('action' => 'showstream'), array('nickname' => '[a-zA-Z0-9]{1,64}'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => '[\pL\pN_\-\.]{1,64}')); $m->connect(':nickname/rsd.xml', array('action' => 'rsd'), -- cgit v1.2.3-54-g00ecf From d3d499879c4d01bde46033a3a98f9190ea18cb63 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Jun 2010 14:29:24 -0700 Subject: - More useful group info from api/statusnet/group/show - Add statusnet:group_info tag to group Atom feeds --- actions/showgroup.php | 10 +--------- classes/User_group.php | 15 +++++++++++++++ lib/apiaction.php | 40 ++++++++++++++++++++++++++-------------- lib/atomgroupnoticefeed.php | 19 +++++++++++++++++++ 4 files changed, 61 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/actions/showgroup.php b/actions/showgroup.php index 3d369e9eb..17c37e4d7 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -430,14 +430,6 @@ class ShowgroupAction extends GroupDesignAction function showStatistics() { - // XXX: WORM cache this - $members = $this->group->getMembers(); - $members_count = 0; - /** $member->count() doesn't work. */ - while ($members->fetch()) { - $members_count++; - } - $this->elementStart('div', array('id' => 'entity_statistics', 'class' => 'section')); @@ -451,7 +443,7 @@ class ShowgroupAction extends GroupDesignAction $this->elementStart('dl', 'entity_members'); $this->element('dt', null, _('Members')); - $this->element('dd', null, (is_int($members_count)) ? $members_count : '0'); + $this->element('dd', null, $this->group->getMemberCount()); $this->elementEnd('dl'); $this->elementEnd('div'); diff --git a/classes/User_group.php b/classes/User_group.php index 110f08301..e04c46626 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -154,6 +154,21 @@ class User_group extends Memcached_DataObject return $members; } + function getMemberCount() + { + // XXX: WORM cache this + + $members = $this->getMembers(); + $member_count = 0; + + /** $member->count() doesn't work. */ + while ($members->fetch()) { + $member_count++; + } + + return $member_count; + } + function getAdmins($offset=0, $limit=null) { $qry = diff --git a/lib/apiaction.php b/lib/apiaction.php index 320aa0316..7cc473d51 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -346,20 +346,32 @@ class ApiAction extends Action function twitterGroupArray($group) { - $twitter_group=array(); - $twitter_group['id']=$group->id; - $twitter_group['url']=$group->permalink(); - $twitter_group['nickname']=$group->nickname; - $twitter_group['fullname']=$group->fullname; - $twitter_group['original_logo']=$group->original_logo; - $twitter_group['homepage_logo']=$group->homepage_logo; - $twitter_group['stream_logo']=$group->stream_logo; - $twitter_group['mini_logo']=$group->mini_logo; - $twitter_group['homepage']=$group->homepage; - $twitter_group['description']=$group->description; - $twitter_group['location']=$group->location; - $twitter_group['created']=$this->dateTwitter($group->created); - $twitter_group['modified']=$this->dateTwitter($group->modified); + $twitter_group = array(); + + $twitter_group['id'] = $group->id; + $twitter_group['url'] = $group->permalink(); + $twitter_group['nickname'] = $group->nickname; + $twitter_group['fullname'] = $group->fullname; + + if (isset($this->auth_user)) { + $twitter_group['member'] = $this->auth_user->isMember($group); + $twitter_group['blocked'] = Group_block::isBlocked( + $group, + $this->auth_user->getProfile() + ); + } + + $twitter_group['member_count'] = $group->getMemberCount(); + $twitter_group['original_logo'] = $group->original_logo; + $twitter_group['homepage_logo'] = $group->homepage_logo; + $twitter_group['stream_logo'] = $group->stream_logo; + $twitter_group['mini_logo'] = $group->mini_logo; + $twitter_group['homepage'] = $group->homepage; + $twitter_group['description'] = $group->description; + $twitter_group['location'] = $group->location; + $twitter_group['created'] = $this->dateTwitter($group->created); + $twitter_group['modified'] = $this->dateTwitter($group->modified); + return $twitter_group; } diff --git a/lib/atomgroupnoticefeed.php b/lib/atomgroupnoticefeed.php index 7934a4f9e..761df587c 100644 --- a/lib/atomgroupnoticefeed.php +++ b/lib/atomgroupnoticefeed.php @@ -93,4 +93,23 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed return $this->group; } + function initFeed() + { + parent::initFeed(); + + $attrs = array(); + + if (!empty($this->cur)) { + $attrs['member'] = $this->cur->isMember($this->group) + ? 'true' : 'false'; + $attrs['blocked'] = Group_block::isBlocked( + $this->group, + $this->cur->getProfile() + ) ? 'true' : 'false'; + } + + $attrs['member_count'] = $this->group->getMemberCount(); + + $this->element('statusnet:group_info', $attrs, null); + } } -- cgit v1.2.3-54-g00ecf From a6ce4eef0df225dd863baf45d5615cbe22dcdea6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Jun 2010 18:27:51 -0700 Subject: Fix problem with AvatarLink in which it was sometimes leaving the width attribute empty --- lib/avatarlink.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/avatarlink.php b/lib/avatarlink.php index e67799e2e..7d4256d6e 100644 --- a/lib/avatarlink.php +++ b/lib/avatarlink.php @@ -76,8 +76,8 @@ class AvatarLink $alink = new AvatarLink(); $alink->url = $filename; $alink->height = $size; + $alink->width = $size; if (!empty($filename)) { - $alink->width = $size; $alink->type = self::mediatype($filename); } else { $alink->url = User_group::defaultLogo($size); -- cgit v1.2.3-54-g00ecf From 1eec7f779fc85b530907ea31deceadb2a30d7614 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 22 Jun 2010 16:28:06 -0700 Subject: - Add profile_info tag to Atom author - Normalize xmlns:statusnet links in the API --- classes/Notice.php | 4 ++-- classes/Profile.php | 10 +++++++++- lib/apiaction.php | 2 ++ lib/atomnoticefeed.php | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index f8eda5777..c752e35a7 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1190,7 +1190,7 @@ class Notice extends Memcached_DataObject 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', - 'xmlns:statusnet' => 'http://status.net/ont/'); + 'xmlns:statusnet' => 'http://status.net/schema/api/1/'); } else { $attrs = array(); } @@ -1225,7 +1225,7 @@ class Notice extends Memcached_DataObject $xs->element('title', null, common_xml_safe_str($this->content)); if ($author) { - $xs->raw($profile->asAtomAuthor()); + $xs->raw($profile->asAtomAuthor($cur)); $xs->raw($profile->asActivityActor()); } diff --git a/classes/Profile.php b/classes/Profile.php index 54f557ea7..a303469e9 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -849,15 +849,23 @@ class Profile extends Memcached_DataObject * * Assumes that Atom has been previously set up as the base namespace. * + * @param Profile $cur the current authenticated user + * * @return string */ - function asAtomAuthor() + function asAtomAuthor($cur = null) { $xs = new XMLStringer(true); $xs->elementStart('author'); $xs->element('name', null, $this->nickname); $xs->element('uri', null, $this->getUri()); + if ($cur != null) { + $attrs = Array(); + $attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false'; + $attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false'; + $xs->element('statusnet:profile_info', $attrs, null); + } $xs->elementEnd('author'); return $xs->getString(); diff --git a/lib/apiaction.php b/lib/apiaction.php index 7cc473d51..226481778 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -208,11 +208,13 @@ class ApiAction extends Action // Is the requesting user following this user? $twitter_user['following'] = false; + $twitter_user['statusnet:blocking'] = false; $twitter_user['notifications'] = false; if (isset($this->auth_user)) { $twitter_user['following'] = $this->auth_user->isSubscribed($profile); + $twitter_user['statusnet:blocking'] = $this->auth_user->hasBlocked($profile); // Notifications on? $sub = Subscription::pkeyGet(array('subscriber' => diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index ef44de4b6..6ed803ce4 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -95,7 +95,7 @@ class AtomNoticeFeed extends Atom10Feed $this->addNamespace( 'statusnet', - 'http://status.net/ont/' + 'http://status.net/schema/api/1/' ); } -- cgit v1.2.3-54-g00ecf From 9eb5a976b03fae6bd1e1fce6abfe4a6c7964d1ae Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 24 Jun 2010 18:11:50 -0700 Subject: Have API methods for search subclass ApiPrivateAuthAction --- actions/apisearchatom.php | 408 ++++++++++++++++++++++++++++++++++++++++++ actions/apisearchjson.php | 154 ++++++++++++++++ actions/apitrends.php | 90 ++++++++++ actions/twitapisearchatom.php | 402 ----------------------------------------- actions/twitapisearchjson.php | 151 ---------------- actions/twitapitrends.php | 88 --------- lib/router.php | 6 +- 7 files changed, 655 insertions(+), 644 deletions(-) create mode 100644 actions/apisearchatom.php create mode 100644 actions/apisearchjson.php create mode 100644 actions/apitrends.php delete mode 100644 actions/twitapisearchatom.php delete mode 100644 actions/twitapisearchjson.php delete mode 100644 actions/twitapitrends.php (limited to 'lib') diff --git a/actions/apisearchatom.php b/actions/apisearchatom.php new file mode 100644 index 000000000..60bb8b040 --- /dev/null +++ b/actions/apisearchatom.php @@ -0,0 +1,408 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/apiprivateauth.php'; + +/** + * Action for outputting search results in Twitter compatible Atom + * format. + * + * TODO: abstract Atom stuff into a ruseable base class like + * RSS10Action. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see ApiPrivateAuthAction + */ + +class ApiSearchAtomAction extends ApiPrivateAuthAction +{ + + var $cnt; + var $query; + var $lang; + var $rpp; + var $page; + var $since_id; + var $geocode; + + /** + * Constructor + * + * Just wraps the Action constructor. + * + * @param string $output URI to output to, default = stdout + * @param boolean $indent Whether to indent output, default true + * + * @see Action::__construct + */ + + function __construct($output='php://output', $indent=null) + { + parent::__construct($output, $indent); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + + function isReadonly() + { + return true; + } + + /** + * Read arguments and initialize members + * + * @param array $args Arguments from $_REQUEST + * + * @return boolean success + * + */ + + function prepare($args) + { + common_debug("in apisearchatom prepare()"); + + parent::prepare($args); + + + $this->query = $this->trimmed('q'); + $this->lang = $this->trimmed('lang'); + $this->rpp = $this->trimmed('rpp'); + + if (!$this->rpp) { + $this->rpp = 15; + } + + if ($this->rpp > 100) { + $this->rpp = 100; + } + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + // TODO: Suppport since_id -- we need to tweak the backend + // Search classes to support it. + + $this->since_id = $this->trimmed('since_id'); + $this->geocode = $this->trimmed('geocode'); + + // TODO: Also, language and geocode + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + common_debug("In apisearchatom handle()"); + $this->showAtom(); + } + + /** + * Get the notices to output as results. This also sets some class + * attrs so we can use them to calculate pagination, and output + * since_id and max_id. + * + * @return array an array of Notice objects sorted in reverse chron + */ + + function getNotices() + { + // TODO: Support search operators like from: and to:, boolean, etc. + + $notices = array(); + $notice = new Notice(); + + // lcase it for comparison + $q = strtolower($this->query); + + $search_engine = $notice->getSearchEngine('notice'); + $search_engine->set_sort_mode('chron'); + $search_engine->limit(($this->page - 1) * $this->rpp, + $this->rpp + 1, true); + if (false === $search_engine->query($q)) { + $this->cnt = 0; + } else { + $this->cnt = $notice->find(); + } + + $cnt = 0; + $this->max_id = 0; + + if ($this->cnt > 0) { + while ($notice->fetch()) { + + ++$cnt; + + if (!$this->max_id) { + $this->max_id = $notice->id; + } + + if ($cnt > $this->rpp) { + break; + } + + $notices[] = clone($notice); + } + } + + return $notices; + } + + /** + * Output search results as an Atom feed + * + * @return void + */ + + function showAtom() + { + $notices = $this->getNotices(); + + $this->initAtom(); + $this->showFeed(); + + foreach ($notices as $n) { + + $profile = $n->getProfile(); + + // Don't show notices from deleted users + + if (!empty($profile)) { + $this->showEntry($n); + } + } + + $this->endAtom(); + } + + /** + * Show feed specific Atom elements + * + * @return void + */ + + function showFeed() + { + // TODO: A9 OpenSearch stuff like search.twitter.com? + + $server = common_config('site', 'server'); + $sitename = common_config('site', 'name'); + + // XXX: Use xmlns:statusnet instead? + + $this->elementStart('feed', + array('xmlns' => 'http://www.w3.org/2005/Atom', + + // XXX: xmlns:twitter causes Atom validation to fail + // It's used for the source attr on notices + + 'xmlns:twitter' => 'http://api.twitter.com/', + 'xml:lang' => 'en-US')); // XXX Other locales ? + + $taguribase = TagURI::base(); + $this->element('id', null, "tag:$taguribase:search/$server"); + + $site_uri = common_path(false); + + $search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query); + + if ($this->rpp != 15) { + $search_uri .= '&rpp=' . $this->rpp; + } + + // FIXME: this alternate link is not quite right because our + // web-based notice search doesn't support a rpp (responses per + // page) param yet + + $this->element('link', array('type' => 'text/html', + 'rel' => 'alternate', + 'href' => $site_uri . 'search/notice?q=' . + urlencode($this->query))); + + // self link + + $self_uri = $search_uri; + $self_uri .= ($this->page > 1) ? '&page=' . $this->page : ''; + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'self', + 'href' => $self_uri)); + + $this->element('title', null, "$this->query - $sitename Search"); + $this->element('updated', null, common_date_iso8601('now')); + + // XXX: The below "rel" links are not valid Atom, but it's what + // Twitter does... + + // refresh link + + $refresh_uri = $search_uri . "&since_id=" . $this->max_id; + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'refresh', + 'href' => $refresh_uri)); + + // pagination links + + if ($this->cnt > $this->rpp) { + + $next_uri = $search_uri . "&max_id=" . $this->max_id . + '&page=' . ($this->page + 1); + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'next', + 'href' => $next_uri)); + } + + if ($this->page > 1) { + + $previous_uri = $search_uri . "&max_id=" . $this->max_id . + '&page=' . ($this->page - 1); + + $this->element('link', array('type' => 'application/atom+xml', + 'rel' => 'previous', + 'href' => $previous_uri)); + } + + } + + /** + * Build an Atom entry similar to search.twitter.com's based on + * a given notice + * + * @param Notice $notice the notice to use + * + * @return void + */ + + function showEntry($notice) + { + $server = common_config('site', 'server'); + $profile = $notice->getProfile(); + $nurl = common_local_url('shownotice', array('notice' => $notice->id)); + + $this->elementStart('entry'); + + $taguribase = TagURI::base(); + + $this->element('id', null, "tag:$taguribase:$notice->id"); + $this->element('published', null, common_date_w3dtf($notice->created)); + $this->element('link', array('type' => 'text/html', + 'rel' => 'alternate', + 'href' => $nurl)); + $this->element('title', null, common_xml_safe_str(trim($notice->content))); + $this->element('content', array('type' => 'html'), $notice->rendered); + $this->element('updated', null, common_date_w3dtf($notice->created)); + $this->element('link', array('type' => 'image/png', + // XXX: Twitter uses rel="image" (not valid) + 'rel' => 'related', + 'href' => $profile->avatarUrl())); + + // @todo: Here is where we'd put in a link to an atom feed for threads + + $source = null; + + $ns = $notice->getSource(); + if ($ns) { + if (!empty($ns->name) && !empty($ns->url)) { + $source = '' + . htmlspecialchars($ns->name) + . ''; + } else { + $source = $ns->code; + } + } + + $this->element("twitter:source", null, $source); + + $this->elementStart('author'); + + $name = $profile->nickname; + + if ($profile->fullname) { + $name .= ' (' . $profile->fullname . ')'; + } + + $this->element('name', null, $name); + $this->element('uri', null, common_profile_uri($profile)); + $this->elementEnd('author'); + + $this->elementEnd('entry'); + } + + /** + * Initialize the Atom output, send headers + * + * @return void + */ + + function initAtom() + { + header('Content-Type: application/atom+xml; charset=utf-8'); + $this->startXml(); + } + + /** + * End the Atom feed + * + * @return void + */ + + function endAtom() + { + $this->elementEnd('feed'); + } + +} diff --git a/actions/apisearchjson.php b/actions/apisearchjson.php new file mode 100644 index 000000000..e44634684 --- /dev/null +++ b/actions/apisearchjson.php @@ -0,0 +1,154 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/apiprivateauth.php'; +require_once INSTALLDIR.'/lib/jsonsearchresultslist.php'; + +/** + * Action handler for Twitter-compatible API search + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * @see ApiAction + */ + +class ApiSearchJSONAction extends ApiPrivateAuthAction +{ + var $query; + var $lang; + var $rpp; + var $page; + var $since_id; + var $limit; + var $geocode; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean true if nothing goes wrong + */ + + function prepare($args) + { + common_debug("apisearchjson prepare()"); + + parent::prepare($args); + + $this->query = $this->trimmed('q'); + $this->lang = $this->trimmed('lang'); + $this->rpp = $this->trimmed('rpp'); + + if (!$this->rpp) { + $this->rpp = 15; + } + + if ($this->rpp > 100) { + $this->rpp = 100; + } + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + $this->since_id = $this->trimmed('since_id'); + $this->geocode = $this->trimmed('geocode'); + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showResults(); + } + + /** + * Show search results + * + * @return void + */ + + function showResults() + { + + // TODO: Support search operators like from: and to:, boolean, etc. + + $notice = new Notice(); + + // lcase it for comparison + $q = strtolower($this->query); + + $search_engine = $notice->getSearchEngine('notice'); + $search_engine->set_sort_mode('chron'); + $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true); + if (false === $search_engine->query($q)) { + $cnt = 0; + } else { + $cnt = $notice->find(); + } + + // TODO: since_id, lang, geocode + + $results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page); + + $this->initDocument('json'); + $results->show(); + $this->endDocument('json'); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + + function isReadOnly($args) + { + return true; + } +} diff --git a/actions/apitrends.php b/actions/apitrends.php new file mode 100644 index 000000000..5b74636c6 --- /dev/null +++ b/actions/apitrends.php @@ -0,0 +1,90 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/apiprivateauth.php'; + +/** + * Returns the top ten queries that are currently trending + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see ApiAction + */ + +class ApiTrendsAction extends ApiPrivateAuthAction +{ + + var $callback; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if user doesn't exist + */ + function prepare($args) + { + parent::prepare($args); + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showTrends(); + } + + /** + * Output the trends + * + * @return void + */ + function showTrends() + { + $this->serverError(_('API method under construction.'), 501); + } + +} \ No newline at end of file diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php deleted file mode 100644 index 51e8a8881..000000000 --- a/actions/twitapisearchatom.php +++ /dev/null @@ -1,402 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Action for outputting search results in Twitter compatible Atom - * format. - * - * TODO: abstract Atom stuff into a ruseable base class like - * RSS10Action. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - * @see ApiAction - */ - -class TwitapisearchatomAction extends ApiAction -{ - - var $cnt; - var $query; - var $lang; - var $rpp; - var $page; - var $since_id; - var $geocode; - - /** - * Constructor - * - * Just wraps the Action constructor. - * - * @param string $output URI to output to, default = stdout - * @param boolean $indent Whether to indent output, default true - * - * @see Action::__construct - */ - - function __construct($output='php://output', $indent=null) - { - parent::__construct($output, $indent); - } - - /** - * Do we need to write to the database? - * - * @return boolean true - */ - - function isReadonly() - { - return true; - } - - /** - * Read arguments and initialize members - * - * @param array $args Arguments from $_REQUEST - * - * @return boolean success - * - */ - - function prepare($args) - { - parent::prepare($args); - - $this->query = $this->trimmed('q'); - $this->lang = $this->trimmed('lang'); - $this->rpp = $this->trimmed('rpp'); - - if (!$this->rpp) { - $this->rpp = 15; - } - - if ($this->rpp > 100) { - $this->rpp = 100; - } - - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - // TODO: Suppport since_id -- we need to tweak the backend - // Search classes to support it. - - $this->since_id = $this->trimmed('since_id'); - $this->geocode = $this->trimmed('geocode'); - - // TODO: Also, language and geocode - - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showAtom(); - } - - /** - * Get the notices to output as results. This also sets some class - * attrs so we can use them to calculate pagination, and output - * since_id and max_id. - * - * @return array an array of Notice objects sorted in reverse chron - */ - - function getNotices() - { - // TODO: Support search operators like from: and to:, boolean, etc. - - $notices = array(); - $notice = new Notice(); - - // lcase it for comparison - $q = strtolower($this->query); - - $search_engine = $notice->getSearchEngine('notice'); - $search_engine->set_sort_mode('chron'); - $search_engine->limit(($this->page - 1) * $this->rpp, - $this->rpp + 1, true); - if (false === $search_engine->query($q)) { - $this->cnt = 0; - } else { - $this->cnt = $notice->find(); - } - - $cnt = 0; - $this->max_id = 0; - - if ($this->cnt > 0) { - while ($notice->fetch()) { - - ++$cnt; - - if (!$this->max_id) { - $this->max_id = $notice->id; - } - - if ($cnt > $this->rpp) { - break; - } - - $notices[] = clone($notice); - } - } - - return $notices; - } - - /** - * Output search results as an Atom feed - * - * @return void - */ - - function showAtom() - { - $notices = $this->getNotices(); - - $this->initAtom(); - $this->showFeed(); - - foreach ($notices as $n) { - - $profile = $n->getProfile(); - - // Don't show notices from deleted users - - if (!empty($profile)) { - $this->showEntry($n); - } - } - - $this->endAtom(); - } - - /** - * Show feed specific Atom elements - * - * @return void - */ - - function showFeed() - { - // TODO: A9 OpenSearch stuff like search.twitter.com? - - $server = common_config('site', 'server'); - $sitename = common_config('site', 'name'); - - // XXX: Use xmlns:statusnet instead? - - $this->elementStart('feed', - array('xmlns' => 'http://www.w3.org/2005/Atom', - - // XXX: xmlns:twitter causes Atom validation to fail - // It's used for the source attr on notices - - 'xmlns:twitter' => 'http://api.twitter.com/', - 'xml:lang' => 'en-US')); // XXX Other locales ? - - $taguribase = TagURI::base(); - $this->element('id', null, "tag:$taguribase:search/$server"); - - $site_uri = common_path(false); - - $search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query); - - if ($this->rpp != 15) { - $search_uri .= '&rpp=' . $this->rpp; - } - - // FIXME: this alternate link is not quite right because our - // web-based notice search doesn't support a rpp (responses per - // page) param yet - - $this->element('link', array('type' => 'text/html', - 'rel' => 'alternate', - 'href' => $site_uri . 'search/notice?q=' . - urlencode($this->query))); - - // self link - - $self_uri = $search_uri; - $self_uri .= ($this->page > 1) ? '&page=' . $this->page : ''; - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'self', - 'href' => $self_uri)); - - $this->element('title', null, "$this->query - $sitename Search"); - $this->element('updated', null, common_date_iso8601('now')); - - // XXX: The below "rel" links are not valid Atom, but it's what - // Twitter does... - - // refresh link - - $refresh_uri = $search_uri . "&since_id=" . $this->max_id; - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'refresh', - 'href' => $refresh_uri)); - - // pagination links - - if ($this->cnt > $this->rpp) { - - $next_uri = $search_uri . "&max_id=" . $this->max_id . - '&page=' . ($this->page + 1); - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'next', - 'href' => $next_uri)); - } - - if ($this->page > 1) { - - $previous_uri = $search_uri . "&max_id=" . $this->max_id . - '&page=' . ($this->page - 1); - - $this->element('link', array('type' => 'application/atom+xml', - 'rel' => 'previous', - 'href' => $previous_uri)); - } - - } - - /** - * Build an Atom entry similar to search.twitter.com's based on - * a given notice - * - * @param Notice $notice the notice to use - * - * @return void - */ - - function showEntry($notice) - { - $server = common_config('site', 'server'); - $profile = $notice->getProfile(); - $nurl = common_local_url('shownotice', array('notice' => $notice->id)); - - $this->elementStart('entry'); - - $taguribase = TagURI::base(); - - $this->element('id', null, "tag:$taguribase:$notice->id"); - $this->element('published', null, common_date_w3dtf($notice->created)); - $this->element('link', array('type' => 'text/html', - 'rel' => 'alternate', - 'href' => $nurl)); - $this->element('title', null, common_xml_safe_str(trim($notice->content))); - $this->element('content', array('type' => 'html'), $notice->rendered); - $this->element('updated', null, common_date_w3dtf($notice->created)); - $this->element('link', array('type' => 'image/png', - // XXX: Twitter uses rel="image" (not valid) - 'rel' => 'related', - 'href' => $profile->avatarUrl())); - - // @todo: Here is where we'd put in a link to an atom feed for threads - - $source = null; - - $ns = $notice->getSource(); - if ($ns) { - if (!empty($ns->name) && !empty($ns->url)) { - $source = '' - . htmlspecialchars($ns->name) - . ''; - } else { - $source = $ns->code; - } - } - - $this->element("twitter:source", null, $source); - - $this->elementStart('author'); - - $name = $profile->nickname; - - if ($profile->fullname) { - $name .= ' (' . $profile->fullname . ')'; - } - - $this->element('name', null, $name); - $this->element('uri', null, common_profile_uri($profile)); - $this->elementEnd('author'); - - $this->elementEnd('entry'); - } - - /** - * Initialize the Atom output, send headers - * - * @return void - */ - - function initAtom() - { - header('Content-Type: application/atom+xml; charset=utf-8'); - $this->startXml(); - } - - /** - * End the Atom feed - * - * @return void - */ - - function endAtom() - { - $this->elementEnd('feed'); - } - -} diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php deleted file mode 100644 index b5c006aa7..000000000 --- a/actions/twitapisearchjson.php +++ /dev/null @@ -1,151 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/jsonsearchresultslist.php'; - -/** - * Action handler for Twitter-compatible API search - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * @see ApiAction - */ - -class TwitapisearchjsonAction extends ApiAction -{ - var $query; - var $lang; - var $rpp; - var $page; - var $since_id; - var $limit; - var $geocode; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean true if nothing goes wrong - */ - - function prepare($args) - { - parent::prepare($args); - - $this->query = $this->trimmed('q'); - $this->lang = $this->trimmed('lang'); - $this->rpp = $this->trimmed('rpp'); - - if (!$this->rpp) { - $this->rpp = 15; - } - - if ($this->rpp > 100) { - $this->rpp = 100; - } - - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - $this->since_id = $this->trimmed('since_id'); - $this->geocode = $this->trimmed('geocode'); - - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showResults(); - } - - /** - * Show search results - * - * @return void - */ - - function showResults() - { - - // TODO: Support search operators like from: and to:, boolean, etc. - - $notice = new Notice(); - - // lcase it for comparison - $q = strtolower($this->query); - - $search_engine = $notice->getSearchEngine('notice'); - $search_engine->set_sort_mode('chron'); - $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true); - if (false === $search_engine->query($q)) { - $cnt = 0; - } else { - $cnt = $notice->find(); - } - - // TODO: since_id, lang, geocode - - $results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page); - - $this->initDocument('json'); - $results->show(); - $this->endDocument('json'); - } - - /** - * Do we need to write to the database? - * - * @return boolean true - */ - - function isReadOnly($args) - { - return true; - } -} diff --git a/actions/twitapitrends.php b/actions/twitapitrends.php deleted file mode 100644 index 5a04569a2..000000000 --- a/actions/twitapitrends.php +++ /dev/null @@ -1,88 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2008-2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Returns the top ten queries that are currently trending - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - * @see ApiAction - */ - -class TwitapitrendsAction extends ApiAction -{ - - var $callback; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean false if user doesn't exist - */ - function prepare($args) - { - parent::prepare($args); - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showTrends(); - } - - /** - * Output the trends - * - * @return void - */ - function showTrends() - { - $this->serverError(_('API method under construction.'), $code = 501); - } - -} \ No newline at end of file diff --git a/lib/router.php b/lib/router.php index fec229c9b..7e1e6a2a4 100644 --- a/lib/router.php +++ b/lib/router.php @@ -667,9 +667,9 @@ class Router ); // search - $m->connect('api/search.atom', array('action' => 'twitapisearchatom')); - $m->connect('api/search.json', array('action' => 'twitapisearchjson')); - $m->connect('api/trends.json', array('action' => 'twitapitrends')); + $m->connect('api/search.atom', array('action' => 'ApiSearchAtom')); + $m->connect('api/search.json', array('action' => 'ApiSearchJSON')); + $m->connect('api/trends.json', array('action' => 'ApiTrends')); $m->connect('api/oauth/request_token', array('action' => 'apioauthrequesttoken')); -- cgit v1.2.3-54-g00ecf