Commit e89908f2 authored by Brion Vibber's avatar Brion Vibber

Merge branch '0.9.x' of git@gitorious.org:statusnet/mainline into 1.0.x

Conflicts:
	lib/channel.php
	scripts/imdaemon.php
parents 714d920f eb563937
......@@ -137,7 +137,9 @@ run correctly.
- PHP 5.2.3+. It may be possible to run this software on earlier
versions of PHP, but many of the functions used are only available
in PHP 5.2 or above.
in PHP 5.2 or above. 5.2.6 or later is needed for XMPP background
daemons on 64-bit platforms. PHP 5.3.x should work but is known
to cause some failures for OpenID.
- MySQL 5.x. The StatusNet database is stored, by default, in a MySQL
server. It has been primarily tested on 5.x servers, although it may
be possible to install on earlier (or later!) versions. The server
......
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Upload an image via the API
*
* PHP version 5
*
* LICENCE: 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 API
* @author Zach Copley <zach@status.net>
* @copyright 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')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
require_once INSTALLDIR . '/lib/mediafile.php';
/**
* Upload an image via the API. Returns a shortened URL for the image
* to the user.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiMediaUploadAction extends ApiAuthAction
{
/**
* Handle the request
*
* Grab the file from the 'media' param, then store, and shorten
*
* @todo Upload throttle!
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
if (empty($_FILES)
&& empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0)
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return;
}
$upload = null;
try {
$upload = MediaFile::fromUpload('media', $this->auth_user);
} catch (ClientException $ce) {
$this->clientError($ce->getMessage());
return;
}
if (isset($upload)) {
$this->showResponse($upload);
} else {
$this->clientError('Upload failed.');
return;
}
}
/**
* Show a Twitpic-like response with the ID of the media file
* and a (hopefully) shortened URL for it.
*
* @param File $upload the uploaded file
*
* @return void
*/
function showResponse($upload)
{
$this->initDocument();
$this->elementStart('rsp', array('stat' => 'ok'));
$this->element('mediaid', null, $upload->fileRecord->id);
$this->element('mediaurl', null, $upload->shortUrl());
$this->elementEnd('rsp');
$this->endDocument();
}
/**
* Overrided clientError to show a more Twitpic-like error
*
* @param String $msg an error message
*
*/
function clientError($msg)
{
$this->initDocument();
$this->elementStart('rsp', array('stat' => 'fail'));
// @todo add in error code
$errAttr = array('msg' => $msg);
$this->element('err', $errAttr, null);
$this->elementEnd('rsp');
$this->endDocument();
}
}
......@@ -244,11 +244,17 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$options = array_merge($options, $locOptions);
}
$this->notice =
Notice::saveNew($this->auth_user->id,
$content,
$this->source,
$options);
try {
$this->notice = Notice::saveNew(
$this->auth_user->id,
$content,
$this->source,
$options
);
} catch (Exception $e) {
$this->clientError($e->getMessage());
return;
}
if (isset($upload)) {
$upload->attachToNotice($this->notice);
......
......@@ -97,8 +97,6 @@ class ApiStatusnetConfigAction extends ApiAction
// XXX: check that all sections and settings are legal XML elements
common_debug(var_export($this->keys, true));
foreach ($this->keys as $section => $settings) {
$this->elementStart($section);
foreach ($settings as $setting) {
......@@ -110,6 +108,14 @@ class ApiStatusnetConfigAction extends ApiAction
} else if ($value === true) {
$value = 'true';
}
// return theme logo if there's no site specific one
if (empty($value)) {
if ($section == 'site' && $setting == 'logo') {
$value = Theme::path('logo.png');
}
}
$this->element($setting, null, $value);
}
$this->elementEnd($section);
......
......@@ -23,7 +23,8 @@
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @copyright 2009 StatusNet, Inc.
* @author Zach Copley <zach@status.net>
* @copyright 2009-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/
*/
......@@ -123,22 +124,26 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
? $avatar->displayUrl()
: Avatar::defaultImage(AVATAR_PROFILE_SIZE);
$link = common_local_url(
'showfavorites',
array('nickname' => $this->user->nickname)
);
$self = $this->getSelfUri();
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$link = common_local_url(
'showfavorites',
array('nickname' => $this->user->nickname)
);
$this->showRssTimeline(
$this->notices,
$title,
$link,
$subtitle,
null,
$logo
$logo,
$self
);
break;
case 'atom':
......@@ -153,23 +158,8 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
$atom->setLogo($logo);
$atom->setUpdated('now');
$atom->addLink(
common_local_url(
'showfavorites',
array('nickname' => $this->user->nickname)
)
);
$id = $this->arg('id');
$aargs = array('format' => 'atom');
if (!empty($id)) {
$aargs['id'] = $id;
}
$atom->addLink(
$this->getSelfUri('ApiTimelineFavorites', $aargs),
array('rel' => 'self', 'type' => 'application/atom+xml')
);
$atom->addLink($link);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
......
......@@ -117,9 +117,17 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
$subtitle = sprintf(
_('Updates from %1$s and friends on %2$s!'),
$this->user->nickname, $sitename
$this->user->nickname,
$sitename
);
$link = common_local_url(
'all',
array('nickname' => $this->user->nickname)
);
$self = $this->getSelfUri();
$logo = (!empty($avatar))
? $avatar->displayUrl()
: Avatar::defaultImage(AVATAR_PROFILE_SIZE);
......@@ -130,19 +138,14 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
break;
case 'rss':
$link = common_local_url(
'all', array(
'nickname' => $this->user->nickname
)
);
$this->showRssTimeline(
$this->notices,
$title,
$link,
$subtitle,
null,
$logo
$logo,
$self
);
break;
case 'atom':
......@@ -156,24 +159,8 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
$atom->setSubtitle($subtitle);
$atom->setLogo($logo);
$atom->setUpdated('now');
$atom->addLink(
common_local_url(
'all',
array('nickname' => $this->user->nickname)
)
);
$id = $this->arg('id');
$aargs = array('format' => 'atom');
if (!empty($id)) {
$aargs['id'] = $id;
}
$atom->addLink(
$this->getSelfUri('ApiTimelineFriends', $aargs),
array('rel' => 'self', 'type' => 'application/atom+xml')
);
$atom->addLink($link);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
......
......@@ -107,6 +107,8 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
// We'll pull common formatting out of this for other formats
$atom = new AtomGroupNoticeFeed($this->group);
$self = $this->getSelfUri();
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
......@@ -118,7 +120,8 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
$this->group->homeUrl(),
$atom->subtitle,
null,
$atom->logo
$atom->logo,
$self
);
break;
case 'atom':
......@@ -126,24 +129,12 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
header('Content-Type: application/atom+xml; charset=utf-8');
try {
$atom->addAuthorRaw($this->group->asAtomAuthor());
$atom->setActivitySubject($this->group->asActivitySubject());
$id = $this->arg('id');
$aargs = array('format' => 'atom');
if (!empty($id)) {
$aargs['id'] = $id;
}
$self = $this->getSelfUri('ApiTimelineGroup', $aargs);
$atom->setId($self);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString());
} catch (Atom10FeedException $e) {
$this->serverError(
'Could not generate feed for group - ' . $e->getMessage()
......
......@@ -72,7 +72,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
function prepare($args)
{
parent::prepare($args);
common_debug("api home_timeline");
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
......@@ -121,8 +121,15 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
$this->user->nickname, $sitename
);
$logo = (!empty($avatar))
? $avatar->displayUrl()
$link = common_local_url(
'all',
array('nickname' => $this->user->nickname)
);
$self = $this->getSelfUri();
$logo = (!empty($avatar))
? $avatar->displayUrl()
: Avatar::defaultImage(AVATAR_PROFILE_SIZE);
switch($this->format) {
......@@ -130,17 +137,14 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$link = common_local_url(
'all',
array('nickname' => $this->user->nickname)
);
$this->showRssTimeline(
$this->notices,
$title,
$link,
$subtitle,
null,
$logo
$logo,
$self
);
break;
case 'atom':
......@@ -155,23 +159,8 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
$atom->setLogo($logo);
$atom->setUpdated('now');
$atom->addLink(
common_local_url(
'all',
array('nickname' => $this->user->nickname)
)
);
$id = $this->arg('id');
$aargs = array('format' => 'atom');
if (!empty($id)) {
$aargs['id'] = $id;
}
$atom->addLink(
$this->getSelfUri('ApiTimelineHome', $aargs),
array('rel' => 'self', 'type' => 'application/atom+xml')
);
$atom->addLink($link);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString());
......
......@@ -123,6 +123,9 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
'replies',
array('nickname' => $this->user->nickname)
);
$self = $this->getSelfUri();
$subtitle = sprintf(
_('%1$s updates that reply to updates from %2$s / %3$s.'),
$sitename, $this->user->nickname, $profile->getBestName()
......@@ -134,10 +137,20 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
$this->showRssTimeline(
$this->notices,
$title,
$link,
$subtitle,
null,
$logo,
$self
);
break;
case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom->setId($id);
......@@ -146,23 +159,8 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
$atom->setLogo($logo);
$atom->setUpdated('now');
$atom->addLink(
common_local_url(
'replies',
array('nickname' => $this->user->nickname)
)
);
$id = $this->arg('id');
$aargs = array('format' => 'atom');
if (!empty($id)) {
$aargs['id'] = $id;
}
$atom->addLink(
$this->getSelfUri('ApiTimelineMentions', $aargs),
array('rel' => 'self', 'type' => 'application/atom+xml')
);
$atom->addLink($link);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString());
......
......@@ -107,7 +107,8 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
$title = sprintf(_("%s public timeline"), $sitename);
$taguribase = TagURI::base();
$id = "tag:$taguribase:PublicTimeline";
$link = common_root_url();
$link = common_local_url('public');
$self = $this->getSelfUri();
$subtitle = sprintf(_("%s updates from everyone!"), $sitename);
switch($this->format) {
......@@ -115,10 +116,20 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $sitelogo);
$this->showRssTimeline(
$this->notices,
$title,
$link,
$subtitle,
null,
$sitelogo,
$self
);
break;
case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed();
$atom->setId($id);
......@@ -126,16 +137,8 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
$atom->setSubtitle($subtitle);
$atom->setLogo($sitelogo);
$atom->setUpdated('now');
$atom->addLink(common_local_url('public'));
$atom->addLink(
$this->getSelfUri(
'ApiTimelinePublic', array('format' => 'atom')
),
array('rel' => 'self', 'type' => 'application/atom+xml')
);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString());
......
......@@ -25,7 +25,7 @@
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-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/
*/
......@@ -67,6 +67,8 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
{
parent::prepare($args);
common_debug("apitimelinetag prepare()");
$this->tag = $this->arg('tag');
$this->notices = $this->getNotices();
......@@ -108,22 +110,28 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
$taguribase = TagURI::base();
$id = "tag:$taguribase:TagTimeline:".$tag;
$link = common_local_url(
'tag',
array('tag' => $this->tag)
);
$self = $this->getSelfUri();
common_debug("self link is: $self");
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$link = common_local_url(
'tag',
array('tag' => $this->tag)
);
$this->showRssTimeline(
$this->notices,
$title,
$link,
$subtitle,
null,
$sitelogo
$sitelogo,
$self
);
break;
case 'atom':
......@@ -138,22 +146,8 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
$atom->setLogo($logo);
$atom->setUpdated('now');
$atom->addLink(
common_local_url(
'tag',
array('tag' => $this->tag)
)
);
$aargs = array('format' => 'atom');
if (!empty($this->tag)) {
$aargs['tag'] = $this->tag;
}
$atom->addLink(
$this->getSelfUri('ApiTimelineTag', $aargs),
array('rel' => 'self', 'type' => 'application/atom+xml')
);
$atom->addLink($link);
$atom->setSelfLink($self);
$atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString());
......
......@@ -116,13 +116,13 @@ class ApiTimelineUserAction extends ApiBareAuthAction
// We'll use the shared params from the Atom stub
// for other feed types.
$atom = new AtomUserNoticeFeed($this->user);
$title = $atom->title;
$link = common_local_url(
$link = common_local_url(
'showstream',
array('nickname' => $this->user->nickname)
);
$subtitle = $atom->subtitle;
$logo = $atom->logo;
$self = $this->getSelfUri();
// FriendFeed's SUP protocol
// Also added RSS and Atom feeds
......@@ -136,25 +136,22 @@ class ApiTimelineUserAction extends ApiBareAuthAction
break;
case 'rss':