Merge branch 'testing' of git@gitorious.org:statusnet/mainline into testing
This commit is contained in:
commit
c1e96cbdef
2
README
2
README
@ -690,7 +690,7 @@ instructions; read to the end first before trying them.
|
||||
9. Copy htaccess.sample to .htaccess in the new directory. Change the
|
||||
RewriteBase to use the correct path.
|
||||
10. Rebuild the database. (You can safely skip this step and go to #12
|
||||
if you're upgrading from another 0.8.x version).
|
||||
if you're upgrading from another 0.9.x version).
|
||||
|
||||
NOTE: this step is destructive and cannot be
|
||||
reversed. YOU CAN EASILY DESTROY YOUR SITE WITH THIS STEP. Don't
|
||||
|
@ -51,6 +51,7 @@ class AccessadminpanelAction extends AdminPanelAction
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title
|
||||
return _('Access');
|
||||
}
|
||||
|
||||
@ -62,6 +63,7 @@ class AccessadminpanelAction extends AdminPanelAction
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Page notice
|
||||
return _('Site access settings');
|
||||
}
|
||||
|
||||
@ -155,24 +157,34 @@ class AccessAdminPanelForm extends AdminForm
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_access'));
|
||||
// TRANS: Form legend for registration form.
|
||||
$this->out->element('legend', null, _('Registration'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$this->out->checkbox('private', _('Private'),
|
||||
// TRANS: Checkbox instructions for admin setting "Private"
|
||||
$instructions = _('Prohibit anonymous users (not logged in) from viewing site?');
|
||||
// TRANS: Checkbox label for prohibiting anonymous users from viewing site.
|
||||
$this->out->checkbox('private', _m('LABEL', 'Private'),
|
||||
(bool) $this->value('private'),
|
||||
_('Prohibit anonymous users (not logged in) from viewing site?'));
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Invite only"
|
||||
$instructions = _('Make registration invitation only.');
|
||||
// TRANS: Checkbox label for configuring site as invite only.
|
||||
$this->out->checkbox('inviteonly', _('Invite only'),
|
||||
(bool) $this->value('inviteonly'),
|
||||
_('Make registration invitation only.'));
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Closed" (no new registrations)
|
||||
$instructions = _('Disable new registrations.');
|
||||
// TRANS: Checkbox label for disabling new user registrations.
|
||||
$this->out->checkbox('closed', _('Closed'),
|
||||
(bool) $this->value('closed'),
|
||||
_('Disable new registrations.'));
|
||||
$instructions);
|
||||
$this->unli();
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
@ -186,7 +198,9 @@ class AccessAdminPanelForm extends AdminForm
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Save'), 'submit', null, _('Save access settings'));
|
||||
// TRANS: Title / tooltip for button to save access settings in site admin panel
|
||||
$title = _('Save access settings');
|
||||
$this->out->submit('submit', _m('BUTTON', 'Save'), 'submit', null, $title);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ class AllAction extends ProfileAction
|
||||
}
|
||||
|
||||
if ($this->page > 1 && $this->notice->N == 0) {
|
||||
// TRANS: Server error when page not found (404)
|
||||
$this->serverError(_('No such page'), $code = 404);
|
||||
}
|
||||
|
||||
@ -81,8 +82,10 @@ class AllAction extends ProfileAction
|
||||
function title()
|
||||
{
|
||||
if ($this->page > 1) {
|
||||
// TRANS: Page title. %1$s is user nickname, %2$d is page number
|
||||
return sprintf(_('%1$s and friends, page %2$d'), $this->user->nickname, $this->page);
|
||||
} else {
|
||||
// TRANS: Page title. %1$s is user nickname
|
||||
return sprintf(_("%s and friends"), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
@ -96,6 +99,7 @@ class AllAction extends ProfileAction
|
||||
'nickname' =>
|
||||
$this->user->nickname)
|
||||
),
|
||||
// TRANS: %1$s is user nickname
|
||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url(
|
||||
@ -104,6 +108,7 @@ class AllAction extends ProfileAction
|
||||
'id' => $this->user->nickname
|
||||
)
|
||||
),
|
||||
// TRANS: %1$s is user nickname
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url(
|
||||
@ -112,6 +117,7 @@ class AllAction extends ProfileAction
|
||||
'id' => $this->user->nickname
|
||||
)
|
||||
),
|
||||
// TRANS: %1$s is user nickname
|
||||
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
|
||||
);
|
||||
}
|
||||
@ -124,6 +130,7 @@ class AllAction extends ProfileAction
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
// TRANS: %1$s is user nickname
|
||||
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
@ -131,6 +138,7 @@ class AllAction extends ProfileAction
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
|
||||
} else {
|
||||
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@"
|
||||
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||
}
|
||||
} else {
|
||||
@ -166,8 +174,10 @@ class AllAction extends ProfileAction
|
||||
{
|
||||
$user = common_current_user();
|
||||
if ($user && ($user->id == $this->user->id)) {
|
||||
// TRANS: H1 text
|
||||
$this->element('h1', null, _("You and friends"));
|
||||
} else {
|
||||
// TRANS: H1 text. %1$s is user nickname
|
||||
$this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname));
|
||||
}
|
||||
}
|
||||
|
@ -115,11 +115,11 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
|
||||
|
||||
$original = clone($profile);
|
||||
|
||||
if (empty($this->name)) {
|
||||
if (!empty($this->name)) {
|
||||
$profile->fullname = $this->name;
|
||||
}
|
||||
|
||||
if (empty($this->url)) {
|
||||
if (!empty($this->url)) {
|
||||
$profile->homepage = $this->url;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Michele <macno@macno.org>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -68,6 +69,24 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
if (empty($this->group)) {
|
||||
$alias = Group_alias::staticGet(
|
||||
'alias',
|
||||
common_canonical_nickname($this->arg('id'))
|
||||
);
|
||||
if (!empty($alias)) {
|
||||
$args = array('id' => $alias->group_id, 'format' => $this->format);
|
||||
common_redirect(common_local_url('ApiGroupShow', $args), 301);
|
||||
} else {
|
||||
$this->clientError(
|
||||
_('Group not found!'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -85,15 +104,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (empty($this->group)) {
|
||||
$this->clientError(
|
||||
_('Group not found!'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
@ -105,7 +115,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
|
||||
$this->clientError(_('API method not found.'), 404, $this->format);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,7 +156,7 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($appUser, 'DELETE', __FILE__);
|
||||
throw new ServerException(_('DB error deleting OAuth app user.'));
|
||||
throw new ServerException(_('Database error deleting OAuth application user.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -182,7 +182,7 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($appUser, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('DB error inserting OAuth app user.'));
|
||||
throw new ServerException(_('Database error inserting OAuth application user.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -50,13 +50,17 @@ if (!defined('STATUSNET')) {
|
||||
class ApiStatusnetConfigAction extends ApiAction
|
||||
{
|
||||
var $keys = array(
|
||||
'site' => array('name', 'server', 'theme', 'path', 'fancy', 'language',
|
||||
'email', 'broughtby', 'broughtbyurl', 'closed',
|
||||
'inviteonly', 'private','textlimit'),
|
||||
'license' => array('url', 'title', 'image'),
|
||||
'site' => array('name', 'server', 'theme', 'path', 'logo', 'fancy', 'language',
|
||||
'email', 'broughtby', 'broughtbyurl', 'timezone', 'closed',
|
||||
'inviteonly', 'private', 'textlimit', 'ssl', 'sslserver', 'shorturllength'),
|
||||
'license' => array('type', 'owner', 'url', 'title', 'image'),
|
||||
'nickname' => array('featured'),
|
||||
'profile' => array('biolimit'),
|
||||
'group' => array('desclimit'),
|
||||
'notice' => array('contentlimit'),
|
||||
'throttle' => array('enabled', 'count', 'timespan'),
|
||||
'xmpp' => array('enabled', 'server', 'user')
|
||||
'xmpp' => array('enabled', 'server', 'port', 'user'),
|
||||
'integration' => array('source')
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -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':
|
||||
$this->showRssTimeline(
|
||||
$this->notices, $title, $link,
|
||||
$subtitle, $suplink, $logo
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$link,
|
||||
$atom->subtitle,
|
||||
$suplink,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$id = $this->arg('id');
|
||||
$aargs = array('format' => 'atom');
|
||||
if (!empty($id)) {
|
||||
$aargs['id'] = $id;
|
||||
}
|
||||
$self = $this->getSelfUri('ApiTimelineUser', $aargs);
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
|
@ -141,7 +141,7 @@ class ConfirmaddressAction extends Action
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Confirm Address');
|
||||
return _('Confirm address');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,7 +13,7 @@
|
||||
* @link http://status.net/
|
||||
*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||
* Copyright (C) 2008-2010, StatusNet, Inc.
|
||||
*
|
||||
* 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
|
||||
@ -168,14 +168,28 @@ class DocAction extends Action
|
||||
|
||||
function getFilename()
|
||||
{
|
||||
if (file_exists(INSTALLDIR.'/local/doc-src/'.$this->title)) {
|
||||
$localDef = INSTALLDIR.'/local/doc-src/'.$this->title;
|
||||
}
|
||||
$localDef = null;
|
||||
$local = null;
|
||||
|
||||
$local = glob(INSTALLDIR.'/local/doc-src/'.$this->title.'.*');
|
||||
if ($local === false) {
|
||||
// Some systems return false, others array(), if dir didn't exist.
|
||||
$local = array();
|
||||
$site = StatusNet::currentSite();
|
||||
|
||||
if (!empty($site) && file_exists(INSTALLDIR.'/local/doc-src/'.$site.'/'.$this->title)) {
|
||||
$localDef = INSTALLDIR.'/local/doc-src/'.$site.'/'.$this->title;
|
||||
|
||||
$local = glob(INSTALLDIR.'/local/doc-src/'.$site.'/'.$this->title.'.*');
|
||||
if ($local === false) {
|
||||
// Some systems return false, others array(), if dir didn't exist.
|
||||
$local = array();
|
||||
}
|
||||
} else {
|
||||
if (file_exists(INSTALLDIR.'/local/doc-src/'.$this->title)) {
|
||||
$localDef = INSTALLDIR.'/local/doc-src/'.$this->title;
|
||||
}
|
||||
|
||||
$local = glob(INSTALLDIR.'/local/doc-src/'.$this->title.'.*');
|
||||
if ($local === false) {
|
||||
$local = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (count($local) || isset($localDef)) {
|
||||
|
@ -251,7 +251,7 @@ class FoafAction extends Action
|
||||
}
|
||||
|
||||
// Their account
|
||||
$this->elementStart('holdsAccount');
|
||||
$this->elementStart('account');
|
||||
$this->elementStart('OnlineAccount', $attr);
|
||||
if ($service) {
|
||||
$this->element('accountServiceHomepage', array('rdf:resource' =>
|
||||
@ -306,7 +306,7 @@ class FoafAction extends Action
|
||||
}
|
||||
|
||||
$this->elementEnd('OnlineAccount');
|
||||
$this->elementEnd('holdsAccount');
|
||||
$this->elementEnd('account');
|
||||
|
||||
return $person;
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ class FoafGroupAction extends Action
|
||||
{
|
||||
$this->elementStart('Agent', array('rdf:about' => $uri));
|
||||
$this->element('nick', null, $details['nickname']);
|
||||
$this->elementStart('holdsAccount');
|
||||
$this->elementStart('account');
|
||||
$this->elementStart('sioc:User', array('rdf:about'=>$uri.'#acct'));
|
||||
$this->elementStart('sioc:has_function');
|
||||
$this->elementStart('statusnet:GroupAdminRole');
|
||||
@ -154,7 +154,7 @@ class FoafGroupAction extends Action
|
||||
$this->elementEnd('statusnet:GroupAdminRole');
|
||||
$this->elementEnd('sioc:has_function');
|
||||
$this->elementEnd('sioc:User');
|
||||
$this->elementEnd('holdsAccount');
|
||||
$this->elementEnd('account');
|
||||
$this->elementEnd('Agent');
|
||||
}
|
||||
else
|
||||
@ -177,4 +177,4 @@ class FoafGroupAction extends Action
|
||||
$this->elementEnd('Document');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +194,8 @@ class InviteAction extends CurrentUserDesignAction
|
||||
_('Optionally add a personal message to the invitation.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('send', _('Send'));
|
||||
// TRANS: Send button for inviting friends
|
||||
$this->submit('send', _m('BUTTON', 'Send'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class OthersettingsAction extends AccountSettingsAction
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Other Settings');
|
||||
return _('Other settings');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,6 +94,7 @@ class PublicAction extends Action
|
||||
}
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Server error when page not found (404)
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
# You have 24 hours to claim your password
|
||||
|
||||
define(MAX_RECOVERY_TIME, 24 * 60 * 60);
|
||||
define('MAX_RECOVERY_TIME', 24 * 60 * 60);
|
||||
|
||||
class RecoverpasswordAction extends Action
|
||||
{
|
||||
@ -262,10 +262,20 @@ class RecoverpasswordAction extends Action
|
||||
# See if it's an unconfirmed email address
|
||||
|
||||
if (!$user) {
|
||||
$confirm_email = Confirm_address::staticGet('address', common_canonical_email($nore));
|
||||
if ($confirm_email && $confirm_email->address_type == 'email') {
|
||||
// Warning: it may actually be legit to have multiple folks
|
||||
// who have claimed, but not yet confirmed, the same address.
|
||||
// We'll only send to the first one that comes up.
|
||||
$confirm_email = new Confirm_address();
|
||||
$confirm_email->address = common_canonical_email($nore);
|
||||
$confirm_email->address_type = 'email';
|
||||
$confirm_email->find();
|
||||
if ($confirm_email->fetch()) {
|
||||
$user = User::staticGet($confirm_email->user_id);
|
||||
} else {
|
||||
$confirm_email = null;
|
||||
}
|
||||
} else {
|
||||
$confirm_email = null;
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
@ -276,9 +286,11 @@ class RecoverpasswordAction extends Action
|
||||
# Try to get an unconfirmed email address if they used a user name
|
||||
|
||||
if (!$user->email && !$confirm_email) {
|
||||
$confirm_email = Confirm_address::staticGet('user_id', $user->id);
|
||||
if ($confirm_email && $confirm_email->address_type != 'email') {
|
||||
# Skip non-email confirmations
|
||||
$confirm_email = new Confirm_address();
|
||||
$confirm_email->user_id = $user->id;
|
||||
$confirm_email->address_type = 'email';
|
||||
$confirm_email->find();
|
||||
if (!$confirm_email->fetch()) {
|
||||
$confirm_email = null;
|
||||
}
|
||||
}
|
||||
@ -294,7 +306,7 @@ class RecoverpasswordAction extends Action
|
||||
$confirm->code = common_confirmation_code(128);
|
||||
$confirm->address_type = 'recover';
|
||||
$confirm->user_id = $user->id;
|
||||
$confirm->address = (isset($user->email)) ? $user->email : $confirm_email->address;
|
||||
$confirm->address = (!empty($user->email)) ? $user->email : $confirm_email->address;
|
||||
|
||||
if (!$confirm->insert()) {
|
||||
common_log_db_error($confirm, 'INSERT', __FILE__);
|
||||
@ -319,7 +331,8 @@ class RecoverpasswordAction extends Action
|
||||
$body .= common_config('site', 'name');
|
||||
$body .= "\n";
|
||||
|
||||
mail_to_user($user, _('Password recovery requested'), $body, $confirm->address);
|
||||
$headers = _mail_prepare_headers('recoverpassword', $user->nickname, $user->nickname);
|
||||
mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address);
|
||||
|
||||
$this->mode = 'sent';
|
||||
$this->msg = _('Instructions for recovering your password ' .
|
||||
|
@ -89,6 +89,7 @@ class RepliesAction extends OwnerDesignAction
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Server error when page not found (404)
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
|
@ -134,6 +134,7 @@ class ShowfavoritesAction extends OwnerDesignAction
|
||||
}
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Server error when page not found (404)
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ class TagAction extends Action
|
||||
$this->notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Server error when page not found (404)
|
||||
$this->serverError(_('No such page'),$code=404);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,8 @@ class UseradminpanelAction extends AdminPanelAction
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('User');
|
||||
// TRANS: User admin panel title
|
||||
return _m('TITLE', 'User');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,5 +266,6 @@ class VersionAction extends Action
|
||||
'Craig Andrews',
|
||||
'mEDI',
|
||||
'Brett Taylor',
|
||||
'Brigitte Schuster');
|
||||
'Brigitte Schuster',
|
||||
'Brion Vibber');
|
||||
}
|
||||
|
@ -67,7 +67,14 @@ class File extends Memcached_DataObject
|
||||
return $att;
|
||||
}
|
||||
|
||||
function saveNew($redir_data, $given_url) {
|
||||
/**
|
||||
* Save a new file record.
|
||||
*
|
||||
* @param array $redir_data lookup data eg from File_redirection::where()
|
||||
* @param string $given_url
|
||||
* @return File
|
||||
*/
|
||||
function saveNew(array $redir_data, $given_url) {
|
||||
$x = new File;
|
||||
$x->url = $given_url;
|
||||
if (!empty($redir_data['protected'])) $x->protected = $redir_data['protected'];
|
||||
@ -77,19 +84,36 @@ class File extends Memcached_DataObject
|
||||
if (isset($redir_data['time']) && $redir_data['time'] > 0) $x->date = intval($redir_data['time']);
|
||||
$file_id = $x->insert();
|
||||
|
||||
$x->saveOembed($redir_data, $given_url);
|
||||
return $x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save embedding information for this file, if applicable.
|
||||
*
|
||||
* Normally this won't need to be called manually, as File::saveNew()
|
||||
* takes care of it.
|
||||
*
|
||||
* @param array $redir_data lookup data eg from File_redirection::where()
|
||||
* @param string $given_url
|
||||
* @return boolean success
|
||||
*/
|
||||
public function saveOembed($redir_data, $given_url)
|
||||
{
|
||||
if (isset($redir_data['type'])
|
||||
&& (('text/html' === substr($redir_data['type'], 0, 9) || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))
|
||||
&& ($oembed_data = File_oembed::_getOembed($given_url))) {
|
||||
|
||||
$fo = File_oembed::staticGet('file_id', $file_id);
|
||||
$fo = File_oembed::staticGet('file_id', $this->id);
|
||||
|
||||
if (empty($fo)) {
|
||||
File_oembed::saveNew($oembed_data, $file_id);
|
||||
File_oembed::saveNew($oembed_data, $this->id);
|
||||
return true;
|
||||
} else {
|
||||
common_log(LOG_WARNING, "Strangely, a File_oembed object exists for new file $file_id", __FILE__);
|
||||
}
|
||||
}
|
||||
return $x;
|
||||
return false;
|
||||
}
|
||||
|
||||
function processNew($given_url, $notice_id=null) {
|
||||
@ -105,6 +129,7 @@ class File extends Memcached_DataObject
|
||||
$redir_url = $redir_data['url'];
|
||||
} elseif (is_string($redir_data)) {
|
||||
$redir_url = $redir_data;
|
||||
$redir_data = array();
|
||||
} else {
|
||||
throw new ServerException("Can't process url '$given_url'");
|
||||
}
|
||||
@ -169,7 +194,11 @@ class File extends Memcached_DataObject
|
||||
{
|
||||
require_once 'MIME/Type/Extension.php';
|
||||
$mte = new MIME_Type_Extension();
|
||||
$ext = $mte->getExtension($mimetype);
|
||||
try {
|
||||
$ext = $mte->getExtension($mimetype);
|
||||
} catch ( Exception $e) {
|
||||
$ext = strtolower(preg_replace('/\W/', '', $mimetype));
|
||||
}
|
||||
$nickname = $profile->nickname;
|
||||
$datestamp = strftime('%Y%m%dT%H%M%S', time());
|
||||
$random = strtolower(common_confirmation_code(32));
|
||||
@ -256,7 +285,7 @@ class File extends Memcached_DataObject
|
||||
$enclosure->mimetype=$this->mimetype;
|
||||
|
||||
if(! isset($this->filename)){
|
||||
$notEnclosureMimeTypes = array('text/html','application/xhtml+xml');
|
||||
$notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml');
|
||||
$mimetype = strtolower($this->mimetype);
|
||||
$semicolon = strpos($mimetype,';');
|
||||
if($semicolon){
|
||||
|
@ -81,6 +81,12 @@ class File_oembed extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save embedding info for a new file.
|
||||
*
|
||||
* @param object $data Services_oEmbed_Object_*
|
||||
* @param int $file_id
|
||||
*/
|
||||
function saveNew($data, $file_id) {
|
||||
$file_oembed = new File_oembed;
|
||||
$file_oembed->file_id = $file_id;
|
||||
|
@ -58,24 +58,30 @@ class File_redirection extends Memcached_DataObject
|
||||
return $request;
|
||||
}
|
||||
|
||||
function _redirectWhere_imp($short_url, $redirs = 10, $protected = false) {
|
||||
/**
|
||||
* Check if this URL is a redirect and return redir info.
|
||||
*
|
||||
* Most code should call File_redirection::where instead, to check if we
|
||||
* already know that redirection and avoid extra hits to the web.
|
||||
*
|
||||
* The URL is hit and any redirects are followed, up to 10 levels or until
|
||||
* a protected URL is reached.
|
||||
*
|
||||
* @param string $in_url
|
||||
* @return mixed one of:
|
||||
* string - target URL, if this is a direct link or can't be followed
|
||||
* array - redirect info if this is an *unknown* redirect:
|
||||
* associative array with the following elements:
|
||||
* code: HTTP status code
|
||||
* redirects: count of redirects followed
|
||||
* url: URL string of final target
|
||||
* type (optional): MIME type from Content-Type header
|
||||
* size (optional): byte size from Content-Length header
|
||||
* time (optional): timestamp from Last-Modified header
|
||||
*/
|
||||
public function lookupWhere($short_url, $redirs = 10, $protected = false) {
|
||||
if ($redirs < 0) return false;
|
||||
|
||||
// let's see if we know this...
|
||||
$a = File::staticGet('url', $short_url);
|
||||
|
||||
if (!empty($a)) {
|
||||
// this is a direct link to $a->url
|
||||
return $a->url;
|
||||
} else {
|
||||
$b = File_redirection::staticGet('url', $short_url);
|
||||
if (!empty($b)) {
|
||||
// this is a redirect to $b->file_id
|
||||
$a = File::staticGet('id', $b->file_id);
|
||||
return $a->url;
|
||||
}
|
||||
}
|
||||
|
||||
if(strpos($short_url,'://') === false){
|
||||
return $short_url;
|
||||
}
|
||||
@ -93,12 +99,13 @@ class File_redirection extends Memcached_DataObject
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Invalid URL or failure to reach server
|
||||
common_log(LOG_ERR, "Error while following redirects for $short_url: " . $e->getMessage());
|
||||
return $short_url;
|
||||
}
|
||||
|
||||
if ($response->getRedirectCount() && File::isProtected($response->getUrl())) {
|
||||
// Bump back up the redirect chain until we find a non-protected URL
|
||||
return self::_redirectWhere_imp($short_url, $response->getRedirectCount() - 1, true);
|
||||
return self::lookupWhere($short_url, $response->getRedirectCount() - 1, true);
|
||||
}
|
||||
|
||||
$ret = array('code' => $response->getStatus()
|
||||
@ -115,11 +122,60 @@ class File_redirection extends Memcached_DataObject
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function where($in_url) {
|
||||
$ret = File_redirection::_redirectWhere_imp($in_url);
|
||||
/**
|
||||
* Check if this URL is a redirect and return redir info.
|
||||
* If a File record is present for this URL, it is not considered a redirect.
|
||||
* If a File_redirection record is present for this URL, the recorded target is returned.
|
||||
*
|
||||
* If no File or File_redirect record is present, the URL is hit and any
|
||||
* redirects are followed, up to 10 levels or until a protected URL is
|
||||
* reached.
|
||||
*
|
||||
* @param string $in_url
|
||||
* @return mixed one of:
|
||||
* string - target URL, if this is a direct link or a known redirect
|
||||
* array - redirect info if this is an *unknown* redirect:
|
||||
* associative array with the following elements:
|
||||
* code: HTTP status code
|
||||
* redirects: count of redirects followed
|
||||
* url: URL string of final target
|
||||
* type (optional): MIME type from Content-Type header
|
||||
* size (optional): byte size from Content-Length header
|
||||
* time (optional): timestamp from Last-Modified header
|
||||
*/
|
||||
public function where($in_url) {
|
||||
// let's see if we know this...
|
||||
$a = File::staticGet('url', $in_url);
|
||||
|
||||
if (!empty($a)) {
|
||||
// this is a direct link to $a->url
|
||||
return $a->url;
|
||||
} else {
|
||||
$b = File_redirection::staticGet('url', $in_url);
|
||||
if (!empty($b)) {
|
||||
// this is a redirect to $b->file_id
|
||||
$a = File::staticGet('id', $b->file_id);
|
||||
return $a->url;
|
||||
}
|
||||
}
|
||||
|
||||
$ret = File_redirection::lookupWhere($in_url);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten a URL with the current user's configured shortening
|
||||
* options, if applicable.
|
||||
*
|
||||
* If it cannot be shortened or the "short" URL is longer than the
|
||||
* original, the original is returned.
|
||||
*
|
||||
* If the referenced item has not been seen before, embedding data
|
||||
* may be saved.
|
||||
*
|
||||
* @param string $long_url
|
||||
* @return string
|
||||
*/
|
||||
function makeShort($long_url) {
|
||||
|
||||
$canon = File_redirection::_canonUrl($long_url);
|
||||
@ -141,11 +197,20 @@ class File_redirection extends Memcached_DataObject
|
||||
// store it
|
||||
$file = File::staticGet('url', $long_url);
|
||||
if (empty($file)) {
|
||||
// Check if the target URL is itself a redirect...
|
||||
$redir_data = File_redirection::where($long_url);
|
||||
$file = File::saveNew($redir_data, $long_url);
|
||||
$file_id = $file->id;
|
||||
if (!empty($redir_data['oembed']['json'])) {
|
||||
File_oembed::saveNew($redir_data['oembed']['json'], $file_id);
|
||||
if (is_array($redir_data)) {
|
||||
// We haven't seen the target URL before.
|
||||
// Save file and embedding data about it!
|
||||
$file = File::saveNew($redir_data, $long_url);
|
||||
$file_id = $file->id;
|
||||
if (!empty($redir_data['oembed']['json'])) {
|
||||
File_oembed::saveNew($redir_data['oembed']['json'], $file_id);
|
||||
}
|
||||
} else if (is_string($redir_data)) {
|
||||
// The file is a known redirect target.
|
||||
$file = File::staticGet('url', $redir_data);
|
||||
$file_id = $file->id;
|
||||
}
|
||||
} else {
|
||||
$file_id = $file->id;
|
||||
|
@ -34,7 +34,7 @@ class Group_alias extends Memcached_DataObject
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Group_alias',$k,$v); }
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Group_alias',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
@ -1128,6 +1128,7 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
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);
|
||||
@ -1143,13 +1144,14 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
|
||||
$xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE));
|
||||
$xs->element('updated', null, common_date_w3dtf($this->created));
|
||||
}
|
||||
|
||||
if ($source) {
|
||||
$xs->elementEnd('source');
|
||||
}
|
||||
|
||||
$xs->element('title', null, $this->content);
|
||||
$xs->element('title', null, common_xml_safe_str($this->content));
|
||||
|
||||
if ($author) {
|
||||
$xs->raw($profile->asAtomAuthor());
|
||||
@ -1225,7 +1227,11 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
$xs->element('content', array('type' => 'html'), $this->rendered);
|
||||
$xs->element(
|
||||
'content',
|
||||
array('type' => 'html'),
|
||||
common_xml_safe_str($this->rendered)
|
||||
);
|
||||
|
||||
$tag = new Notice_tag();
|
||||
$tag->notice_id = $this->id;
|
||||
|
@ -147,14 +147,16 @@ class Profile extends Memcached_DataObject
|
||||
return ($this->fullname) ? $this->fullname : $this->nickname;
|
||||
}
|
||||
|
||||
# Get latest notice on or before date; default now
|
||||
function getCurrentNotice($dt=null)
|
||||
/**
|
||||
* Get the most recent notice posted by this user, if any.
|
||||
*
|
||||
* @return mixed Notice or null
|
||||
*/
|
||||
function getCurrentNotice()
|
||||
{
|
||||
$notice = new Notice();
|
||||
$notice->profile_id = $this->id;
|
||||
if ($dt) {
|
||||
$notice->whereAdd('created < "' . $dt . '"');
|
||||
}
|
||||
// @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)) {
|
||||
|
@ -132,13 +132,18 @@ class User extends Memcached_DataObject
|
||||
return !in_array($nickname, $blacklist);
|
||||
}
|
||||
|
||||
function getCurrentNotice($dt=null)
|
||||
/**
|
||||
* Get the most recent notice posted by this user, if any.
|
||||
*
|
||||
* @return mixed Notice or null
|
||||
*/
|
||||
function getCurrentNotice()
|
||||
{
|
||||
$profile = $this->getProfile();
|
||||
if (!$profile) {
|
||||
return null;
|
||||
}
|
||||
return $profile->getCurrentNotice($dt);
|
||||
return $profile->getCurrentNotice();
|
||||
}
|
||||
|
||||
function getCarrier()
|
||||
@ -206,6 +211,7 @@ class User extends Memcached_DataObject
|
||||
if(! User::allowed_nickname($nickname)){
|
||||
common_log(LOG_WARNING, sprintf("Attempted to register a nickname that is not allowed: %s", $profile->nickname),
|
||||
__FILE__);
|
||||
return false;
|
||||
}
|
||||
$profile->profileurl = common_profile_url($nickname);
|
||||
|
||||
|
@ -295,7 +295,7 @@ class User_group extends Memcached_DataObject
|
||||
}
|
||||
|
||||
// If not, check local groups.
|
||||
|
||||
|
||||
$group = Local_group::staticGet('nickname', $nickname);
|
||||
if (!empty($group)) {
|
||||
return User_group::staticGet('id', $group->group_id);
|
||||
@ -371,16 +371,15 @@ class User_group extends Memcached_DataObject
|
||||
|
||||
if ($source) {
|
||||
$xs->elementStart('source');
|
||||
$xs->element('id', null, $this->permalink());
|
||||
$xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
|
||||
$xs->element('link', array('href' => $this->permalink()));
|
||||
}
|
||||
|
||||
if ($source) {
|
||||
$xs->element('updated', null, $this->modified);
|
||||
$xs->elementEnd('source');
|
||||
}
|
||||
|
||||
$xs->element('title', null, $this->nickname);
|
||||
$xs->element('summary', null, $this->description);
|
||||
$xs->element('summary', null, common_xml_safe_str($this->description));
|
||||
|
||||
$xs->element('link', array('rel' => 'alternate',
|
||||
'href' => $this->permalink()));
|
||||
@ -390,7 +389,11 @@ class User_group extends Memcached_DataObject
|
||||
$xs->element('published', null, common_date_w3dtf($this->created));
|
||||
$xs->element('updated', null, common_date_w3dtf($this->modified));
|
||||
|
||||
$xs->element('content', array('type' => 'html'), $this->description);
|
||||
$xs->element(
|
||||
'content',
|
||||
array('type' => 'html'),
|
||||
common_xml_safe_str($this->description)
|
||||
);
|
||||
|
||||
$xs->elementEnd('entry');
|
||||
|
||||
@ -455,7 +458,7 @@ class User_group extends Memcached_DataObject
|
||||
$group = new User_group();
|
||||
|
||||
$group->query('BEGIN');
|
||||
|
||||
|
||||
if (empty($uri)) {
|
||||
// fill in later...
|
||||
$uri = null;
|
||||
@ -483,7 +486,7 @@ class User_group extends Memcached_DataObject
|
||||
$result = $group->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($group, 'UPDATE', __FILE__);
|
||||
throw new ServerException(_('Could not set group uri.'));
|
||||
throw new ServerException(_('Could not set group URI.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ class User_username extends Memcached_DataObject
|
||||
|
||||
// now define the keys.
|
||||
function keys() {
|
||||
return array('provider_name', 'username');
|
||||
return array('provider_name' => 'K', 'username' => 'K');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ $config['sphinx']['port'] = 3312;
|
||||
//
|
||||
// $config['twitterimport']['enabled'] = true;
|
||||
|
||||
// Twitter OAuth settings
|
||||
// Twitter OAuth settings. Documentation is at http://apiwiki.twitter.com/OAuth-FAQ
|
||||
// $config['twitter']['consumer_key'] = 'YOURKEY';
|
||||
// $config['twitter']['consumer_secret'] = 'YOURSECRET';
|
||||
|
||||
@ -268,6 +268,8 @@ $config['sphinx']['port'] = 3312;
|
||||
// Support for file uploads (attachments),
|
||||
// select supported mimetypes and quotas (in bytes)
|
||||
// $config['attachments']['supported'] = array('image/png', 'application/ogg');
|
||||
// $config['attachments']['supported'] = true; //allow all file types to be uploaded
|
||||
|
||||
// $config['attachments']['file_quota'] = 5000000;
|
||||
// $config['attachments']['user_quota'] = 50000000;
|
||||
// $config['attachments']['monthly_quota'] = 15000000;
|
||||
|
103
index.php
103
index.php
@ -37,8 +37,6 @@ define('INSTALLDIR', dirname(__FILE__));
|
||||
define('STATUSNET', true);
|
||||
define('LACONICA', true); // compatibility
|
||||
|
||||
require_once INSTALLDIR . '/lib/common.php';
|
||||
|
||||
$user = null;
|
||||
$action = null;
|
||||
|
||||
@ -68,52 +66,69 @@ function getPath($req)
|
||||
*/
|
||||
function handleError($error)
|
||||
{
|
||||
if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
$logmsg = "PEAR error: " . $error->getMessage();
|
||||
if (common_config('site', 'logdebug')) {
|
||||
$logmsg .= " : ". $error->getDebugInfo();
|
||||
}
|
||||
// DB queries often end up with a lot of newlines; merge to a single line
|
||||
// for easier grepability...
|
||||
$logmsg = str_replace("\n", " ", $logmsg);
|
||||
common_log(LOG_ERR, $logmsg);
|
||||
|
||||
// @fixme backtrace output should be consistent with exception handling
|
||||
if (common_config('site', 'logdebug')) {
|
||||
$bt = $error->getBacktrace();
|
||||
foreach ($bt as $n => $line) {
|
||||
common_log(LOG_ERR, formatBacktraceLine($n, $line));
|
||||
if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ($error instanceof DB_DataObject_Error
|
||||
|| $error instanceof DB_Error
|
||||
) {
|
||||
$msg = sprintf(
|
||||
_(
|
||||
'The database for %s isn\'t responding correctly, '.
|
||||
'so the site won\'t work properly. '.
|
||||
'The site admins probably know about the problem, '.
|
||||
'but you can contact them at %s to make sure. '.
|
||||
'Otherwise, wait a few minutes and try again.'
|
||||
),
|
||||
common_config('site', 'name'),
|
||||
common_config('site', 'email')
|
||||
);
|
||||
} else {
|
||||
$msg = _(
|
||||
'An important error occured, probably related to email setup. '.
|
||||
'Check logfiles for more info..'
|
||||
);
|
||||
}
|
||||
|
||||
$dac = new DBErrorAction($msg, 500);
|
||||
$dac->showPage();
|
||||
$logmsg = "PEAR error: " . $error->getMessage();
|
||||
if ($error instanceof PEAR_Exception && common_config('site', 'logdebug')) {
|
||||
$logmsg .= " : ". $error->toText();
|
||||
}
|
||||
// DB queries often end up with a lot of newlines; merge to a single line
|
||||
// for easier grepability...
|
||||
$logmsg = str_replace("\n", " ", $logmsg);
|
||||
common_log(LOG_ERR, $logmsg);
|
||||
|
||||
// @fixme backtrace output should be consistent with exception handling
|
||||
if (common_config('site', 'logdebug')) {
|
||||
$bt = $error->getTrace();
|
||||
foreach ($bt as $n => $line) {
|
||||
common_log(LOG_ERR, formatBacktraceLine($n, $line));
|
||||
}
|
||||
}
|
||||
if ($error instanceof DB_DataObject_Error
|
||||
|| $error instanceof DB_Error
|
||||
|| ($error instanceof PEAR_Exception && $error->getCode() == -24)
|
||||
) {
|
||||
//If we run into a DB error, assume we can't connect to the DB at all
|
||||
//so set the current user to null, so we don't try to access the DB
|
||||
//while rendering the error page.
|
||||
global $_cur;
|
||||
$_cur = null;
|
||||
|
||||
$msg = sprintf(
|
||||
_(
|
||||
'The database for %s isn\'t responding correctly, '.
|
||||
'so the site won\'t work properly. '.
|
||||
'The site admins probably know about the problem, '.
|
||||
'but you can contact them at %s to make sure. '.
|
||||
'Otherwise, wait a few minutes and try again.'
|
||||
),
|
||||
common_config('site', 'name'),
|
||||
common_config('site', 'email')
|
||||
);
|
||||
} else {
|
||||
$msg = _(
|
||||
'An important error occured, probably related to email setup. '.
|
||||
'Check logfiles for more info..'
|
||||
);
|
||||
}
|
||||
|
||||
$dac = new DBErrorAction($msg, 500);
|
||||
$dac->showPage();
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo _('An error occurred.');
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
set_exception_handler('handleError');
|
||||
|
||||
require_once INSTALLDIR . '/lib/common.php';
|
||||
|
||||
/**
|
||||
* Format a backtrace line for debug output roughly like debug_print_backtrace() does.
|
||||
* Exceptions already have this built in, but PEAR error objects just give us the array.
|
||||
@ -238,10 +253,6 @@ function main()
|
||||
return;
|
||||
}
|
||||
|
||||
// For database errors
|
||||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
|
||||
|
||||
// Make sure RW database is setup
|
||||
|
||||
setupRW();
|
||||
|
@ -426,39 +426,69 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->elementStart('ul', array('class' => 'nav'));
|
||||
if (Event::handle('StartPrimaryNav', array($this))) {
|
||||
if ($user) {
|
||||
// TRANS: Tooltip for main menu option "Personal"
|
||||
$tooltip = _m('TOOLTIP', 'Personal profile and friends timeline');
|
||||
// TRANS: Main menu option when logged in for access to personal profile and friends timeline
|
||||
$this->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
||||
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
||||
_m('MENU', 'Personal'), $tooltip, false, 'nav_home');
|
||||
// TRANS: Tooltip for main menu option "Account"
|
||||
$tooltip = _m('TOOLTIP', 'Change your email, avatar, password, profile');
|
||||
// TRANS: Main menu option when logged in for access to user settings
|
||||
$this->menuItem(common_local_url('profilesettings'),
|
||||
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
||||
_('Account'), $tooltip, false, 'nav_account');
|
||||
// TRANS: Tooltip for main menu option "Services"
|
||||
$tooltip = _m('TOOLTIP', 'Connect to services');
|
||||
// TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
|
||||
$this->menuItem(common_local_url('oauthconnectionssettings'),
|
||||
_('Connect'), _('Connect to services'), false, 'nav_connect');
|
||||
_('Connect'), $tooltip, false, 'nav_connect');
|
||||
if ($user->hasRight(Right::CONFIGURESITE)) {
|
||||
// TRANS: Tooltip for menu option "Admin"
|
||||
$tooltip = _m('TOOLTIP', 'Change site configuration');
|
||||
// TRANS: Main menu option when logged in and site admin for access to site configuration
|
||||
$this->menuItem(common_local_url('siteadminpanel'),
|
||||
_('Admin'), _('Change site configuration'), false, 'nav_admin');
|
||||
_m('MENU', 'Admin'), $tooltip, false, 'nav_admin');
|
||||
}
|
||||
if (common_config('invite', 'enabled')) {
|
||||
// TRANS: Tooltip for main menu option "Invite"
|
||||
$tooltip = _m('TOOLTIP', 'Invite friends and colleagues to join you on %s');
|
||||
// TRANS: Main menu option when logged in and invitations are allowed for inviting new users
|
||||
$this->menuItem(common_local_url('invite'),
|
||||
_('Invite'),
|
||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||
_m('MENU', 'Invite'),
|
||||
sprintf($tooltip,
|
||||
common_config('site', 'name')),
|
||||
false, 'nav_invitecontact');
|
||||
}
|
||||
// TRANS: Tooltip for main menu option "Logout"
|
||||
$tooltip = _m('TOOLTIP', 'Logout from the site');
|
||||
// TRANS: Main menu option when logged in to log out the current user
|
||||
$this->menuItem(common_local_url('logout'),
|
||||
_('Logout'), _('Logout from the site'), false, 'nav_logout');
|
||||
_m('MENU', 'Logout'), $tooltip, false, 'nav_logout');
|
||||
}
|
||||
else {
|
||||
if (!common_config('site', 'closed')) {
|
||||
// TRANS: Tooltip for main menu option "Register"
|
||||
$tooltip = _m('TOOLTIP', 'Create an account');
|
||||
// TRANS: Main menu option when not logged in to register a new account
|
||||
$this->menuItem(common_local_url('register'),
|
||||
_('Register'), _('Create an account'), false, 'nav_register');
|
||||
_m('MENU', 'Register'), $tooltip, false, 'nav_register');
|
||||
}
|
||||
// TRANS: Tooltip for main menu option "Login"
|
||||
$tooltip = _m('TOOLTIP', 'Login to the site');
|
||||
// TRANS: Main menu option when not logged in to log in
|
||||
$this->menuItem(common_local_url('login'),
|
||||
_('Login'), _('Login to the site'), false, 'nav_login');
|
||||
_m('MENU', 'Login'), $tooltip, false, 'nav_login');
|
||||
}
|
||||
// TRANS: Tooltip for main menu option "Help"
|
||||
$tooltip = _m('TOOLTIP', 'Help me!');
|
||||
// TRANS: Main menu option for help on the StatusNet site
|
||||
$this->menuItem(common_local_url('doc', array('title' => 'help')),
|
||||
_('Help'), _('Help me!'), false, 'nav_help');
|
||||
_m('MENU', 'Help'), $tooltip, false, 'nav_help');
|
||||
if ($user || !common_config('site', 'private')) {
|
||||
// TRANS: Tooltip for main menu option "Search"
|
||||
$tooltip = _m('TOOLTIP', 'Search for people or text');
|
||||
// TRANS: Main menu option when logged in or when the StatusNet instance is not private
|
||||
$this->menuItem(common_local_url('peoplesearch'),
|
||||
_('Search'), _('Search for people or text'), false, 'nav_search');
|
||||
_m('MENU', 'Search'), $tooltip, false, 'nav_search');
|
||||
}
|
||||
Event::handle('EndPrimaryNav', array($this));
|
||||
}
|
||||
@ -479,6 +509,7 @@ class Action extends HTMLOutputter // lawsuit
|
||||
if ($text) {
|
||||
$this->elementStart('dl', array('id' => 'site_notice',
|
||||
'class' => 'system_notice'));
|
||||
// TRANS: DT element for site notice. String is hidden in default CSS.
|
||||
$this->element('dt', null, _('Site notice'));
|
||||
$this->elementStart('dd', null);
|
||||
$this->raw($text);
|
||||
|
@ -78,7 +78,7 @@ class PoCoAddress
|
||||
if (!empty($this->formatted)) {
|
||||
$xs = new XMLStringer(true);
|
||||
$xs->elementStart('poco:address');
|
||||
$xs->element('poco:formatted', null, $this->formatted);
|
||||
$xs->element('poco:formatted', null, common_xml_safe_str($this->formatted));
|
||||
$xs->elementEnd('poco:address');
|
||||
return $xs->getString();
|
||||
}
|
||||
@ -279,7 +279,7 @@ class PoCo
|
||||
);
|
||||
|
||||
if (!empty($this->note)) {
|
||||
$xs->element('poco:note', null, $this->note);
|
||||
$xs->element('poco:note', null, common_xml_safe_str($this->note));
|
||||
}
|
||||
|
||||
if (!empty($this->address)) {
|
||||
@ -805,7 +805,6 @@ class ActivityObject
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
function asString($tag='activity:object')
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
@ -817,16 +816,28 @@ class ActivityObject
|
||||
$xs->element(self::ID, null, $this->id);
|
||||
|
||||
if (!empty($this->title)) {
|
||||
$xs->element(self::TITLE, null, $this->title);
|
||||
$xs->element(
|
||||
self::TITLE,
|
||||
null,
|
||||
common_xml_safe_str($this->title)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->summary)) {
|
||||
$xs->element(self::SUMMARY, null, $this->summary);
|
||||
$xs->element(
|
||||
self::SUMMARY,
|
||||
null,
|
||||
common_xml_safe_str($this->summary)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->content)) {
|
||||
// XXX: assuming HTML content here
|
||||
$xs->element(ActivityUtils::CONTENT, array('type' => 'html'), $this->content);
|
||||
$xs->element(
|
||||
ActivityUtils::CONTENT,
|
||||
array('type' => 'html'),
|
||||
common_xml_safe_str($this->content)
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->link)) {
|
||||
|
@ -69,6 +69,7 @@ class AdminPanelAction extends Action
|
||||
// User must be logged in.
|
||||
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Client error message
|
||||
$this->clientError(_('Not logged in.'));
|
||||
return false;
|
||||
}
|
||||
@ -93,6 +94,7 @@ class AdminPanelAction extends Action
|
||||
// User must have the right to change admin settings
|
||||
|
||||
if (!$user->hasRight(Right::CONFIGURESITE)) {
|
||||
// TRANS: Client error message
|
||||
$this->clientError(_('You cannot make changes to this site.'));
|
||||
return false;
|
||||
}
|
||||
@ -104,6 +106,7 @@ class AdminPanelAction extends Action
|
||||
$name = mb_substr($name, 0, -10);
|
||||
|
||||
if (!self::canAdmin($name)) {
|
||||
// TRANS: Client error message
|
||||
$this->clientError(_('Changes to that panel are not allowed.'), 403);
|
||||
return false;
|
||||
}
|
||||
@ -134,6 +137,7 @@ class AdminPanelAction extends Action
|
||||
Config::loadSettings();
|
||||
|
||||
$this->success = true;
|
||||
// TRANS: Message after successful saving of administrative settings.
|
||||
$this->msg = _('Settings saved.');
|
||||
} catch (Exception $e) {
|
||||
$this->success = false;
|
||||
@ -221,6 +225,7 @@ class AdminPanelAction extends Action
|
||||
|
||||
function showForm()
|
||||
{
|
||||
// TRANS: Client error message
|
||||
$this->clientError(_('showForm() not implemented.'));
|
||||
return;
|
||||
}
|
||||
@ -250,6 +255,7 @@ class AdminPanelAction extends Action
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
// TRANS: Client error message
|
||||
$this->clientError(_('saveSettings() not implemented.'));
|
||||
return;
|
||||
}
|
||||
@ -273,6 +279,7 @@ class AdminPanelAction extends Action
|
||||
$result = $config->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($config, 'DELETE', __FILE__);
|
||||
// TRANS: Client error message
|
||||
$this->clientError(_("Unable to delete design setting."));
|
||||
return null;
|
||||
}
|
||||
@ -337,43 +344,67 @@ class AdminPanelNav extends Widget
|
||||
if (Event::handle('StartAdminPanelNav', array($this))) {
|
||||
|
||||
if (AdminPanelAction::canAdmin('site')) {
|
||||
$this->out->menuItem(common_local_url('siteadminpanel'), _('Site'),
|
||||
_('Basic site configuration'), $action_name == 'siteadminpanel', 'nav_site_admin_panel');
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Basic site configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('siteadminpanel'), _m('MENU', 'Site'),
|
||||
$menu_title, $action_name == 'siteadminpanel', 'nav_site_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('design')) {
|
||||
$this->out->menuItem(common_local_url('designadminpanel'), _('Design'),
|
||||
_('Design configuration'), $action_name == 'designadminpanel', 'nav_design_admin_panel');
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Design configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('designadminpanel'), _m('MENU', 'Design'),
|
||||
$menu_title, $action_name == 'designadminpanel', 'nav_design_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('user')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('User configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('useradminpanel'), _('User'),
|
||||
_('User configuration'), $action_name == 'useradminpanel', 'nav_user_admin_panel');
|
||||
$menu_title, $action_name == 'useradminpanel', 'nav_user_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('access')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Access configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('accessadminpanel'), _('Access'),
|
||||
_('Access configuration'), $action_name == 'accessadminpanel', 'nav_access_admin_panel');
|
||||
$menu_title, $action_name == 'accessadminpanel', 'nav_access_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('paths')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Paths configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('pathsadminpanel'), _('Paths'),
|
||||
_('Paths configuration'), $action_name == 'pathsadminpanel', 'nav_paths_admin_panel');
|
||||
$menu_title, $action_name == 'pathsadminpanel', 'nav_paths_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('sessions')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Sessions configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('sessionsadminpanel'), _('Sessions'),
|
||||
_('Sessions configuration'), $action_name == 'sessionsadminpanel', 'nav_sessions_admin_panel');
|
||||
$menu_title, $action_name == 'sessionsadminpanel', 'nav_sessions_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('sitenotice')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Edit site notice');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('sitenoticeadminpanel'), _('Site notice'),
|
||||
_('Edit site notice'), $action_name == 'sitenoticeadminpanel', 'nav_sitenotice_admin_panel');
|
||||
$menu_title, $action_name == 'sitenoticeadminpanel', 'nav_sitenotice_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('snapshot')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Snapshots configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('snapshotadminpanel'), _('Snapshots'),
|
||||
_('Snapshots configuration'), $action_name == 'snapshotadminpanel', 'nav_snapshot_admin_panel');
|
||||
$menu_title, $action_name == 'snapshotadminpanel', 'nav_snapshot_admin_panel');
|
||||
}
|
||||
|
||||
Event::handle('EndAdminPanelNav', array($this));
|
||||
|
@ -491,7 +491,7 @@ class ApiAction extends Action
|
||||
$this->showXmlAttachments($twitter_status['attachments']);
|
||||
break;
|
||||
case 'geo':
|
||||
$this->showGeoRSS($value);
|
||||
$this->showGeoXML($value);
|
||||
break;
|
||||
case 'retweeted_status':
|
||||
$this->showTwitterXmlStatus($value, 'retweeted_status');
|
||||
@ -539,7 +539,7 @@ class ApiAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function showGeoRSS($geo)
|
||||
function showGeoXML($geo)
|
||||
{
|
||||
if (empty($geo)) {
|
||||
// empty geo element
|
||||
@ -551,6 +551,17 @@ class ApiAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function showGeoRSS($geo)
|
||||
{
|
||||
if (!empty($geo)) {
|
||||
$this->element(
|
||||
'georss:point',
|
||||
null,
|
||||
$geo['coordinates'][0] . ' ' . $geo['coordinates'][1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function showTwitterRssItem($entry)
|
||||
{
|
||||
$this->elementStart('item');
|
||||
@ -619,13 +630,25 @@ class ApiAction extends Action
|
||||
$this->endDocument('xml');
|
||||
}
|
||||
|
||||
function showRssTimeline($notice, $title, $link, $subtitle, $suplink=null, $logo=null)
|
||||
function showRssTimeline($notice, $title, $link, $subtitle, $suplink = null, $logo = null, $self = null)
|
||||
{
|
||||
|
||||
$this->initDocument('rss');
|
||||
|
||||
$this->element('title', null, $title);
|
||||
$this->element('link', null, $link);
|
||||
|
||||
if (!is_null($self)) {
|
||||
$this->element(
|
||||
'atom:link',
|
||||
array(
|
||||
'type' => 'application/rss+xml',
|
||||
'href' => $self,
|
||||
'rel' => 'self'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_null($suplink)) {
|
||||
// For FriendFeed's SUP protocol
|
||||
$this->element('link', array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||
@ -732,8 +755,12 @@ class ApiAction extends Action
|
||||
function showTwitterAtomEntry($entry)
|
||||
{
|
||||
$this->elementStart('entry');
|
||||
$this->element('title', null, $entry['title']);
|
||||
$this->element('content', array('type' => 'html'), $entry['content']);
|
||||
$this->element('title', null, common_xml_safe_str($entry['title']));
|
||||
$this->element(
|
||||
'content',
|
||||
array('type' => 'html'),
|
||||
common_xml_safe_str($entry['content'])
|
||||
);
|
||||
$this->element('id', null, $entry['id']);
|
||||
$this->element('published', null, $entry['published']);
|
||||
$this->element('updated', null, $entry['updated']);
|
||||
@ -848,7 +875,7 @@ class ApiAction extends Action
|
||||
|
||||
$this->initDocument('atom');
|
||||
|
||||
$this->element('title', null, $title);
|
||||
$this->element('title', null, common_xml_safe_str($title));
|
||||
$this->element('id', null, $id);
|
||||
$this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
|
||||
|
||||
@ -858,7 +885,7 @@ class ApiAction extends Action
|
||||
}
|
||||
|
||||
$this->element('updated', null, common_date_iso8601('now'));
|
||||
$this->element('subtitle', null, $subtitle);
|
||||
$this->element('subtitle', null, common_xml_safe_str($subtitle));
|
||||
|
||||
if (is_array($group)) {
|
||||
foreach ($group as $g) {
|
||||
@ -1138,7 +1165,14 @@ class ApiAction extends Action
|
||||
function initTwitterRss()
|
||||
{
|
||||
$this->startXML();
|
||||
$this->elementStart('rss', array('version' => '2.0', 'xmlns:atom'=>'http://www.w3.org/2005/Atom'));
|
||||
$this->elementStart(
|
||||
'rss',
|
||||
array(
|
||||
'version' => '2.0',
|
||||
'xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
||||
'xmlns:georss' => 'http://www.georss.org/georss'
|
||||
)
|
||||
);
|
||||
$this->elementStart('channel');
|
||||
Event::handle('StartApiRss', array($this));
|
||||
}
|
||||
@ -1336,8 +1370,27 @@ class ApiAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function getSelfUri($action, $aargs)
|
||||
/**
|
||||
* Calculate the complete URI that called up this action. Used for
|
||||
* Atom rel="self" links. Warning: this is funky.
|
||||
*
|
||||
* @return string URL a URL suitable for rel="self" Atom links
|
||||
*/
|
||||
function getSelfUri()
|
||||
{
|
||||
$action = mb_substr(get_class($this), 0, -6); // remove 'Action'
|
||||
|
||||
$id = $this->arg('id');
|
||||
$aargs = array('format' => $this->format);
|
||||
if (!empty($id)) {
|
||||
$aargs['id'] = $id;
|
||||
}
|
||||
|
||||
$tag = $this->arg('tag');
|
||||
if (!empty($tag)) {
|
||||
$aargs['tag'] = $tag;
|
||||
}
|
||||
|
||||
parse_str($_SERVER['QUERY_STRING'], $params);
|
||||
$pstring = '';
|
||||
if (!empty($params)) {
|
||||
|
@ -178,7 +178,7 @@ class Atom10Feed extends XMLStringer
|
||||
|
||||
$this->element(
|
||||
'generator', array(
|
||||
'url' => 'http://status.net',
|
||||
'uri' => 'http://status.net',
|
||||
'version' => STATUSNET_VERSION
|
||||
),
|
||||
'StatusNet'
|
||||
|
@ -69,13 +69,17 @@ abstract class AuthenticationPlugin extends Plugin
|
||||
/**
|
||||
* Automatically register a user when they attempt to login with valid credentials.
|
||||
* User::register($data) is a very useful method for this implementation
|
||||
* @param username
|
||||
* @param username username (that is used to login and find the user in the authentication provider) of the user to be registered
|
||||
* @param nickname nickname of the user in the SN system. If nickname is null, then set nickname = username
|
||||
* @return mixed instance of User, or false (if user couldn't be created)
|
||||
*/
|
||||
function autoRegister($username)
|
||||
function autoRegister($username, $nickname = null)
|
||||
{
|
||||
if(is_null($nickname)){
|
||||
$nickname = $username;
|
||||
}
|
||||
$registration_data = array();
|
||||
$registration_data['nickname'] = $username ;
|
||||
$registration_data['nickname'] = $nickname;
|
||||
return User::register($registration_data);
|
||||
}
|
||||
|
||||
@ -92,6 +96,21 @@ abstract class AuthenticationPlugin extends Plugin
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a username, suggest what the nickname should be
|
||||
* Used during autoregistration
|
||||
* Useful if your usernames are ugly, and you want to suggest
|
||||
* nice looking nicknames when users initially sign on
|
||||
* All nicknames returned by this function should be valid
|
||||
* implementations may want to use common_nicknamize() to ensure validity
|
||||
* @param username
|
||||
* @return string nickname
|
||||
*/
|
||||
function suggestNicknameForUsername($username)
|
||||
{
|
||||
return common_nicknamize($username);
|
||||
}
|
||||
|
||||
//------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\
|
||||
function onInitializePlugin(){
|
||||
if(!isset($this->provider_name)){
|
||||
@ -108,10 +127,22 @@ abstract class AuthenticationPlugin extends Plugin
|
||||
function onAutoRegister($nickname, $provider_name, &$user)
|
||||
{
|
||||
if($provider_name == $this->provider_name && $this->autoregistration){
|
||||
$user = $this->autoregister($nickname);
|
||||
if($user){
|
||||
User_username::register($user,$nickname,$this->provider_name);
|
||||
return false;
|
||||
$suggested_nickname = $this->suggestNicknameForUsername($nickname);
|
||||
$test_user = User::staticGet('nickname', $suggested_nickname);
|
||||
if($test_user) {
|
||||
//someone already exists with the suggested nickname, so used the passed nickname
|
||||
$suggested_nickname = common_nicknamize($nickname);
|
||||
}
|
||||
$test_user = User::staticGet('nickname', $suggested_nickname);
|
||||
if($test_user) {
|
||||
//someone already exists with the suggested nickname
|
||||
//not much else we can do
|
||||
}else{
|
||||
$user = $this->autoRegister($nickname, $suggested_nickname);
|
||||
if($user){
|
||||
User_username::register($user,$nickname,$this->provider_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,23 +153,30 @@ abstract class AuthenticationPlugin extends Plugin
|
||||
$user_username->username=$nickname;
|
||||
$user_username->provider_name=$this->provider_name;
|
||||
if($user_username->find() && $user_username->fetch()){
|
||||
$username = $user_username->username;
|
||||
$authenticated = $this->checkPassword($username, $password);
|
||||
$authenticated = $this->checkPassword($user_username->username, $password);
|
||||
if($authenticated){
|
||||
$authenticatedUser = User::staticGet('id', $user_username->user_id);
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
//$nickname is the username used to login
|
||||
//$suggested_nickname is the nickname the auth provider suggests for that username
|
||||
$suggested_nickname = $this->suggestNicknameForUsername($nickname);
|
||||
$user = User::staticGet('nickname', $suggested_nickname);
|
||||
if($user){
|
||||
//make sure a different provider isn't handling this nickname
|
||||
//make sure this user isn't claimed
|
||||
$user_username = new User_username();
|
||||
$user_username->username=$nickname;
|
||||
if(!$user_username->find()){
|
||||
//no other provider claims this username, so it's safe for us to handle it
|
||||
$user_username->user_id=$user->id;
|
||||
$we_can_handle = false;
|
||||
if($user_username->find()){
|
||||
//either this provider, or another one, has already claimed this user
|
||||
//so we cannot. Let another plugin try.
|
||||
return;
|
||||
}else{
|
||||
//no other provider claims this user, so it's safe for us to handle it
|
||||
$authenticated = $this->checkPassword($nickname, $password);
|
||||
if($authenticated){
|
||||
$authenticatedUser = User::staticGet('nickname', $nickname);
|
||||
$authenticatedUser = $user;
|
||||
User_username::register($authenticatedUser,$nickname,$this->provider_name);
|
||||
return false;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ abstract class AuthorizationPlugin extends Plugin
|
||||
}
|
||||
|
||||
function onStartSetApiUser(&$user) {
|
||||
return $this->onStartSetUser(&$user);
|
||||
return $this->onStartSetUser($user);
|
||||
}
|
||||
|
||||
function onStartHasRole($profile, $name, &$has_role) {
|
||||
|
@ -711,6 +711,34 @@ class LoginCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
class LoseCommand extends Command
|
||||
{
|
||||
|
||||
var $other = null;
|
||||
|
||||
function __construct($user, $other)
|
||||
{
|
||||
parent::__construct($user);
|
||||
$this->other = $other;
|
||||
}
|
||||
|
||||
function execute($channel)
|
||||
{
|
||||
if(!$this->other) {
|
||||
$channel->error($this->user, _('Specify the name of the user to unsubscribe from'));
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile());
|
||||
|
||||
if ($result) {
|
||||
$channel->output($this->user, sprintf(_('Unsubscribed %s'), $this->other));
|
||||
} else {
|
||||
$channel->error($this->user, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubscriptionsCommand extends Command
|
||||
{
|
||||
function handle($channel)
|
||||
@ -793,6 +821,7 @@ class HelpCommand extends Command
|
||||
"d <nickname> <text> - direct message to user\n".
|
||||
"get <nickname> - get last notice from user\n".
|
||||
"whois <nickname> - get profile info on user\n".
|
||||
"lose <nickname> - force user to stop following you\n".
|
||||
"fav <nickname> - add user's last notice as a 'fave'\n".
|
||||
"fav #<notice_id> - add notice with the given id as a 'fave'\n".
|
||||
"repeat #<notice_id> - repeat a notice with a given id\n".
|
||||
|
@ -47,6 +47,17 @@ class CommandInterpreter
|
||||
} else {
|
||||
return new LoginCommand($user);
|
||||
}
|
||||
case 'lose':
|
||||
if ($arg) {
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new LoseCommand($user, $other);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
case 'subscribers':
|
||||
if ($arg) {
|
||||
return null;
|
||||
|
@ -71,6 +71,7 @@ if (!function_exists('dl')) {
|
||||
# global configuration object
|
||||
|
||||
require_once('PEAR.php');
|
||||
require_once('PEAR/Exception.php');
|
||||
require_once('DB/DataObject.php');
|
||||
require_once('DB/DataObject/Cast.php'); # for dates
|
||||
|
||||
@ -128,6 +129,17 @@ require_once INSTALLDIR.'/lib/activity.php';
|
||||
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||
|
||||
|
||||
//set PEAR error handling to use regular PHP exceptions
|
||||
function PEAR_ErrorToPEAR_Exception($err)
|
||||
{
|
||||
if ($err->getCode()) {
|
||||
throw new PEAR_Exception($err->getMessage(), $err->getCode());
|
||||
}
|
||||
throw new PEAR_Exception($err->getMessage());
|
||||
}
|
||||
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'PEAR_ErrorToPEAR_Exception');
|
||||
|
||||
try {
|
||||
StatusNet::init(@$server, @$path, @$conffile);
|
||||
} catch (NoConfigException $e) {
|
||||
|
@ -282,6 +282,7 @@ $default =
|
||||
'Mapstraction' => null,
|
||||
'OStatus' => null,
|
||||
'WikiHashtags' => null,
|
||||
'RSSCloud' => null,
|
||||
'OpenID' => null),
|
||||
),
|
||||
'admin' =>
|
||||
|
@ -356,40 +356,47 @@ class HTMLOutputter extends XMLOutputter
|
||||
|
||||
if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment']))
|
||||
{
|
||||
$path = common_config('javascript', 'path');
|
||||
if (strpos($src, 'plugins/') === 0 || strpos($src, 'local/') === 0) {
|
||||
|
||||
if (empty($path)) {
|
||||
$path = common_config('site', 'path') . '/js/';
|
||||
}
|
||||
$src = common_path($src) . '?version=' . STATUSNET_VERSION;
|
||||
|
||||
if ($path[strlen($path)-1] != '/') {
|
||||
$path .= '/';
|
||||
}
|
||||
}else{
|
||||
|
||||
if ($path[0] != '/') {
|
||||
$path = '/'.$path;
|
||||
}
|
||||
$path = common_config('javascript', 'path');
|
||||
|
||||
$server = common_config('javascript', 'server');
|
||||
|
||||
if (empty($server)) {
|
||||
$server = common_config('site', 'server');
|
||||
}
|
||||
|
||||
$ssl = common_config('javascript', 'ssl');
|
||||
|
||||
if (is_null($ssl)) { // null -> guess
|
||||
if (common_config('site', 'ssl') == 'always' &&
|
||||
!common_config('javascript', 'server')) {
|
||||
$ssl = true;
|
||||
} else {
|
||||
$ssl = false;
|
||||
if (empty($path)) {
|
||||
$path = common_config('site', 'path') . '/js/';
|
||||
}
|
||||
|
||||
if ($path[strlen($path)-1] != '/') {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
if ($path[0] != '/') {
|
||||
$path = '/'.$path;
|
||||
}
|
||||
|
||||
$server = common_config('javascript', 'server');
|
||||
|
||||
if (empty($server)) {
|
||||
$server = common_config('site', 'server');
|
||||
}
|
||||
|
||||
$ssl = common_config('javascript', 'ssl');
|
||||
|
||||
if (is_null($ssl)) { // null -> guess
|
||||
if (common_config('site', 'ssl') == 'always' &&
|
||||
!common_config('javascript', 'server')) {
|
||||
$ssl = true;
|
||||
} else {
|
||||
$ssl = false;
|
||||
}
|
||||
}
|
||||
|
||||
$protocol = ($ssl) ? 'https' : 'http';
|
||||
|
||||
$src = $protocol.'://'.$server.$path.$src . '?version=' . STATUSNET_VERSION;
|
||||
}
|
||||
|
||||
$protocol = ($ssl) ? 'https' : 'http';
|
||||
|
||||
$src = $protocol.'://'.$server.$path.$src . '?version=' . STATUSNET_VERSION;
|
||||
}
|
||||
|
||||
$this->element('script', array('type' => $type,
|
||||
|
@ -120,6 +120,16 @@ class HTTPClient extends HTTP_Request2
|
||||
{
|
||||
$this->config['max_redirs'] = 10;
|
||||
$this->config['follow_redirects'] = true;
|
||||
|
||||
// We've had some issues with keepalive breaking with
|
||||
// HEAD requests, such as to youtube which seems to be
|
||||
// emitting chunked encoding info for an empty body
|
||||
// instead of not emitting anything. This may be a
|
||||
// bug on YouTube's end, but the upstream libray
|
||||
// ought to be investigated to see if we can handle
|
||||
// it gracefully in that case as well.
|
||||
$this->config['protocol_version'] = '1.0';
|
||||
|
||||
parent::__construct($url, $method, $config);
|
||||
$this->setHeader('User-Agent', $this->userAgent());
|
||||
}
|
||||
|
@ -60,6 +60,21 @@ class ImageFile
|
||||
$this->filepath = $filepath;
|
||||
|
||||
$info = @getimagesize($this->filepath);
|
||||
|
||||
if (!(
|
||||
($info[2] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) ||
|
||||
($info[2] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) ||
|
||||
$info[2] == IMAGETYPE_BMP ||
|
||||
($info[2] == IMAGETYPE_WBMP && function_exists('imagecreatefromwbmp')) ||
|
||||
($info[2] == IMAGETYPE_XBM && function_exists('imagecreatefromxbm')) ||
|
||||
($info[2] == IMAGETYPE_XPM && function_exists('imagecreatefromxpm')) ||
|
||||
($info[2] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')))) {
|
||||
|
||||
@unlink($_FILES[$param]['tmp_name']);
|
||||
throw new Exception(_('Unsupported image file format.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->type = ($info) ? $info[2]:$type;
|
||||
$this->width = ($info) ? $info[0]:$width;
|
||||
$this->height = ($info) ? $info[1]:$height;
|
||||
@ -97,15 +112,6 @@ class ImageFile
|
||||
return;
|
||||
}
|
||||
|
||||
if ($info[2] !== IMAGETYPE_GIF &&
|
||||
$info[2] !== IMAGETYPE_JPEG &&
|
||||
$info[2] !== IMAGETYPE_PNG) {
|
||||
|
||||
@unlink($_FILES[$param]['tmp_name']);
|
||||
throw new Exception(_('Unsupported image file format.'));
|
||||
return;
|
||||
}
|
||||
|
||||
return new ImageFile(null, $_FILES[$param]['tmp_name']);
|
||||
}
|
||||
|
||||
@ -146,6 +152,18 @@ class ImageFile
|
||||
case IMAGETYPE_PNG:
|
||||
$image_src = imagecreatefrompng($this->filepath);
|
||||
break;
|
||||
case IMAGETYPE_BMP:
|
||||
$image_src = imagecreatefrombmp($this->filepath);
|
||||
break;
|
||||
case IMAGETYPE_WBMP:
|
||||
$image_src = imagecreatefromwbmp($this->filepath);
|
||||
break;
|
||||
case IMAGETYPE_XBM:
|
||||
$image_src = imagecreatefromxbm($this->filepath);
|
||||
break;
|
||||
case IMAGETYPE_XPM:
|
||||
$image_src = imagecreatefromxpm($this->filepath);
|
||||
break;
|
||||
default:
|
||||
throw new Exception(_('Unknown file type'));
|
||||
return;
|
||||
@ -153,7 +171,7 @@ class ImageFile
|
||||
|
||||
$image_dest = imagecreatetruecolor($size, $size);
|
||||
|
||||
if ($this->type == IMAGETYPE_GIF || $this->type == IMAGETYPE_PNG) {
|
||||
if ($this->type == IMAGETYPE_GIF || $this->type == IMAGETYPE_PNG || $this->type == IMAGETYPE_BMP) {
|
||||
|
||||
$transparent_idx = imagecolortransparent($image_src);
|
||||
|
||||
@ -176,6 +194,24 @@ class ImageFile
|
||||
|
||||
imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $size, $size, $w, $h);
|
||||
|
||||
if($this->type == IMAGETYPE_BMP) {
|
||||
//we don't want to save BMP... it's an inefficient, rare, antiquated format
|
||||
//save png instead
|
||||
$this->type = IMAGETYPE_PNG;
|
||||
} else if($this->type == IMAGETYPE_WBMP) {
|
||||
//we don't want to save WBMP... it's a rare format that we can't guarantee clients will support
|
||||
//save png instead
|
||||
$this->type = IMAGETYPE_PNG;
|
||||
} else if($this->type == IMAGETYPE_XBM) {
|
||||
//we don't want to save XBM... it's a rare format that we can't guarantee clients will support
|
||||
//save png instead
|
||||
$this->type = IMAGETYPE_PNG;
|
||||
} else if($this->type == IMAGETYPE_XPM) {
|
||||
//we don't want to save XPM... it's a rare format that we can't guarantee clients will support
|
||||
//save png instead
|
||||
$this->type = IMAGETYPE_PNG;
|
||||
}
|
||||
|
||||
$outname = Avatar::filename($this->id,
|
||||
image_type_to_extension($this->type),
|
||||
$size,
|
||||
@ -245,4 +281,101 @@ class ImageFile
|
||||
|
||||
return $num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//PHP doesn't (as of 2/24/2010) have an imagecreatefrombmp so conditionally define one
|
||||
if(!function_exists('imagecreatefrombmp')){
|
||||
//taken shamelessly from http://www.php.net/manual/en/function.imagecreatefromwbmp.php#86214
|
||||
function imagecreatefrombmp($p_sFile)
|
||||
{
|
||||
// Load the image into a string
|
||||
$file = fopen($p_sFile,"rb");
|
||||
$read = fread($file,10);
|
||||
while(!feof($file)&&($read<>""))
|
||||
$read .= fread($file,1024);
|
||||
|
||||
$temp = unpack("H*",$read);
|
||||
$hex = $temp[1];
|
||||
$header = substr($hex,0,108);
|
||||
|
||||
// Process the header
|
||||
// Structure: http://www.fastgraph.com/help/bmp_header_format.html
|
||||
if (substr($header,0,4)=="424d")
|
||||
{
|
||||
// Cut it in parts of 2 bytes
|
||||
$header_parts = str_split($header,2);
|
||||
|
||||
// Get the width 4 bytes
|
||||
$width = hexdec($header_parts[19].$header_parts[18]);
|
||||
|
||||
// Get the height 4 bytes
|
||||
$height = hexdec($header_parts[23].$header_parts[22]);
|
||||
|
||||
// Unset the header params
|
||||
unset($header_parts);
|
||||
}
|
||||
|
||||
// Define starting X and Y
|
||||
$x = 0;
|
||||
$y = 1;
|
||||
|
||||
// Create newimage
|
||||
$image = imagecreatetruecolor($width,$height);
|
||||
|
||||
// Grab the body from the image
|
||||
$body = substr($hex,108);
|
||||
|
||||
// Calculate if padding at the end-line is needed
|
||||
// Divided by two to keep overview.
|
||||
// 1 byte = 2 HEX-chars
|
||||
$body_size = (strlen($body)/2);
|
||||
$header_size = ($width*$height);
|
||||
|
||||
// Use end-line padding? Only when needed
|
||||
$usePadding = ($body_size>($header_size*3)+4);
|
||||
|
||||
// Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
|
||||
// Calculate the next DWORD-position in the body
|
||||
for ($i=0;$i<$body_size;$i+=3)
|
||||
{
|
||||
// Calculate line-ending and padding
|
||||
if ($x>=$width)
|
||||
{
|
||||
// If padding needed, ignore image-padding
|
||||
// Shift i to the ending of the current 32-bit-block
|
||||
if ($usePadding)
|
||||
$i += $width%4;
|
||||
|
||||
// Reset horizontal position
|
||||
$x = 0;
|
||||
|
||||
// Raise the height-position (bottom-up)
|
||||
$y++;
|
||||
|
||||
// Reached the image-height? Break the for-loop
|
||||
if ($y>$height)
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculation of the RGB-pixel (defined as BGR in image-data)
|
||||
// Define $i_pos as absolute position in the body
|
||||
$i_pos = $i*2;
|
||||
$r = hexdec($body[$i_pos+4].$body[$i_pos+5]);
|
||||
$g = hexdec($body[$i_pos+2].$body[$i_pos+3]);
|
||||
$b = hexdec($body[$i_pos].$body[$i_pos+1]);
|
||||
|
||||
// Calculate and draw the pixel
|
||||
$color = imagecolorallocate($image,$r,$g,$b);
|
||||
imagesetpixel($image,$x,$height-$y,$color);
|
||||
|
||||
// Raise the horizontal position
|
||||
$x++;
|
||||
}
|
||||
|
||||
// Unset the body / free the memory
|
||||
unset($body);
|
||||
|
||||
// Return image-object
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ abstract class IoMaster
|
||||
* for per-queue and per-site records.
|
||||
*
|
||||
* @param string $key counter name
|
||||
* @param array $owners list of owner keys like 'queue:jabber' or 'site:stat01'
|
||||
* @param array $owners list of owner keys like 'queue:xmpp' or 'site:stat01'
|
||||
*/
|
||||
public function stats($key, $owners=array())
|
||||
{
|
||||
|
@ -289,6 +289,7 @@ function get_all_languages() {
|
||||
'ar' => array('q' => 0.8, 'lang' => 'ar', 'name' => 'Arabic', 'direction' => 'rtl'),
|
||||
'arz' => array('q' => 0.8, 'lang' => 'arz', 'name' => 'Egyptian Spoken Arabic', 'direction' => 'rtl'),
|
||||
'bg' => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'),
|
||||
'br' => array('q' => 0.8, 'lang' => 'br', 'name' => 'Breton', 'direction' => 'ltr'),
|
||||
'ca' => array('q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'),
|
||||
'cs' => array('q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'),
|
||||
'de' => array('q' => 0.8, 'lang' => 'de', 'name' => 'German', 'direction' => 'ltr'),
|
||||
|
67
lib/mail.php
67
lib/mail.php
@ -133,12 +133,13 @@ function mail_notify_from()
|
||||
* @param User &$user user to send email to
|
||||
* @param string $subject subject of the email
|
||||
* @param string $body body of the email
|
||||
* @param array $headers optional list of email headers
|
||||
* @param string $address optional specification of email address
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function mail_to_user(&$user, $subject, $body, $address=null)
|
||||
function mail_to_user(&$user, $subject, $body, $headers=array(), $address=null)
|
||||
{
|
||||
if (!$address) {
|
||||
$address = $user->email;
|
||||
@ -180,7 +181,9 @@ function mail_confirm_address($user, $code, $nickname, $address)
|
||||
$nickname, common_config('site', 'name'),
|
||||
common_local_url('confirmaddress', array('code' => $code)),
|
||||
common_config('site', 'name'));
|
||||
return mail_to_user($user, $subject, $body, $address);
|
||||
$headers = array();
|
||||
|
||||
return mail_to_user($user, $subject, $body, $headers, $address);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,6 +234,7 @@ function mail_subscribe_notify_profile($listenee, $other)
|
||||
|
||||
$recipients = $listenee->email;
|
||||
|
||||
$headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname);
|
||||
$headers['From'] = mail_notify_from();
|
||||
$headers['To'] = $name . ' <' . $listenee->email . '>';
|
||||
$headers['Subject'] = sprintf(_('%1$s is now listening to '.
|
||||
@ -476,7 +480,10 @@ function mail_notify_nudge($from, $to)
|
||||
common_local_url('all', array('nickname' => $to->nickname)),
|
||||
common_config('site', 'name'));
|
||||
common_init_locale();
|
||||
return mail_to_user($to, $subject, $body);
|
||||
|
||||
$headers = _mail_prepare_headers('nudge', $to->nickname, $from->nickname);
|
||||
|
||||
return mail_to_user($to, $subject, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,8 +533,10 @@ function mail_notify_message($message, $from=null, $to=null)
|
||||
common_local_url('newmessage', array('to' => $from->id)),
|
||||
common_config('site', 'name'));
|
||||
|
||||
$headers = _mail_prepare_headers('message', $to->nickname, $from->nickname);
|
||||
|
||||
common_init_locale();
|
||||
return mail_to_user($to, $subject, $body);
|
||||
return mail_to_user($to, $subject, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -578,8 +587,10 @@ function mail_notify_fave($other, $user, $notice)
|
||||
common_config('site', 'name'),
|
||||
$user->nickname);
|
||||
|
||||
$headers = _mail_prepare_headers('fave', $other->nickname, $user->nickname);
|
||||
|
||||
common_init_locale();
|
||||
mail_to_user($other, $subject, $body);
|
||||
mail_to_user($other, $subject, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -611,19 +622,19 @@ function mail_notify_attn($user, $notice)
|
||||
|
||||
common_init_locale($user->language);
|
||||
|
||||
if ($notice->conversation != $notice->id) {
|
||||
$conversationEmailText = "The full conversation can be read here:\n\n".
|
||||
"\t%5\$s\n\n ";
|
||||
$conversationUrl = common_local_url('conversation',
|
||||
if ($notice->conversation != $notice->id) {
|
||||
$conversationEmailText = "The full conversation can be read here:\n\n".
|
||||
"\t%5\$s\n\n ";
|
||||
$conversationUrl = common_local_url('conversation',
|
||||
array('id' => $notice->conversation)).'#notice-'.$notice->id;
|
||||
} else {
|
||||
$conversationEmailText = "%5\$s";
|
||||
$conversationUrl = null;
|
||||
}
|
||||
} else {
|
||||
$conversationEmailText = "%5\$s";
|
||||
$conversationUrl = null;
|
||||
}
|
||||
|
||||
$subject = sprintf(_('%s (@%s) sent a notice to your attention'), $bestname, $sender->nickname);
|
||||
|
||||
$body = sprintf(_("%1\$s (@%9\$s) just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
|
||||
$body = sprintf(_("%1\$s (@%9\$s) just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
|
||||
"The notice is here:\n\n".
|
||||
"\t%3\$s\n\n" .
|
||||
"It reads:\n\n".
|
||||
@ -641,7 +652,7 @@ function mail_notify_attn($user, $notice)
|
||||
common_local_url('shownotice',
|
||||
array('notice' => $notice->id)),//%3
|
||||
$notice->content,//%4
|
||||
$conversationUrl,//%5
|
||||
$conversationUrl,//%5
|
||||
common_local_url('newnotice',
|
||||
array('replyto' => $sender->nickname, 'inreplyto' => $notice->id)),//%6
|
||||
common_local_url('replies',
|
||||
@ -649,6 +660,30 @@ function mail_notify_attn($user, $notice)
|
||||
common_local_url('emailsettings'), //%8
|
||||
$sender->nickname); //%9
|
||||
|
||||
$headers = _mail_prepare_headers('mention', $user->nickname, $sender->nickname);
|
||||
|
||||
common_init_locale();
|
||||
mail_to_user($user, $subject, $body);
|
||||
mail_to_user($user, $subject, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the common mail headers used in notification emails
|
||||
*
|
||||
* @param string $msg_type type of message being sent to the user
|
||||
* @param string $to nickname of the receipient
|
||||
* @param string $from nickname of the user triggering the notification
|
||||
*
|
||||
* @return array list of mail headers to include in the message
|
||||
*/
|
||||
function _mail_prepare_headers($msg_type, $to, $from)
|
||||
{
|
||||
$headers = array(
|
||||
'X-StatusNet-MessageType' => $msg_type,
|
||||
'X-StatusNet-TargetUser' => $to,
|
||||
'X-StatusNet-SourceUser' => $from,
|
||||
'X-StatusNet-Domain' => common_config('site', 'server')
|
||||
);
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ class MediaFile
|
||||
$filetype = MIME_Type::autoDetect($stream['uri']);
|
||||
}
|
||||
|
||||
if (in_array($filetype, common_config('attachments', 'supported'))) {
|
||||
if (common_config('attachments', 'supported') === true || in_array($filetype, common_config('attachments', 'supported'))) {
|
||||
return $filetype;
|
||||
}
|
||||
$media = MIME_Type::getMedia($filetype);
|
||||
|
@ -175,6 +175,6 @@ class MessageForm extends Form
|
||||
'class' => 'submit',
|
||||
'name' => 'message_send',
|
||||
'type' => 'submit',
|
||||
'value' => _('Send')));
|
||||
'value' => _m('Send button for sending notice', 'Send')));
|
||||
}
|
||||
}
|
||||
|
@ -90,15 +90,24 @@ class MysqlSchema extends Schema
|
||||
* @param string $name Name of the table to get
|
||||
*
|
||||
* @return TableDef tabledef for that table.
|
||||
* @throws SchemaTableMissingException
|
||||
*/
|
||||
|
||||
public function getTableDef($name)
|
||||
{
|
||||
$res = $this->conn->query('DESCRIBE ' . $name);
|
||||
$query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS " .
|
||||
"WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s'";
|
||||
$schema = $this->conn->dsn['database'];
|
||||
$sql = sprintf($query, $schema, $name);
|
||||
$res = $this->conn->query($sql);
|
||||
|
||||
if (PEAR::isError($res)) {
|
||||
throw new Exception($res->getMessage());
|
||||
}
|
||||
if ($res->numRows() == 0) {
|
||||
$res->free();
|
||||
throw new SchemaTableMissingException("No such table: $name");
|
||||
}
|
||||
|
||||
$td = new TableDef();
|
||||
|
||||
@ -111,9 +120,9 @@ class MysqlSchema extends Schema
|
||||
|
||||
$cd = new ColumnDef();
|
||||
|
||||
$cd->name = $row['Field'];
|
||||
$cd->name = $row['COLUMN_NAME'];
|
||||
|
||||
$packed = $row['Type'];
|
||||
$packed = $row['COLUMN_TYPE'];
|
||||
|
||||
if (preg_match('/^(\w+)\((\d+)\)$/', $packed, $match)) {
|
||||
$cd->type = $match[1];
|
||||
@ -122,17 +131,57 @@ class MysqlSchema extends Schema
|
||||
$cd->type = $packed;
|
||||
}
|
||||
|
||||
$cd->nullable = ($row['Null'] == 'YES') ? true : false;
|
||||
$cd->key = $row['Key'];
|
||||
$cd->default = $row['Default'];
|
||||
$cd->extra = $row['Extra'];
|
||||
$cd->nullable = ($row['IS_NULLABLE'] == 'YES') ? true : false;
|
||||
$cd->key = $row['COLUMN_KEY'];
|
||||
$cd->default = $row['COLUMN_DEFAULT'];
|
||||
$cd->extra = $row['EXTRA'];
|
||||
|
||||
// Autoincrement is stuck into the extra column.
|
||||
// Pull it out so we don't accidentally mod it every time...
|
||||
$extra = preg_replace('/(^|\s)auto_increment(\s|$)/i', '$1$2', $cd->extra);
|
||||
if ($extra != $cd->extra) {
|
||||
$cd->extra = trim($extra);
|
||||
$cd->auto_increment = true;
|
||||
}
|
||||
|
||||
// mysql extensions -- not (yet) used by base class
|
||||
$cd->charset = $row['CHARACTER_SET_NAME'];
|
||||
$cd->collate = $row['COLLATION_NAME'];
|
||||
|
||||
$td->columns[] = $cd;
|
||||
}
|
||||
$res->free();
|
||||
|
||||
return $td;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the given table properties from INFORMATION_SCHEMA.
|
||||
* Most of the good stuff is MySQL extensions.
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception if table info can't be looked up
|
||||
*/
|
||||
|
||||
function getTableProperties($table, $props)
|
||||
{
|
||||
$query = "SELECT %s FROM INFORMATION_SCHEMA.TABLES " .
|
||||
"WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s'";
|
||||
$schema = $this->conn->dsn['database'];
|
||||
$sql = sprintf($query, implode(',', $props), $schema, $table);
|
||||
$res = $this->conn->query($sql);
|
||||
|
||||
$row = array();
|
||||
$ok = $res->fetchInto($row, DB_FETCHMODE_ASSOC);
|
||||
$res->free();
|
||||
|
||||
if ($ok) {
|
||||
return $row;
|
||||
} else {
|
||||
throw new SchemaTableMissingException("No such table: $table");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a ColumnDef object for a single column.
|
||||
*
|
||||
@ -185,35 +234,26 @@ class MysqlSchema extends Schema
|
||||
}
|
||||
|
||||
$sql .= $this->_columnSql($cd);
|
||||
|
||||
switch ($cd->key) {
|
||||
case 'UNI':
|
||||
$uniques[] = $cd->name;
|
||||
break;
|
||||
case 'PRI':
|
||||
$primary[] = $cd->name;
|
||||
break;
|
||||
case 'MUL':
|
||||
$indices[] = $cd->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($primary) > 0) { // it really should be...
|
||||
$sql .= ",\nconstraint primary key (" . implode(',', $primary) . ")";
|
||||
$idx = $this->_indexList($columns);
|
||||
|
||||
if ($idx['primary']) {
|
||||
$sql .= ",\nconstraint primary key (" . implode(',', $idx['primary']) . ")";
|
||||
}
|
||||
|
||||
foreach ($uniques as $u) {
|
||||
$sql .= ",\nunique index {$name}_{$u}_idx ($u)";
|
||||
foreach ($idx['uniques'] as $u) {
|
||||
$key = $this->_uniqueKey($name, $u);
|
||||
$sql .= ",\nunique index $key ($u)";
|
||||
}
|
||||
|
||||
foreach ($indices as $i) {
|
||||
$sql .= ",\nindex {$name}_{$i}_idx ($i)";
|
||||
foreach ($idx['indices'] as $i) {
|
||||
$key = $this->_key($name, $i);
|
||||
$sql .= ",\nindex $key ($i)";
|
||||
}
|
||||
|
||||
$sql .= "); ";
|
||||
$sql .= ") ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ";
|
||||
|
||||
common_log(LOG_INFO, $sql);
|
||||
$res = $this->conn->query($sql);
|
||||
|
||||
if (PEAR::isError($res)) {
|
||||
@ -223,6 +263,47 @@ class MysqlSchema extends Schema
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look over a list of column definitions and list up which
|
||||
* indices will be present
|
||||
*/
|
||||
private function _indexList(array $columns)
|
||||
{
|
||||
$list = array('uniques' => array(),
|
||||
'primary' => array(),
|
||||
'indices' => array());
|
||||
foreach ($columns as $cd) {
|
||||
switch ($cd->key) {
|
||||
case 'UNI':
|
||||
$list['uniques'][] = $cd->name;
|
||||
break;
|
||||
case 'PRI':
|
||||
$list['primary'][] = $cd->name;
|
||||
break;
|
||||
case 'MUL':
|
||||
$list['indices'][] = $cd->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique index key name for a given column on this table
|
||||
*/
|
||||
function _uniqueKey($tableName, $columnName)
|
||||
{
|
||||
return $this->_key($tableName, $columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index key name for a given column on this table
|
||||
*/
|
||||
function _key($tableName, $columnName)
|
||||
{
|
||||
return "{$tableName}_{$columnName}_idx";
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops a table from the schema
|
||||
*
|
||||
@ -394,21 +475,20 @@ class MysqlSchema extends Schema
|
||||
|
||||
try {
|
||||
$td = $this->getTableDef($tableName);
|
||||
} catch (Exception $e) {
|
||||
if (preg_match('/no such table/', $e->getMessage())) {
|
||||
return $this->createTable($tableName, $columns);
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
} catch (SchemaTableMissingException $e) {
|
||||
return $this->createTable($tableName, $columns);
|
||||
}
|
||||
|
||||
$cur = $this->_names($td->columns);
|
||||
$new = $this->_names($columns);
|
||||
|
||||
$toadd = array_diff($new, $cur);
|
||||
$todrop = array_diff($cur, $new);
|
||||
$same = array_intersect($new, $cur);
|
||||
$tomod = array();
|
||||
$dropIndex = array();
|
||||
$toadd = array_diff($new, $cur);
|
||||
$todrop = array_diff($cur, $new);
|
||||
$same = array_intersect($new, $cur);
|
||||
$tomod = array();
|
||||
$addIndex = array();
|
||||
$tableProps = array();
|
||||
|
||||
foreach ($same as $m) {
|
||||
$curCol = $this->_byName($td->columns, $m);
|
||||
@ -416,10 +496,64 @@ class MysqlSchema extends Schema
|
||||
|
||||
if (!$newCol->equals($curCol)) {
|
||||
$tomod[] = $newCol->name;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Earlier versions may have accidentally left tables at default
|
||||
// charsets which might be latin1 or other freakish things.
|
||||
if ($this->_isString($curCol)) {
|
||||
if ($curCol->charset != 'utf8') {
|
||||
$tomod[] = $newCol->name;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($toadd) + count($todrop) + count($tomod) == 0) {
|
||||
// Find any indices we have to change...
|
||||
$curIdx = $this->_indexList($td->columns);
|
||||
$newIdx = $this->_indexList($columns);
|
||||
|
||||
if ($curIdx['primary'] != $newIdx['primary']) {
|
||||
if ($curIdx['primary']) {
|
||||
$dropIndex[] = 'drop primary key';
|
||||
}
|
||||
if ($newIdx['primary']) {
|
||||
$keys = implode(',', $newIdx['primary']);
|
||||
$addIndex[] = "add constraint primary key ($keys)";
|
||||
}
|
||||
}
|
||||
|
||||
$dropUnique = array_diff($curIdx['uniques'], $newIdx['uniques']);
|
||||
$addUnique = array_diff($newIdx['uniques'], $curIdx['uniques']);
|
||||
foreach ($dropUnique as $columnName) {
|
||||
$dropIndex[] = 'drop key ' . $this->_uniqueKey($tableName, $columnName);
|
||||
}
|
||||
foreach ($addUnique as $columnName) {
|
||||
$addIndex[] = 'add constraint unique key ' . $this->_uniqueKey($tableName, $columnName) . " ($columnName)";;
|
||||
}
|
||||
|
||||
$dropMultiple = array_diff($curIdx['indices'], $newIdx['indices']);
|
||||
$addMultiple = array_diff($newIdx['indices'], $curIdx['indices']);
|
||||
foreach ($dropMultiple as $columnName) {
|
||||
$dropIndex[] = 'drop key ' . $this->_key($tableName, $columnName);
|
||||
}
|
||||
foreach ($addMultiple as $columnName) {
|
||||
$addIndex[] = 'add key ' . $this->_key($tableName, $columnName) . " ($columnName)";
|
||||
}
|
||||
|
||||
// Check for table properties: make sure we're using a sane
|
||||
// engine type and charset/collation.
|
||||
// @fixme make the default engine configurable?
|
||||
$oldProps = $this->getTableProperties($tableName, array('ENGINE', 'TABLE_COLLATION'));
|
||||
if (strtolower($oldProps['ENGINE']) != 'innodb') {
|
||||
$tableProps['ENGINE'] = 'InnoDB';
|
||||
}
|
||||
if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8_bin') {
|
||||
$tableProps['DEFAULT CHARSET'] = 'utf8';
|
||||
$tableProps['COLLATE'] = 'utf8_bin';
|
||||
}
|
||||
|
||||
if (count($dropIndex) + count($toadd) + count($todrop) + count($tomod) + count($addIndex) + count($tableProps) == 0) {
|
||||
// nothing to do
|
||||
return true;
|
||||
}
|
||||
@ -429,6 +563,10 @@ class MysqlSchema extends Schema
|
||||
|
||||
$phrase = array();
|
||||
|
||||
foreach ($dropIndex as $indexSql) {
|
||||
$phrase[] = $indexSql;
|
||||
}
|
||||
|
||||
foreach ($toadd as $columnName) {
|
||||
$cd = $this->_byName($columns, $columnName);
|
||||
|
||||
@ -445,8 +583,17 @@ class MysqlSchema extends Schema
|
||||
$phrase[] = 'MODIFY COLUMN ' . $this->_columnSql($cd);
|
||||
}
|
||||
|
||||
foreach ($addIndex as $indexSql) {
|
||||
$phrase[] = $indexSql;
|
||||
}
|
||||
|
||||
foreach ($tableProps as $key => $val) {
|
||||
$phrase[] = "$key=$val";
|
||||
}
|
||||
|
||||
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(', ', $phrase);
|
||||
|
||||
common_log(LOG_DEBUG, __METHOD__ . ': ' . $sql);
|
||||
$res = $this->conn->query($sql);
|
||||
|
||||
if (PEAR::isError($res)) {
|
||||
@ -519,6 +666,10 @@ class MysqlSchema extends Schema
|
||||
$sql .= "{$cd->type} ";
|
||||
}
|
||||
|
||||
if ($this->_isString($cd)) {
|
||||
$sql .= " CHARACTER SET utf8 ";
|
||||
}
|
||||
|
||||
if (!empty($cd->default)) {
|
||||
$sql .= "default {$cd->default} ";
|
||||
} else {
|
||||
@ -535,4 +686,13 @@ class MysqlSchema extends Schema
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this column a string type?
|
||||
*/
|
||||
private function _isString(ColumnDef $cd)
|
||||
{
|
||||
$strings = array('char', 'varchar', 'text');
|
||||
return in_array(strtolower($cd->type), $strings);
|
||||
}
|
||||
}
|
||||
|
@ -233,6 +233,6 @@ class NoticeForm extends Form
|
||||
'class' => 'submit',
|
||||
'name' => 'status_submit',
|
||||
'type' => 'submit',
|
||||
'value' => _('Send')));
|
||||
'value' => _m('Send button for sending notice', 'Send')));
|
||||
}
|
||||
}
|
||||
|
@ -442,11 +442,13 @@ class NoticeListItem extends Widget
|
||||
'title' => $latlon),
|
||||
$name);
|
||||
} else {
|
||||
$this->out->elementStart('a', array('href' => $url));
|
||||
$this->out->element('abbr', array('class' => 'geo',
|
||||
'title' => $latlon),
|
||||
$name);
|
||||
$this->out->elementEnd('a');
|
||||
$xstr = new XMLStringer(false);
|
||||
$xstr->elementStart('a', array('href' => $url));
|
||||
$xstr->element('abbr', array('class' => 'geo',
|
||||
'title' => $latlon),
|
||||
$name);
|
||||
$xstr->elementEnd('a');
|
||||
$this->out->raw($xstr->getString());
|
||||
}
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
|
@ -61,7 +61,8 @@ class PgsqlSchema extends Schema
|
||||
|
||||
public function getTableDef($name)
|
||||
{
|
||||
$res = $this->conn->query("select *, column_default as default, is_nullable as Null, udt_name as Type, column_name AS Field from INFORMATION_SCHEMA.COLUMNS where table_name = '$name'");
|
||||
$res = $this->conn->query("SELECT *, column_default as default, is_nullable as Null,
|
||||
udt_name as Type, column_name AS Field from INFORMATION_SCHEMA.COLUMNS where table_name = '$name'");
|
||||
|
||||
if (PEAR::isError($res)) {
|
||||
throw new Exception($res->getMessage());
|
||||
@ -72,6 +73,9 @@ class PgsqlSchema extends Schema
|
||||
$td->name = $name;
|
||||
$td->columns = array();
|
||||
|
||||
if ($res->numRows() == 0 ) {
|
||||
throw new Exception('no such table'); //pretend to be the msyql error. yeah, this sucks.
|
||||
}
|
||||
$row = array();
|
||||
|
||||
while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) {
|
||||
@ -166,12 +170,10 @@ class PgsqlSchema extends Schema
|
||||
}
|
||||
|
||||
if (count($primary) > 0) { // it really should be...
|
||||
$sql .= ",\nconstraint primary key (" . implode(',', $primary) . ")";
|
||||
$sql .= ",\n primary key (" . implode(',', $primary) . ")";
|
||||
}
|
||||
|
||||
foreach ($uniques as $u) {
|
||||
$sql .= ",\nunique index {$name}_{$u}_idx ($u)";
|
||||
}
|
||||
|
||||
|
||||
foreach ($indices as $i) {
|
||||
$sql .= ",\nindex {$name}_{$i}_idx ($i)";
|
||||
@ -179,6 +181,10 @@ class PgsqlSchema extends Schema
|
||||
|
||||
$sql .= "); ";
|
||||
|
||||
|
||||
foreach ($uniques as $u) {
|
||||
$sql .= "\n CREATE index {$name}_{$u}_idx ON {$name} ($u); ";
|
||||
}
|
||||
$res = $this->conn->query($sql);
|
||||
|
||||
if (PEAR::isError($res)) {
|
||||
@ -209,6 +215,22 @@ class PgsqlSchema extends Schema
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the (mostly) mysql-ish column types into somethings more standard
|
||||
* @param string column type
|
||||
*
|
||||
* @return string postgres happy column type
|
||||
*/
|
||||
private function _columnTypeTranslation($type) {
|
||||
$map = array(
|
||||
'datetime' => 'timestamp'
|
||||
);
|
||||
if(!empty($map[$type])) {
|
||||
return $map[$type];
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an index to a table.
|
||||
*
|
||||
@ -359,6 +381,7 @@ class PgsqlSchema extends Schema
|
||||
|
||||
try {
|
||||
$td = $this->getTableDef($tableName);
|
||||
|
||||
} catch (Exception $e) {
|
||||
if (preg_match('/no such table/', $e->getMessage())) {
|
||||
return $this->createTable($tableName, $columns);
|
||||
@ -477,11 +500,12 @@ class PgsqlSchema extends Schema
|
||||
private function _columnSql($cd)
|
||||
{
|
||||
$sql = "{$cd->name} ";
|
||||
$type = $this->_columnTypeTranslation($cd->type);
|
||||
|
||||
if (!empty($cd->size)) {
|
||||
$sql .= "{$cd->type}({$cd->size}) ";
|
||||
$sql .= "{$type}({$cd->size}) ";
|
||||
} else {
|
||||
$sql .= "{$cd->type} ";
|
||||
$sql .= "{$type} ";
|
||||
}
|
||||
|
||||
if (!empty($cd->default)) {
|
||||
|
84
lib/processmanager.php
Normal file
84
lib/processmanager.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* i/o manager to watch for a dead parent process
|
||||
*
|
||||
* 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 QueueManager
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@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/
|
||||
*/
|
||||
|
||||
class ProcessManager extends IoManager
|
||||
{
|
||||
protected $socket;
|
||||
|
||||
public static function get()
|
||||
{
|
||||
throw new Exception("Must pass ProcessManager per-instance");
|
||||
}
|
||||
|
||||
public function __construct($socket)
|
||||
{
|
||||
$this->socket = $socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the i/o queue master if and how we can handle multi-site
|
||||
* processes.
|
||||
*
|
||||
* Return one of:
|
||||
* IoManager::SINGLE_ONLY
|
||||
* IoManager::INSTANCE_PER_SITE
|
||||
* IoManager::INSTANCE_PER_PROCESS
|
||||
*/
|
||||
public static function multiSite()
|
||||
{
|
||||
return IoManager::INSTANCE_PER_PROCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* We won't get any input on it, but if it's broken we'll
|
||||
* know something's gone horribly awry.
|
||||
*
|
||||
* @return array of resources
|
||||
*/
|
||||
function getSockets()
|
||||
{
|
||||
return array($this->socket);
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the parent died and request a shutdown...
|
||||
*
|
||||
* @param resource $socket
|
||||
* @return boolean success
|
||||
*/
|
||||
function handleInput($socket)
|
||||
{
|
||||
if (feof($socket)) {
|
||||
common_log(LOG_INFO, "Parent process exited; shutting down child.");
|
||||
$this->master->requestShutdown();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,9 @@ abstract class QueueManager extends IoManager
|
||||
{
|
||||
if (isset($this->handlers[$queue])) {
|
||||
$class = $this->handlers[$queue];
|
||||
if (class_exists($class)) {
|
||||
if(is_object($class)) {
|
||||
return $class;
|
||||
} else if (class_exists($class)) {
|
||||
return new $class();
|
||||
} else {
|
||||
$this->_log(LOG_ERR, "Nonexistent handler class '$class' for queue '$queue'");
|
||||
@ -286,7 +288,7 @@ abstract class QueueManager extends IoManager
|
||||
* Only registered transports will be reliably picked up!
|
||||
*
|
||||
* @param string $transport
|
||||
* @param string $class
|
||||
* @param string $class class name or object instance
|
||||
* @param string $group
|
||||
*/
|
||||
public function connect($transport, $class, $group='main')
|
||||
|
@ -485,3 +485,9 @@ class Schema
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
class SchemaTableMissingException extends Exception
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,8 @@ abstract class SpawningDaemon extends Daemon
|
||||
*/
|
||||
function run()
|
||||
{
|
||||
$this->initPipes();
|
||||
|
||||
$children = array();
|
||||
for ($i = 1; $i <= $this->threads; $i++) {
|
||||
$pid = pcntl_fork();
|
||||
@ -128,6 +130,34 @@ abstract class SpawningDaemon extends Daemon
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an IPC socket pair which child processes can use to detect
|
||||
* if the parent process has been killed.
|
||||
*/
|
||||
function initPipes()
|
||||
{
|
||||
$sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
|
||||
if ($sockets) {
|
||||
$this->parentWriter = $sockets[0];
|
||||
$this->parentReader = $sockets[1];
|
||||
} else {
|
||||
$this->log(LOG_ERROR, "Couldn't create inter-process sockets");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an IOManager that simply ensures that we have a connection
|
||||
* to the parent process open. If it breaks, the child process will
|
||||
* die.
|
||||
*
|
||||
* @return ProcessManager
|
||||
*/
|
||||
public function processManager()
|
||||
{
|
||||
return new ProcessManager($this->parentReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to respawn an exited subprocess based on its exit code.
|
||||
* Otherwise we'll respawn all exits by default.
|
||||
@ -152,6 +182,8 @@ abstract class SpawningDaemon extends Daemon
|
||||
*/
|
||||
protected function initAndRunChild($thread)
|
||||
{
|
||||
// Close the writer end of our parent<->children pipe.
|
||||
fclose($this->parentWriter);
|
||||
$this->set_id($this->get_id() . "." . $thread);
|
||||
$this->resetDb();
|
||||
$exitCode = $this->runThread();
|
||||
|
@ -42,4 +42,4 @@ function subs_unsubscribe_to($user, $other)
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
lib/util.php
10
lib/util.php
@ -1493,7 +1493,15 @@ function common_copy_args($from)
|
||||
$to = array();
|
||||
$strip = get_magic_quotes_gpc();
|
||||
foreach ($from as $k => $v) {
|
||||
$to[$k] = ($strip) ? stripslashes($v) : $v;
|
||||
if($strip) {
|
||||
if(is_array($v)) {
|
||||
$to[$k] = common_copy_args($v);
|
||||
} else {
|
||||
$to[$k] = stripslashes($v);
|
||||
}
|
||||
} else {
|
||||
$to[$k] = $v;
|
||||
}
|
||||
}
|
||||
return $to;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6102
locale/br/LC_MESSAGES/statusnet.po
Normal file
6102
locale/br/LC_MESSAGES/statusnet.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user