Merge branch 'testing'
This commit is contained in:
commit
62d5f1addb
|
@ -83,6 +83,7 @@ class AllrssAction extends Rss10Action
|
||||||
function getNotices($limit=0)
|
function getNotices($limit=0)
|
||||||
{
|
{
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
if (!empty($cur) && $cur->id == $user->id) {
|
if (!empty($cur) && $cur->id == $user->id) {
|
||||||
$notice = $this->user->noticeInbox(0, $limit);
|
$notice = $this->user->noticeInbox(0, $limit);
|
||||||
|
@ -90,7 +91,6 @@ class AllrssAction extends Rss10Action
|
||||||
$notice = $this->user->noticesWithFriends(0, $limit);
|
$notice = $this->user->noticesWithFriends(0, $limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->user;
|
|
||||||
$notice = $user->noticesWithFriends(0, $limit);
|
$notice = $user->noticesWithFriends(0, $limit);
|
||||||
$notices = array();
|
$notices = array();
|
||||||
|
|
||||||
|
|
|
@ -104,30 +104,21 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
||||||
|
|
||||||
function showTimeline()
|
function showTimeline()
|
||||||
{
|
{
|
||||||
$sitename = common_config('site', 'name');
|
// We'll pull common formatting out of this for other formats
|
||||||
$avatar = $this->group->homepage_logo;
|
$atom = new AtomGroupNoticeFeed($this->group);
|
||||||
$title = sprintf(_("%s timeline"), $this->group->nickname);
|
|
||||||
|
|
||||||
$subtitle = sprintf(
|
|
||||||
_('Updates from %1$s on %2$s!'),
|
|
||||||
$this->group->nickname,
|
|
||||||
$sitename
|
|
||||||
);
|
|
||||||
|
|
||||||
$logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
|
||||||
|
|
||||||
switch($this->format) {
|
switch($this->format) {
|
||||||
case 'xml':
|
case 'xml':
|
||||||
$this->showXmlTimeline($this->notices);
|
$this->showXmlTimeline($this->notices);
|
||||||
break;
|
break;
|
||||||
case 'rss':
|
case 'rss':
|
||||||
$this->showRssTimeline(
|
$this->showRssTimeline(
|
||||||
$this->notices,
|
$this->notices,
|
||||||
$title,
|
$atom->title,
|
||||||
$this->group->homeUrl(),
|
$this->group->homeUrl(),
|
||||||
$subtitle,
|
$atom->subtitle,
|
||||||
null,
|
null,
|
||||||
$logo
|
$atom->logo
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'atom':
|
case 'atom':
|
||||||
|
@ -136,38 +127,22 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
$atom = new AtomGroupNoticeFeed($this->group);
|
|
||||||
|
|
||||||
// @todo set all this Atom junk up inside the feed class
|
|
||||||
|
|
||||||
#$atom->setId($id);
|
|
||||||
$atom->setTitle($title);
|
|
||||||
$atom->setSubtitle($subtitle);
|
|
||||||
$atom->setLogo($logo);
|
|
||||||
$atom->setUpdated('now');
|
|
||||||
|
|
||||||
$atom->addAuthorRaw($this->group->asAtomAuthor());
|
$atom->addAuthorRaw($this->group->asAtomAuthor());
|
||||||
$atom->setActivitySubject($this->group->asActivitySubject());
|
$atom->setActivitySubject($this->group->asActivitySubject());
|
||||||
|
|
||||||
$atom->addLink($this->group->homeUrl());
|
|
||||||
|
|
||||||
$id = $this->arg('id');
|
$id = $this->arg('id');
|
||||||
$aargs = array('format' => 'atom');
|
$aargs = array('format' => 'atom');
|
||||||
if (!empty($id)) {
|
if (!empty($id)) {
|
||||||
$aargs['id'] = $id;
|
$aargs['id'] = $id;
|
||||||
}
|
}
|
||||||
|
$self = $this->getSelfUri('ApiTimelineGroup', $aargs);
|
||||||
|
|
||||||
$atom->setId($this->getSelfUri('ApiTimelineGroup', $aargs));
|
$atom->setId($self);
|
||||||
|
$atom->setSelfLink($self);
|
||||||
$atom->addLink(
|
|
||||||
$this->getSelfUri('ApiTimelineGroup', $aargs),
|
|
||||||
array('rel' => 'self', 'type' => 'application/atom+xml')
|
|
||||||
);
|
|
||||||
|
|
||||||
$atom->addEntryFromNotices($this->notices);
|
$atom->addEntryFromNotices($this->notices);
|
||||||
|
|
||||||
//$this->raw($atom->getString());
|
$this->raw($atom->getString());
|
||||||
print $atom->getString(); // temp hack until PuSH feeds are redone cleanly
|
|
||||||
|
|
||||||
} catch (Atom10FeedException $e) {
|
} catch (Atom10FeedException $e) {
|
||||||
$this->serverError(
|
$this->serverError(
|
||||||
|
|
|
@ -112,19 +112,17 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
function showTimeline()
|
function showTimeline()
|
||||||
{
|
{
|
||||||
$profile = $this->user->getProfile();
|
$profile = $this->user->getProfile();
|
||||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
|
||||||
|
|
||||||
$sitename = common_config('site', 'name');
|
// We'll use the shared params from the Atom stub
|
||||||
$title = sprintf(_("%s timeline"), $this->user->nickname);
|
// for other feed types.
|
||||||
|
$atom = new AtomUserNoticeFeed($this->user);
|
||||||
|
$title = $atom->title;
|
||||||
$link = common_local_url(
|
$link = common_local_url(
|
||||||
'showstream',
|
'showstream',
|
||||||
array('nickname' => $this->user->nickname)
|
array('nickname' => $this->user->nickname)
|
||||||
);
|
);
|
||||||
$subtitle = sprintf(
|
$subtitle = $atom->subtitle;
|
||||||
_('Updates from %1$s on %2$s!'),
|
$logo = $atom->logo;
|
||||||
$this->user->nickname, $sitename
|
|
||||||
);
|
|
||||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
|
||||||
|
|
||||||
// FriendFeed's SUP protocol
|
// FriendFeed's SUP protocol
|
||||||
// Also added RSS and Atom feeds
|
// Also added RSS and Atom feeds
|
||||||
|
@ -146,47 +144,18 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||||
|
|
||||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||||
|
|
||||||
// @todo set all this Atom junk up inside the feed class
|
|
||||||
|
|
||||||
$atom = new AtomUserNoticeFeed($this->user);
|
|
||||||
|
|
||||||
$atom->setTitle($title);
|
|
||||||
$atom->setSubtitle($subtitle);
|
|
||||||
$atom->setLogo($logo);
|
|
||||||
$atom->setUpdated('now');
|
|
||||||
|
|
||||||
$atom->addLink(
|
|
||||||
common_local_url(
|
|
||||||
'showstream',
|
|
||||||
array('nickname' => $this->user->nickname)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$id = $this->arg('id');
|
$id = $this->arg('id');
|
||||||
$aargs = array('format' => 'atom');
|
$aargs = array('format' => 'atom');
|
||||||
if (!empty($id)) {
|
if (!empty($id)) {
|
||||||
$aargs['id'] = $id;
|
$aargs['id'] = $id;
|
||||||
}
|
}
|
||||||
|
$self = $this->getSelfUri('ApiTimelineUser', $aargs);
|
||||||
$atom->setId($this->getSelfUri('ApiTimelineUser', $aargs));
|
$atom->setId($self);
|
||||||
|
$atom->setSelfLink($self);
|
||||||
$atom->addLink(
|
|
||||||
$this->getSelfUri('ApiTimelineUser', $aargs),
|
|
||||||
array('rel' => 'self', 'type' => 'application/atom+xml')
|
|
||||||
);
|
|
||||||
|
|
||||||
$atom->addLink(
|
|
||||||
$suplink,
|
|
||||||
array(
|
|
||||||
'rel' => 'http://api.friendfeed.com/2008/03#sup',
|
|
||||||
'type' => 'application/json'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$atom->addEntryFromNotices($this->notices);
|
$atom->addEntryFromNotices($this->notices);
|
||||||
|
|
||||||
#$this->raw($atom->getString());
|
$this->raw($atom->getString());
|
||||||
print $atom->getString(); // temporary for output buffering
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'json':
|
case 'json':
|
||||||
|
|
99
actions/grantrole.php
Normal file
99
actions/grantrole.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Action class to sandbox an abusive user
|
||||||
|
*
|
||||||
|
* 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 Action
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sandbox a user.
|
||||||
|
*
|
||||||
|
* @category Action
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GrantRoleAction extends ProfileFormAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check parameters
|
||||||
|
*
|
||||||
|
* @param array $args action arguments (URL, GET, POST)
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
if (!parent::prepare($args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->role = $this->arg('role');
|
||||||
|
if (!Profile_role::isValid($this->role)) {
|
||||||
|
$this->clientError(_("Invalid role."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Profile_role::isSettable($this->role)) {
|
||||||
|
$this->clientError(_("This role is reserved and cannot be set."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
assert(!empty($cur)); // checked by parent
|
||||||
|
|
||||||
|
if (!$cur->hasRight(Right::GRANTROLE)) {
|
||||||
|
$this->clientError(_("You cannot grant user roles on this site."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!empty($this->profile)); // checked by parent
|
||||||
|
|
||||||
|
if ($this->profile->hasRole($this->role)) {
|
||||||
|
$this->clientError(_("User already has this role."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sandbox a user.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
$this->profile->grantRole($this->role);
|
||||||
|
}
|
||||||
|
}
|
99
actions/revokerole.php
Normal file
99
actions/revokerole.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Action class to sandbox an abusive user
|
||||||
|
*
|
||||||
|
* 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 Action
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sandbox a user.
|
||||||
|
*
|
||||||
|
* @category Action
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RevokeRoleAction extends ProfileFormAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check parameters
|
||||||
|
*
|
||||||
|
* @param array $args action arguments (URL, GET, POST)
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
if (!parent::prepare($args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->role = $this->arg('role');
|
||||||
|
if (!Profile_role::isValid($this->role)) {
|
||||||
|
$this->clientError(_("Invalid role."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Profile_role::isSettable($this->role)) {
|
||||||
|
$this->clientError(_("This role is reserved and cannot be set."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
assert(!empty($cur)); // checked by parent
|
||||||
|
|
||||||
|
if (!$cur->hasRight(Right::REVOKEROLE)) {
|
||||||
|
$this->clientError(_("You cannot revoke user roles on this site."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!empty($this->profile)); // checked by parent
|
||||||
|
|
||||||
|
if (!$this->profile->hasRole($this->role)) {
|
||||||
|
$this->clientError(_("User doesn't have this role."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sandbox a user.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
$this->profile->revokeRole($this->role);
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,7 +66,7 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||||
|
|
||||||
function getInstructions()
|
function getInstructions()
|
||||||
{
|
{
|
||||||
return _('Basic settings for this StatusNet site.');
|
return _('Basic settings for this StatusNet site');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,10 +90,11 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||||
|
|
||||||
function saveSettings()
|
function saveSettings()
|
||||||
{
|
{
|
||||||
static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl',
|
static $settings = array(
|
||||||
'email', 'timezone', 'language',
|
'site' => array('name', 'broughtby', 'broughtbyurl',
|
||||||
'site', 'textlimit', 'dupelimit'),
|
'email', 'timezone', 'language',
|
||||||
'snapshot' => array('run', 'reporturl', 'frequency'));
|
'site', 'textlimit', 'dupelimit'),
|
||||||
|
);
|
||||||
|
|
||||||
$values = array();
|
$values = array();
|
||||||
|
|
||||||
|
@ -158,25 +159,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||||
$this->clientError(sprintf(_('Unknown language "%s".'), $values['site']['language']));
|
$this->clientError(sprintf(_('Unknown language "%s".'), $values['site']['language']));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate report URL
|
|
||||||
|
|
||||||
if (!is_null($values['snapshot']['reporturl']) &&
|
|
||||||
!Validate::uri($values['snapshot']['reporturl'], array('allowed_schemes' => array('http', 'https')))) {
|
|
||||||
$this->clientError(_("Invalid snapshot report URL."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate snapshot run value
|
|
||||||
|
|
||||||
if (!in_array($values['snapshot']['run'], array('web', 'cron', 'never'))) {
|
|
||||||
$this->clientError(_("Invalid snapshot run value."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate snapshot run value
|
|
||||||
|
|
||||||
if (!Validate::number($values['snapshot']['frequency'])) {
|
|
||||||
$this->clientError(_("Snapshot frequency must be a number."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate text limit
|
// Validate text limit
|
||||||
|
|
||||||
if (!Validate::number($values['site']['textlimit'], array('min' => 140))) {
|
if (!Validate::number($values['site']['textlimit'], array('min' => 140))) {
|
||||||
|
@ -285,32 +267,6 @@ class SiteAdminPanelForm extends AdminForm
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_snapshots'));
|
|
||||||
$this->out->element('legend', null, _('Snapshots'));
|
|
||||||
$this->out->elementStart('ul', 'form_data');
|
|
||||||
$this->li();
|
|
||||||
$snapshot = array('web' => _('Randomly during Web hit'),
|
|
||||||
'cron' => _('In a scheduled job'),
|
|
||||||
'never' => _('Never'));
|
|
||||||
$this->out->dropdown('run', _('Data snapshots'),
|
|
||||||
$snapshot, _('When to send statistical data to status.net servers'),
|
|
||||||
false, $this->value('run', 'snapshot'));
|
|
||||||
$this->unli();
|
|
||||||
|
|
||||||
$this->li();
|
|
||||||
$this->input('frequency', _('Frequency'),
|
|
||||||
_('Snapshots will be sent once every N web hits'),
|
|
||||||
'snapshot');
|
|
||||||
$this->unli();
|
|
||||||
|
|
||||||
$this->li();
|
|
||||||
$this->input('reporturl', _('Report URL'),
|
|
||||||
_('Snapshots will be sent to this URL'),
|
|
||||||
'snapshot');
|
|
||||||
$this->unli();
|
|
||||||
$this->out->elementEnd('ul');
|
|
||||||
$this->out->elementEnd('fieldset');
|
|
||||||
|
|
||||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_limits'));
|
$this->out->elementStart('fieldset', array('id' => 'settings_admin_limits'));
|
||||||
$this->out->element('legend', null, _('Limits'));
|
$this->out->element('legend', null, _('Limits'));
|
||||||
$this->out->elementStart('ul', 'form_data');
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
|
|
@ -99,7 +99,7 @@ class SitenoticeadminpanelAction extends AdminPanelAction
|
||||||
|
|
||||||
$result = Config::save('site', 'notice', $siteNotice);
|
$result = Config::save('site', 'notice', $siteNotice);
|
||||||
|
|
||||||
if (!result) {
|
if (!$result) {
|
||||||
$this->ServerError(_("Unable to save site notice."));
|
$this->ServerError(_("Unable to save site notice."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
251
actions/snapshotadminpanel.php
Normal file
251
actions/snapshotadminpanel.php
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Snapshots administration panel
|
||||||
|
*
|
||||||
|
* 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 Settings
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2010 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage snapshots
|
||||||
|
*
|
||||||
|
* @category Admin
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SnapshotadminpanelAction extends AdminPanelAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the page title
|
||||||
|
*
|
||||||
|
* @return string page title
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('Snapshots');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for using this form.
|
||||||
|
*
|
||||||
|
* @return string instructions
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
return _('Manage snapshot configuration');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the snapshots admin panel form
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showForm()
|
||||||
|
{
|
||||||
|
$form = new SnapshotAdminPanelForm($this);
|
||||||
|
$form->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save settings from the form
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function saveSettings()
|
||||||
|
{
|
||||||
|
static $settings = array(
|
||||||
|
'snapshot' => array('run', 'reporturl', 'frequency')
|
||||||
|
);
|
||||||
|
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
foreach ($settings as $section => $parts) {
|
||||||
|
foreach ($parts as $setting) {
|
||||||
|
$values[$section][$setting] = $this->trimmed($setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This throws an exception on validation errors
|
||||||
|
|
||||||
|
$this->validate($values);
|
||||||
|
|
||||||
|
// assert(all values are valid);
|
||||||
|
|
||||||
|
$config = new Config();
|
||||||
|
|
||||||
|
$config->query('BEGIN');
|
||||||
|
|
||||||
|
foreach ($settings as $section => $parts) {
|
||||||
|
foreach ($parts as $setting) {
|
||||||
|
Config::save($section, $setting, $values[$section][$setting]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$config->query('COMMIT');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate(&$values)
|
||||||
|
{
|
||||||
|
// Validate snapshot run value
|
||||||
|
|
||||||
|
if (!in_array($values['snapshot']['run'], array('web', 'cron', 'never'))) {
|
||||||
|
$this->clientError(_("Invalid snapshot run value."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate snapshot frequency value
|
||||||
|
|
||||||
|
if (!Validate::number($values['snapshot']['frequency'])) {
|
||||||
|
$this->clientError(_("Snapshot frequency must be a number."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate report URL
|
||||||
|
|
||||||
|
if (!is_null($values['snapshot']['reporturl'])
|
||||||
|
&& !Validate::uri(
|
||||||
|
$values['snapshot']['reporturl'],
|
||||||
|
array('allowed_schemes' => array('http', 'https')
|
||||||
|
)
|
||||||
|
)) {
|
||||||
|
$this->clientError(_("Invalid snapshot report URL."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SnapshotAdminPanelForm extends AdminForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* ID of the form
|
||||||
|
*
|
||||||
|
* @return int ID of the form
|
||||||
|
*/
|
||||||
|
|
||||||
|
function id()
|
||||||
|
{
|
||||||
|
return 'form_snapshot_admin_panel';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class of the form
|
||||||
|
*
|
||||||
|
* @return string class of the form
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formClass()
|
||||||
|
{
|
||||||
|
return 'form_settings';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action of the form
|
||||||
|
*
|
||||||
|
* @return string URL of the action
|
||||||
|
*/
|
||||||
|
|
||||||
|
function action()
|
||||||
|
{
|
||||||
|
return common_local_url('snapshotadminpanel');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data elements of the form
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formData()
|
||||||
|
{
|
||||||
|
$this->out->elementStart(
|
||||||
|
'fieldset',
|
||||||
|
array('id' => 'settings_admin_snapshots')
|
||||||
|
);
|
||||||
|
$this->out->element('legend', null, _('Snapshots'));
|
||||||
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
$this->li();
|
||||||
|
$snapshot = array(
|
||||||
|
'web' => _('Randomly during Web hit'),
|
||||||
|
'cron' => _('In a scheduled job'),
|
||||||
|
'never' => _('Never')
|
||||||
|
);
|
||||||
|
$this->out->dropdown(
|
||||||
|
'run',
|
||||||
|
_('Data snapshots'),
|
||||||
|
$snapshot,
|
||||||
|
_('When to send statistical data to status.net servers'),
|
||||||
|
false,
|
||||||
|
$this->value('run', 'snapshot')
|
||||||
|
);
|
||||||
|
$this->unli();
|
||||||
|
|
||||||
|
$this->li();
|
||||||
|
$this->input(
|
||||||
|
'frequency',
|
||||||
|
_('Frequency'),
|
||||||
|
_('Snapshots will be sent once every N web hits'),
|
||||||
|
'snapshot'
|
||||||
|
);
|
||||||
|
$this->unli();
|
||||||
|
|
||||||
|
$this->li();
|
||||||
|
$this->input(
|
||||||
|
'reporturl',
|
||||||
|
_('Report URL'),
|
||||||
|
_('Snapshots will be sent to this URL'),
|
||||||
|
'snapshot'
|
||||||
|
);
|
||||||
|
$this->unli();
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
$this->out->elementEnd('fieldset');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action elements
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formActions()
|
||||||
|
{
|
||||||
|
$this->out->submit(
|
||||||
|
'submit',
|
||||||
|
_('Save'),
|
||||||
|
'submit',
|
||||||
|
null,
|
||||||
|
_('Save snapshot settings')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1106,7 +1106,7 @@ class Notice extends Memcached_DataObject
|
||||||
return $groups;
|
return $groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
function asAtomEntry($namespace=false, $source=false)
|
function asAtomEntry($namespace=false, $source=false, $author=true)
|
||||||
{
|
{
|
||||||
$profile = $this->getProfile();
|
$profile = $this->getProfile();
|
||||||
|
|
||||||
|
@ -1151,8 +1151,10 @@ class Notice extends Memcached_DataObject
|
||||||
|
|
||||||
$xs->element('title', null, $this->content);
|
$xs->element('title', null, $this->content);
|
||||||
|
|
||||||
$xs->raw($profile->asAtomAuthor());
|
if ($author) {
|
||||||
$xs->raw($profile->asActivityActor());
|
$xs->raw($profile->asAtomAuthor());
|
||||||
|
$xs->raw($profile->asActivityActor());
|
||||||
|
}
|
||||||
|
|
||||||
$xs->element('link', array('rel' => 'alternate',
|
$xs->element('link', array('rel' => 'alternate',
|
||||||
'type' => 'text/html',
|
'type' => 'text/html',
|
||||||
|
|
|
@ -743,6 +743,10 @@ class Profile extends Memcached_DataObject
|
||||||
case Right::CONFIGURESITE:
|
case Right::CONFIGURESITE:
|
||||||
$result = $this->hasRole(Profile_role::ADMINISTRATOR);
|
$result = $this->hasRole(Profile_role::ADMINISTRATOR);
|
||||||
break;
|
break;
|
||||||
|
case Right::GRANTROLE:
|
||||||
|
case Right::REVOKEROLE:
|
||||||
|
$result = $this->hasRole(Profile_role::OWNER);
|
||||||
|
break;
|
||||||
case Right::NEWNOTICE:
|
case Right::NEWNOTICE:
|
||||||
case Right::NEWMESSAGE:
|
case Right::NEWMESSAGE:
|
||||||
case Right::SUBSCRIBE:
|
case Right::SUBSCRIBE:
|
||||||
|
|
|
@ -53,4 +53,21 @@ class Profile_role extends Memcached_DataObject
|
||||||
const ADMINISTRATOR = 'administrator';
|
const ADMINISTRATOR = 'administrator';
|
||||||
const SANDBOXED = 'sandboxed';
|
const SANDBOXED = 'sandboxed';
|
||||||
const SILENCED = 'silenced';
|
const SILENCED = 'silenced';
|
||||||
|
|
||||||
|
public static function isValid($role)
|
||||||
|
{
|
||||||
|
// @fixme could probably pull this from class constants
|
||||||
|
$known = array(self::OWNER,
|
||||||
|
self::MODERATOR,
|
||||||
|
self::ADMINISTRATOR,
|
||||||
|
self::SANDBOXED,
|
||||||
|
self::SILENCED);
|
||||||
|
return in_array($role, $known);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isSettable($role)
|
||||||
|
{
|
||||||
|
$allowedRoles = array('administrator', 'moderator');
|
||||||
|
return self::isValid($role) && in_array($role, $allowedRoles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
86
install.php
86
install.php
|
@ -31,6 +31,7 @@
|
||||||
* @author Robin Millette <millette@controlyourself.ca>
|
* @author Robin Millette <millette@controlyourself.ca>
|
||||||
* @author Sarven Capadisli <csarven@status.net>
|
* @author Sarven Capadisli <csarven@status.net>
|
||||||
* @author Tom Adams <tom@holizz.com>
|
* @author Tom Adams <tom@holizz.com>
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
||||||
* @version 0.9.x
|
* @version 0.9.x
|
||||||
* @link http://status.net
|
* @link http://status.net
|
||||||
|
@ -490,15 +491,25 @@ function showForm()
|
||||||
<p class="form_guide">Database name</p>
|
<p class="form_guide">Database name</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="username">Username</label>
|
<label for="username">DB username</label>
|
||||||
<input type="text" id="username" name="username" />
|
<input type="text" id="username" name="username" />
|
||||||
<p class="form_guide">Database username</p>
|
<p class="form_guide">Database username</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="password">Password</label>
|
<label for="password">DB password</label>
|
||||||
<input type="password" id="password" name="password" />
|
<input type="password" id="password" name="password" />
|
||||||
<p class="form_guide">Database password (optional)</p>
|
<p class="form_guide">Database password (optional)</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="admin_nickname">Administrator nickname</label>
|
||||||
|
<input type="text" id="admin_nickname" name="admin_nickname" />
|
||||||
|
<p class="form_guide">Nickname for the initial StatusNet user (administrator)</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="initial_user_password">Administrator password</label>
|
||||||
|
<input type="password" id="admin_password" name="admin_password" />
|
||||||
|
<p class="form_guide">Password for the initial StatusNet user (administrator)</p>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<input type="submit" name="submit" class="submit" value="Submit" />
|
<input type="submit" name="submit" class="submit" value="Submit" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -521,6 +532,10 @@ function handlePost()
|
||||||
$password = $_POST['password'];
|
$password = $_POST['password'];
|
||||||
$sitename = $_POST['sitename'];
|
$sitename = $_POST['sitename'];
|
||||||
$fancy = !empty($_POST['fancy']);
|
$fancy = !empty($_POST['fancy']);
|
||||||
|
|
||||||
|
$adminNick = $_POST['admin_nickname'];
|
||||||
|
$adminPass = $_POST['admin_password'];
|
||||||
|
|
||||||
$server = $_SERVER['HTTP_HOST'];
|
$server = $_SERVER['HTTP_HOST'];
|
||||||
$path = substr(dirname($_SERVER['PHP_SELF']), 1);
|
$path = substr(dirname($_SERVER['PHP_SELF']), 1);
|
||||||
|
|
||||||
|
@ -552,6 +567,16 @@ STR;
|
||||||
$fail = true;
|
$fail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty($adminNick)) {
|
||||||
|
updateStatus("No initial StatusNet user nickname specified.", true);
|
||||||
|
$fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($adminPass)) {
|
||||||
|
updateStatus("No initial StatusNet user password specified.", true);
|
||||||
|
$fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
if ($fail) {
|
if ($fail) {
|
||||||
showForm();
|
showForm();
|
||||||
return;
|
return;
|
||||||
|
@ -574,13 +599,29 @@ STR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Okay, cross fingers and try to register an initial user
|
||||||
|
if (registerInitialUser($adminNick, $adminPass)) {
|
||||||
|
updateStatus(
|
||||||
|
"An initial user with the administrator role has been created."
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
updateStatus(
|
||||||
|
"Could not create initial StatusNet user (administrator).",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
showForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO https needs to be considered
|
TODO https needs to be considered
|
||||||
*/
|
*/
|
||||||
$link = "http://".$server.'/'.$path;
|
$link = "http://".$server.'/'.$path;
|
||||||
|
|
||||||
updateStatus("StatusNet has been installed at $link");
|
updateStatus("StatusNet has been installed at $link");
|
||||||
updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
|
updateStatus(
|
||||||
|
"You can visit your <a href='$link'>new StatusNet site</a> (login as '$adminNick')."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Pgsql_Db_installer($host, $database, $username, $password)
|
function Pgsql_Db_installer($host, $database, $username, $password)
|
||||||
|
@ -756,6 +797,33 @@ function runDbScript($filename, $conn, $type = 'mysqli')
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function registerInitialUser($nickname, $password)
|
||||||
|
{
|
||||||
|
define('STATUSNET', true);
|
||||||
|
define('LACONICA', true); // compatibility
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/common.php';
|
||||||
|
|
||||||
|
$user = User::register(
|
||||||
|
array('nickname' => $nickname,
|
||||||
|
'password' => $password,
|
||||||
|
'fullname' => $nickname
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (empty($user)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// give initial user carte blanche
|
||||||
|
|
||||||
|
$user->grantRole('owner');
|
||||||
|
$user->grantRole('moderator');
|
||||||
|
$user->grantRole('administrator');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
|
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
|
||||||
<!DOCTYPE html
|
<!DOCTYPE html
|
||||||
|
@ -765,10 +833,10 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
<head>
|
<head>
|
||||||
<title>Install StatusNet</title>
|
<title>Install StatusNet</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico"/>
|
<link rel="shortcut icon" href="favicon.ico"/>
|
||||||
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
|
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css" media="screen, projection, tv"/>
|
||||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
|
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css" /><![endif]-->
|
||||||
<!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
|
<!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css" /><![endif]-->
|
||||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
|
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css" /><![endif]-->
|
||||||
<script src="js/jquery.min.js"></script>
|
<script src="js/jquery.min.js"></script>
|
||||||
<script src="js/install.js"></script>
|
<script src="js/install.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -784,8 +852,10 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
</div>
|
</div>
|
||||||
<div id="core">
|
<div id="core">
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<h1>Install StatusNet</h1>
|
<div id="content_inner">
|
||||||
|
<h1>Install StatusNet</h1>
|
||||||
<?php main(); ?>
|
<?php main(); ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1064,6 +1064,18 @@ class Activity
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->entry = $entry;
|
$this->entry = $entry;
|
||||||
|
|
||||||
|
// @fixme Don't send in a DOMDocument
|
||||||
|
if ($feed instanceof DOMDocument) {
|
||||||
|
common_log(
|
||||||
|
LOG_WARNING,
|
||||||
|
'Activity::__construct() - '
|
||||||
|
. 'DOMDocument passed in for feed by mistake. '
|
||||||
|
. "Expecting a 'feed' DOMElement."
|
||||||
|
);
|
||||||
|
$feed = $feed->getElementsByTagName('feed')->item(0);
|
||||||
|
}
|
||||||
|
|
||||||
$this->feed = $feed;
|
$this->feed = $feed;
|
||||||
|
|
||||||
$pubEl = $this->_child($entry, self::PUBLISHED, self::ATOM);
|
$pubEl = $this->_child($entry, self::PUBLISHED, self::ATOM);
|
||||||
|
|
|
@ -381,6 +381,11 @@ class AdminPanelNav extends Widget
|
||||||
_('Edit site notice'), $action_name == 'sitenoticeadminpanel', 'nav_sitenotice_admin_panel');
|
_('Edit site notice'), $action_name == 'sitenoticeadminpanel', 'nav_sitenotice_admin_panel');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AdminPanelAction::canAdmin('snapshot')) {
|
||||||
|
$this->out->menuItem(common_local_url('snapshotadminpanel'), _('Snapshots'),
|
||||||
|
_('Snapshots configuration'), $action_name == 'snapshotadminpanel', 'nav_snapshot_admin_panel');
|
||||||
|
}
|
||||||
|
|
||||||
Event::handle('EndAdminPanelNav', array($this));
|
Event::handle('EndAdminPanelNav', array($this));
|
||||||
}
|
}
|
||||||
$this->action->elementEnd('ul');
|
$this->action->elementEnd('ul');
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* StatusNet, the distributed open-source microblogging tool
|
|
||||||
*
|
|
||||||
* Class for building / manipulating an Atom entry in memory
|
|
||||||
*
|
|
||||||
* 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 Feed
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Zach Copley <zach@status.net>
|
|
||||||
* @copyright 2010 StatusNet, Inc.
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Atom10EntryException extends Exception
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class for manipulating an Atom entry in memory. Get the entry as an XML
|
|
||||||
* string with Atom10Entry::getString().
|
|
||||||
*
|
|
||||||
* @category Feed
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Zach Copley <zach@status.net>
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
|
||||||
class Atom10Entry extends XMLStringer
|
|
||||||
{
|
|
||||||
private $namespaces;
|
|
||||||
private $categories;
|
|
||||||
private $content;
|
|
||||||
private $contributors;
|
|
||||||
private $id;
|
|
||||||
private $links;
|
|
||||||
private $published;
|
|
||||||
private $rights;
|
|
||||||
private $source;
|
|
||||||
private $summary;
|
|
||||||
private $title;
|
|
||||||
|
|
||||||
function __construct($indent = true) {
|
|
||||||
parent::__construct($indent);
|
|
||||||
$this->namespaces = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addNamespace($namespace, $uri)
|
|
||||||
{
|
|
||||||
$ns = array($namespace => $uri);
|
|
||||||
$this->namespaces = array_merge($this->namespaces, $ns);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initEntry()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function endEntry()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check that all required elements have been set, etc.
|
|
||||||
* Throws an Atom10EntryException if something's missing.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function validate()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getString()
|
|
||||||
{
|
|
||||||
$this->validate();
|
|
||||||
|
|
||||||
$this->initEntry();
|
|
||||||
$this->renderEntries();
|
|
||||||
$this->endEntry();
|
|
||||||
|
|
||||||
return $this->xw->outputMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -49,6 +49,8 @@ class Atom10FeedException extends Exception
|
||||||
class Atom10Feed extends XMLStringer
|
class Atom10Feed extends XMLStringer
|
||||||
{
|
{
|
||||||
public $xw;
|
public $xw;
|
||||||
|
|
||||||
|
// @fixme most of these should probably be read-only properties
|
||||||
private $namespaces;
|
private $namespaces;
|
||||||
private $authors;
|
private $authors;
|
||||||
private $subject;
|
private $subject;
|
||||||
|
@ -57,10 +59,12 @@ class Atom10Feed extends XMLStringer
|
||||||
private $generator;
|
private $generator;
|
||||||
private $icon;
|
private $icon;
|
||||||
private $links;
|
private $links;
|
||||||
private $logo;
|
private $selfLink;
|
||||||
|
private $selfLinkType;
|
||||||
|
public $logo;
|
||||||
private $rights;
|
private $rights;
|
||||||
private $subtitle;
|
public $subtitle;
|
||||||
private $title;
|
public $title;
|
||||||
private $published;
|
private $published;
|
||||||
private $updated;
|
private $updated;
|
||||||
private $entries;
|
private $entries;
|
||||||
|
@ -172,6 +176,14 @@ class Atom10Feed extends XMLStringer
|
||||||
}
|
}
|
||||||
$this->elementStart('feed', $commonAttrs);
|
$this->elementStart('feed', $commonAttrs);
|
||||||
|
|
||||||
|
$this->element(
|
||||||
|
'generator', array(
|
||||||
|
'url' => 'http://status.net',
|
||||||
|
'version' => STATUSNET_VERSION
|
||||||
|
),
|
||||||
|
'StatusNet'
|
||||||
|
);
|
||||||
|
|
||||||
$this->element('id', null, $this->id);
|
$this->element('id', null, $this->id);
|
||||||
$this->element('title', null, $this->title);
|
$this->element('title', null, $this->title);
|
||||||
$this->element('subtitle', null, $this->subtitle);
|
$this->element('subtitle', null, $this->subtitle);
|
||||||
|
@ -184,6 +196,10 @@ class Atom10Feed extends XMLStringer
|
||||||
|
|
||||||
$this->renderAuthors();
|
$this->renderAuthors();
|
||||||
|
|
||||||
|
if ($this->selfLink) {
|
||||||
|
$this->addLink($this->selfLink, array('rel' => 'self',
|
||||||
|
'type' => $this->selfLinkType));
|
||||||
|
}
|
||||||
$this->renderLinks();
|
$this->renderLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +269,12 @@ class Atom10Feed extends XMLStringer
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setSelfLink($url, $type='application/atom+xml')
|
||||||
|
{
|
||||||
|
$this->selfLink = $url;
|
||||||
|
$this->selfLinkType = $type;
|
||||||
|
}
|
||||||
|
|
||||||
function setTitle($title)
|
function setTitle($title)
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
|
|
|
@ -49,14 +49,42 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param Group $group the group for the feed (optional)
|
* @param Group $group the group for the feed
|
||||||
* @param boolean $indent flag to turn indenting on or off
|
* @param boolean $indent flag to turn indenting on or off
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function __construct($group = null, $indent = true) {
|
function __construct($group, $indent = true) {
|
||||||
parent::__construct($indent);
|
parent::__construct($indent);
|
||||||
$this->group = $group;
|
$this->group = $group;
|
||||||
|
|
||||||
|
$title = sprintf(_("%s timeline"), $group->nickname);
|
||||||
|
$this->setTitle($title);
|
||||||
|
|
||||||
|
$sitename = common_config('site', 'name');
|
||||||
|
$subtitle = sprintf(
|
||||||
|
_('Updates from %1$s on %2$s!'),
|
||||||
|
$group->nickname,
|
||||||
|
$sitename
|
||||||
|
);
|
||||||
|
$this->setSubtitle($subtitle);
|
||||||
|
|
||||||
|
$avatar = $group->homepage_logo;
|
||||||
|
$logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
||||||
|
$this->setLogo($logo);
|
||||||
|
|
||||||
|
$this->setUpdated('now');
|
||||||
|
|
||||||
|
$self = common_local_url('ApiTimelineGroup',
|
||||||
|
array('id' => $group->id,
|
||||||
|
'format' => 'atom'));
|
||||||
|
$this->setId($self);
|
||||||
|
$this->setSelfLink($self);
|
||||||
|
|
||||||
|
$this->addAuthorRaw($group->asAtomAuthor());
|
||||||
|
$this->setActivitySubject($group->asActivitySubject());
|
||||||
|
|
||||||
|
$this->addLink($group->homeUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroup()
|
function getGroup()
|
||||||
|
|
|
@ -107,9 +107,19 @@ class AtomNoticeFeed extends Atom10Feed
|
||||||
*/
|
*/
|
||||||
function addEntryFromNotice($notice)
|
function addEntryFromNotice($notice)
|
||||||
{
|
{
|
||||||
$this->addEntryRaw($notice->asAtomEntry());
|
$source = $this->showSource();
|
||||||
|
$author = $this->showAuthor();
|
||||||
|
|
||||||
|
$this->addEntryRaw($notice->asAtomEntry(false, $source, $author));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSource()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAuthor()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,23 +49,71 @@ class AtomUserNoticeFeed extends AtomNoticeFeed
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param User $user the user for the feed (optional)
|
* @param User $user the user for the feed
|
||||||
* @param boolean $indent flag to turn indenting on or off
|
* @param boolean $indent flag to turn indenting on or off
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function __construct($user = null, $indent = true) {
|
function __construct($user, $indent = true) {
|
||||||
parent::__construct($indent);
|
parent::__construct($indent);
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
if (!empty($user)) {
|
if (!empty($user)) {
|
||||||
$profile = $user->getProfile();
|
$profile = $user->getProfile();
|
||||||
$this->addAuthor($profile->nickname, $user->uri);
|
$this->addAuthor($profile->nickname, $user->uri);
|
||||||
|
$this->setActivitySubject($profile->asActivityNoun('subject'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$title = sprintf(_("%s timeline"), $user->nickname);
|
||||||
|
$this->setTitle($title);
|
||||||
|
|
||||||
|
$sitename = common_config('site', 'name');
|
||||||
|
$subtitle = sprintf(
|
||||||
|
_('Updates from %1$s on %2$s!'),
|
||||||
|
$user->nickname, $sitename
|
||||||
|
);
|
||||||
|
$this->setSubtitle($subtitle);
|
||||||
|
|
||||||
|
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||||
|
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||||
|
$this->setLogo($logo);
|
||||||
|
|
||||||
|
$this->setUpdated('now');
|
||||||
|
|
||||||
|
$this->addLink(
|
||||||
|
common_local_url(
|
||||||
|
'showstream',
|
||||||
|
array('nickname' => $user->nickname)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$self = common_local_url('ApiTimelineUser',
|
||||||
|
array('id' => $user->id,
|
||||||
|
'format' => 'atom'));
|
||||||
|
$this->setId($self);
|
||||||
|
$this->setSelfLink($self);
|
||||||
|
|
||||||
|
$this->addLink(
|
||||||
|
common_local_url('sup', null, null, $user->id),
|
||||||
|
array(
|
||||||
|
'rel' => 'http://api.friendfeed.com/2008/03#sup',
|
||||||
|
'type' => 'application/json'
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUser()
|
function getUser()
|
||||||
{
|
{
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSource()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAuthor()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
93
lib/grantroleform.php
Normal file
93
lib/grantroleform.php
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Form for granting a role
|
||||||
|
*
|
||||||
|
* 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 Form
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>, Brion Vibber <brion@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/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for sandboxing a user
|
||||||
|
*
|
||||||
|
* @category Form
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see UnSandboxForm
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GrantRoleForm extends ProfileActionForm
|
||||||
|
{
|
||||||
|
function __construct($role, $label, $writer, $profile, $r2args)
|
||||||
|
{
|
||||||
|
parent::__construct($writer, $profile, $r2args);
|
||||||
|
$this->role = $role;
|
||||||
|
$this->label = $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action this form provides
|
||||||
|
*
|
||||||
|
* @return string Name of the action, lowercased.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function target()
|
||||||
|
{
|
||||||
|
return 'grantrole';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the form
|
||||||
|
*
|
||||||
|
* @return string Title of the form, internationalized
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formData()
|
||||||
|
{
|
||||||
|
parent::formData();
|
||||||
|
$this->out->hidden('role', $this->role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the form
|
||||||
|
*
|
||||||
|
* @return string description of the form, internationalized
|
||||||
|
*/
|
||||||
|
|
||||||
|
function description()
|
||||||
|
{
|
||||||
|
return sprintf(_('Grant this user the "%s" role'), $this->label);
|
||||||
|
}
|
||||||
|
}
|
93
lib/revokeroleform.php
Normal file
93
lib/revokeroleform.php
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Form for revoking a role
|
||||||
|
*
|
||||||
|
* 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 Form
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>, Brion Vibber <brion@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/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for sandboxing a user
|
||||||
|
*
|
||||||
|
* @category Form
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see UnSandboxForm
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RevokeRoleForm extends ProfileActionForm
|
||||||
|
{
|
||||||
|
function __construct($role, $label, $writer, $profile, $r2args)
|
||||||
|
{
|
||||||
|
parent::__construct($writer, $profile, $r2args);
|
||||||
|
$this->role = $role;
|
||||||
|
$this->label = $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action this form provides
|
||||||
|
*
|
||||||
|
* @return string Name of the action, lowercased.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function target()
|
||||||
|
{
|
||||||
|
return 'revokerole';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the form
|
||||||
|
*
|
||||||
|
* @return string Title of the form, internationalized
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formData()
|
||||||
|
{
|
||||||
|
parent::formData();
|
||||||
|
$this->out->hidden('role', $this->role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the form
|
||||||
|
*
|
||||||
|
* @return string description of the form, internationalized
|
||||||
|
*/
|
||||||
|
|
||||||
|
function description()
|
||||||
|
{
|
||||||
|
return sprintf(_('Revoke the "%s" role from this user'), $this->label);
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,5 +58,7 @@ class Right
|
||||||
const EMAILONSUBSCRIBE = 'emailonsubscribe';
|
const EMAILONSUBSCRIBE = 'emailonsubscribe';
|
||||||
const EMAILONFAVE = 'emailonfave';
|
const EMAILONFAVE = 'emailonfave';
|
||||||
const MAKEGROUPADMIN = 'makegroupadmin';
|
const MAKEGROUPADMIN = 'makegroupadmin';
|
||||||
|
const GRANTROLE = 'grantrole';
|
||||||
|
const REVOKEROLE = 'revokerole';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@ class Router
|
||||||
'groupblock', 'groupunblock',
|
'groupblock', 'groupunblock',
|
||||||
'sandbox', 'unsandbox',
|
'sandbox', 'unsandbox',
|
||||||
'silence', 'unsilence',
|
'silence', 'unsilence',
|
||||||
|
'grantrole', 'revokerole',
|
||||||
'repeat',
|
'repeat',
|
||||||
'deleteuser',
|
'deleteuser',
|
||||||
'geocode',
|
'geocode',
|
||||||
|
@ -650,6 +651,7 @@ class Router
|
||||||
$m->connect('admin/paths', array('action' => 'pathsadminpanel'));
|
$m->connect('admin/paths', array('action' => 'pathsadminpanel'));
|
||||||
$m->connect('admin/sessions', array('action' => 'sessionsadminpanel'));
|
$m->connect('admin/sessions', array('action' => 'sessionsadminpanel'));
|
||||||
$m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel'));
|
$m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel'));
|
||||||
|
$m->connect('admin/snapshot', array('action' => 'snapshotadminpanel'));
|
||||||
|
|
||||||
$m->connect('getfile/:filename',
|
$m->connect('getfile/:filename',
|
||||||
array('action' => 'getfile'),
|
array('action' => 'getfile'),
|
||||||
|
|
|
@ -354,10 +354,10 @@ class StatusNet
|
||||||
|
|
||||||
class NoConfigException extends Exception
|
class NoConfigException extends Exception
|
||||||
{
|
{
|
||||||
public $config_files;
|
public $configFiles;
|
||||||
|
|
||||||
function __construct($msg, $config_files) {
|
function __construct($msg, $configFiles) {
|
||||||
parent::__construct($msg);
|
parent::__construct($msg);
|
||||||
$this->config_files = $config_files;
|
$this->configFiles = $configFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,6 +346,16 @@ class UserProfile extends Widget
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($cur->hasRight(Right::GRANTROLE)) {
|
||||||
|
$this->out->elementStart('li', 'entity_role');
|
||||||
|
$this->out->element('p', null, _('User role'));
|
||||||
|
$this->out->elementStart('ul');
|
||||||
|
$this->roleButton('administrator', _m('role', 'Administrator'));
|
||||||
|
$this->roleButton('moderator', _m('role', 'Moderator'));
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,6 +369,22 @@ class UserProfile extends Widget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function roleButton($role, $label)
|
||||||
|
{
|
||||||
|
list($action, $r2args) = $this->out->returnToArgs();
|
||||||
|
$r2args['action'] = $action;
|
||||||
|
|
||||||
|
$this->out->elementStart('li', "entity_role_$role");
|
||||||
|
if ($this->user->hasRole($role)) {
|
||||||
|
$rf = new RevokeRoleForm($role, $label, $this->out, $this->profile, $r2args);
|
||||||
|
$rf->show();
|
||||||
|
} else {
|
||||||
|
$rf = new GrantRoleForm($role, $label, $this->out, $this->profile, $r2args);
|
||||||
|
$rf->show();
|
||||||
|
}
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
function showRemoteSubscribeLink()
|
function showRemoteSubscribeLink()
|
||||||
{
|
{
|
||||||
$url = common_local_url('remotesubscribe',
|
$url = common_local_url('remotesubscribe',
|
||||||
|
|
|
@ -44,7 +44,9 @@ class OStatusPlugin extends Plugin
|
||||||
$m->connect('.well-known/host-meta',
|
$m->connect('.well-known/host-meta',
|
||||||
array('action' => 'hostmeta'));
|
array('action' => 'hostmeta'));
|
||||||
$m->connect('main/xrd',
|
$m->connect('main/xrd',
|
||||||
array('action' => 'xrd'));
|
array('action' => 'userxrd'));
|
||||||
|
$m->connect('main/ownerxrd',
|
||||||
|
array('action' => 'ownerxrd'));
|
||||||
$m->connect('main/ostatus',
|
$m->connect('main/ostatus',
|
||||||
array('action' => 'ostatusinit'));
|
array('action' => 'ostatusinit'));
|
||||||
$m->connect('main/ostatus?nickname=:nickname',
|
$m->connect('main/ostatus?nickname=:nickname',
|
||||||
|
@ -111,7 +113,7 @@ class OStatusPlugin extends Plugin
|
||||||
{
|
{
|
||||||
if ($action instanceof ShowstreamAction) {
|
if ($action instanceof ShowstreamAction) {
|
||||||
$acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server');
|
$acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server');
|
||||||
$url = common_local_url('xrd');
|
$url = common_local_url('userxrd');
|
||||||
$url.= '?uri='. $acct;
|
$url.= '?uri='. $acct;
|
||||||
|
|
||||||
header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="application/xrd+xml"');
|
header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="application/xrd+xml"');
|
||||||
|
|
|
@ -32,7 +32,7 @@ class HostMetaAction extends Action
|
||||||
parent::handle();
|
parent::handle();
|
||||||
|
|
||||||
$domain = common_config('site', 'server');
|
$domain = common_config('site', 'server');
|
||||||
$url = common_local_url('xrd');
|
$url = common_local_url('userxrd');
|
||||||
$url.= '?uri={uri}';
|
$url.= '?uri={uri}';
|
||||||
|
|
||||||
$xrd = new XRD();
|
$xrd = new XRD();
|
||||||
|
|
|
@ -72,9 +72,9 @@ class OStatusGroupAction extends OStatusSubAction
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('profile',
|
$this->input('profile',
|
||||||
_m('Group profile URL'),
|
_m('Join group'),
|
||||||
$this->profile_uri,
|
$this->profile_uri,
|
||||||
_m('Enter the profile URL of a group on another StatusNet site'));
|
_m("OStatus group's address, like http://example.net/group/nickname"));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,9 @@ class OStatusSubAction extends Action
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('profile',
|
$this->input('profile',
|
||||||
_m('Address or profile URL'),
|
_m('Subscribe to'),
|
||||||
$this->profile_uri,
|
$this->profile_uri,
|
||||||
_m('Enter the profile URL of a PubSubHubbub-enabled feed'));
|
_m("OStatus user's address, like nickname@example.com or http://example.net/nickname"));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
@ -244,25 +244,33 @@ class OStatusSubAction extends Action
|
||||||
} else if (Validate::uri($this->profile_uri)) {
|
} else if (Validate::uri($this->profile_uri)) {
|
||||||
$this->oprofile = Ostatus_profile::ensureProfile($this->profile_uri);
|
$this->oprofile = Ostatus_profile::ensureProfile($this->profile_uri);
|
||||||
} else {
|
} else {
|
||||||
$this->error = _m("Invalid address format.");
|
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
||||||
|
common_debug('Invalid address format.', __FILE__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (FeedSubBadURLException $e) {
|
} catch (FeedSubBadURLException $e) {
|
||||||
$this->error = _m('Invalid URL or could not reach server.');
|
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
||||||
|
common_debug('Invalid URL or could not reach server.', __FILE__);
|
||||||
} catch (FeedSubBadResponseException $e) {
|
} catch (FeedSubBadResponseException $e) {
|
||||||
$this->error = _m('Cannot read feed; server returned error.');
|
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||||
|
common_debug('Cannot read feed; server returned error.', __FILE__);
|
||||||
} catch (FeedSubEmptyException $e) {
|
} catch (FeedSubEmptyException $e) {
|
||||||
$this->error = _m('Cannot read feed; server returned an empty page.');
|
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||||
|
common_debug('Cannot read feed; server returned an empty page.', __FILE__);
|
||||||
} catch (FeedSubBadHTMLException $e) {
|
} catch (FeedSubBadHTMLException $e) {
|
||||||
$this->error = _m('Bad HTML, could not find feed link.');
|
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||||
|
common_debug('Bad HTML, could not find feed link.', __FILE__);
|
||||||
} catch (FeedSubNoFeedException $e) {
|
} catch (FeedSubNoFeedException $e) {
|
||||||
$this->error = _m('Could not find a feed linked from this URL.');
|
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||||
|
common_debug('Could not find a feed linked from this URL.', __FILE__);
|
||||||
} catch (FeedSubUnrecognizedTypeException $e) {
|
} catch (FeedSubUnrecognizedTypeException $e) {
|
||||||
$this->error = _m('Not a recognized feed type.');
|
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||||
} catch (FeedSubException $e) {
|
common_debug('Not a recognized feed type.', __FILE__);
|
||||||
|
} catch (Exception $e) {
|
||||||
// Any new ones we forgot about
|
// Any new ones we forgot about
|
||||||
$this->error = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage());
|
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
||||||
|
common_debug(sprintf('Bad feed URL: %s %s', get_class($e), $e->getMessage()), __FILE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -315,7 +323,6 @@ class OStatusSubAction extends Action
|
||||||
if ($this->pullRemoteProfile()) {
|
if ($this->pullRemoteProfile()) {
|
||||||
$this->validateRemoteProfile();
|
$this->validateRemoteProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +398,7 @@ class OStatusSubAction extends Action
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
// TRANS: Page title for OStatus remote subscription form
|
// TRANS: Page title for OStatus remote subscription form
|
||||||
return _m('Authorize subscription');
|
return _m('Confirm');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
56
plugins/OStatus/actions/ownerxrd.php
Normal file
56
plugins/OStatus/actions/ownerxrd.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 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
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package OStatusPlugin
|
||||||
|
* @maintainer James Walker <james@status.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
class OwnerxrdAction extends XrdAction
|
||||||
|
{
|
||||||
|
|
||||||
|
public $uri;
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
$this->user = User::siteOwner();
|
||||||
|
|
||||||
|
if (!$this->user) {
|
||||||
|
$this->clientError(_('No such user.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nick = common_canonical_nickname($this->user->nickname);
|
||||||
|
$acct = 'acct:' . $nick . '@' . common_config('site', 'server');
|
||||||
|
|
||||||
|
$this->xrd = new XRD();
|
||||||
|
|
||||||
|
// Check to see if a $config['webfinger']['owner'] has been set
|
||||||
|
if ($owner = common_config('webfinger', 'owner')) {
|
||||||
|
$this->xrd->subject = Discovery::normalize($owner);
|
||||||
|
$this->xrd->alias[] = $acct;
|
||||||
|
} else {
|
||||||
|
$this->xrd->subject = $acct;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
48
plugins/OStatus/actions/userxrd.php
Normal file
48
plugins/OStatus/actions/userxrd.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 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
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package OStatusPlugin
|
||||||
|
* @maintainer James Walker <james@status.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) { exit(1); }
|
||||||
|
|
||||||
|
class UserxrdAction extends XrdAction
|
||||||
|
{
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$this->uri = $this->trimmed('uri');
|
||||||
|
$acct = Discovery::normalize($this->uri);
|
||||||
|
|
||||||
|
list($nick, $domain) = explode('@', substr(urldecode($acct), 5));
|
||||||
|
$nick = common_canonical_nickname($nick);
|
||||||
|
|
||||||
|
$this->user = User::staticGet('nickname', $nick);
|
||||||
|
if (!$this->user) {
|
||||||
|
$this->clientError(_('No such user.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1267,6 +1267,11 @@ class Ostatus_profile extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $addr webfinger address
|
||||||
|
* @return Ostatus_profile
|
||||||
|
* @throws Exception on error conditions
|
||||||
|
*/
|
||||||
public static function ensureWebfinger($addr)
|
public static function ensureWebfinger($addr)
|
||||||
{
|
{
|
||||||
// First, try the cache
|
// First, try the cache
|
||||||
|
@ -1275,7 +1280,8 @@ class Ostatus_profile extends Memcached_DataObject
|
||||||
|
|
||||||
if ($uri !== false) {
|
if ($uri !== false) {
|
||||||
if (is_null($uri)) {
|
if (is_null($uri)) {
|
||||||
return null;
|
// Negative cache entry
|
||||||
|
throw new Exception('Not a valid webfinger address.');
|
||||||
}
|
}
|
||||||
$oprofile = Ostatus_profile::staticGet('uri', $uri);
|
$oprofile = Ostatus_profile::staticGet('uri', $uri);
|
||||||
if (!empty($oprofile)) {
|
if (!empty($oprofile)) {
|
||||||
|
@ -1299,20 +1305,24 @@ class Ostatus_profile extends Memcached_DataObject
|
||||||
try {
|
try {
|
||||||
$result = $disco->lookup($addr);
|
$result = $disco->lookup($addr);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
// Save negative cache entry so we don't waste time looking it up again.
|
||||||
|
// @fixme distinguish temporary failures?
|
||||||
self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null);
|
self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null);
|
||||||
return null;
|
throw new Exception('Not a valid webfinger address.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hints = array('webfinger' => $addr);
|
||||||
|
|
||||||
foreach ($result->links as $link) {
|
foreach ($result->links as $link) {
|
||||||
switch ($link['rel']) {
|
switch ($link['rel']) {
|
||||||
case Discovery::PROFILEPAGE:
|
case Discovery::PROFILEPAGE:
|
||||||
$profileUrl = $link['href'];
|
$hints['profileurl'] = $profileUrl = $link['href'];
|
||||||
break;
|
break;
|
||||||
case Salmon::NS_REPLIES:
|
case Salmon::NS_REPLIES:
|
||||||
$salmonEndpoint = $link['href'];
|
$hints['salmon'] = $salmonEndpoint = $link['href'];
|
||||||
break;
|
break;
|
||||||
case Discovery::UPDATESFROM:
|
case Discovery::UPDATESFROM:
|
||||||
$feedUrl = $link['href'];
|
$hints['feedurl'] = $feedUrl = $link['href'];
|
||||||
break;
|
break;
|
||||||
case Discovery::HCARD:
|
case Discovery::HCARD:
|
||||||
$hcardUrl = $link['href'];
|
$hcardUrl = $link['href'];
|
||||||
|
@ -1323,11 +1333,6 @@ class Ostatus_profile extends Memcached_DataObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$hints = array('webfinger' => $addr,
|
|
||||||
'profileurl' => $profileUrl,
|
|
||||||
'feedurl' => $feedUrl,
|
|
||||||
'salmon' => $salmonEndpoint);
|
|
||||||
|
|
||||||
if (isset($hcardUrl)) {
|
if (isset($hcardUrl)) {
|
||||||
$hcardHints = self::slurpHcard($hcardUrl);
|
$hcardHints = self::slurpHcard($hcardUrl);
|
||||||
// Note: Webfinger > hcard
|
// Note: Webfinger > hcard
|
||||||
|
@ -1410,7 +1415,7 @@ class Ostatus_profile extends Memcached_DataObject
|
||||||
return $oprofile;
|
return $oprofile;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
throw new Exception("Couldn't find a valid profile for '$addr'");
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveHTMLFile($title, $rendered)
|
function saveHTMLFile($title, $rendered)
|
||||||
|
|
|
@ -156,17 +156,31 @@ class MagicEnvelope
|
||||||
public function verify($env)
|
public function verify($env)
|
||||||
{
|
{
|
||||||
if ($env['alg'] != 'RSA-SHA256') {
|
if ($env['alg'] != 'RSA-SHA256') {
|
||||||
|
common_log(LOG_DEBUG, "Salmon error: bad algorithm");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($env['encoding'] != MagicEnvelope::ENCODING) {
|
if ($env['encoding'] != MagicEnvelope::ENCODING) {
|
||||||
|
common_log(LOG_DEBUG, "Salmon error: bad encoding");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = base64_decode($env['data']);
|
$text = base64_decode($env['data']);
|
||||||
$signer_uri = $this->getAuthor($text);
|
$signer_uri = $this->getAuthor($text);
|
||||||
|
|
||||||
$verifier = Magicsig::fromString($this->getKeyPair($signer_uri));
|
try {
|
||||||
|
$keypair = $this->getKeyPair($signer_uri);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_DEBUG, "Salmon error: ".$e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$verifier = Magicsig::fromString($keypair);
|
||||||
|
|
||||||
|
if (!$verifier) {
|
||||||
|
common_log(LOG_DEBUG, "Salmon error: unable to parse keypair");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return $verifier->verify($env['data'], $env['sig']);
|
return $verifier->verify($env['data'], $env['sig']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,46 +164,21 @@ class OStatusQueueHandler extends QueueHandler
|
||||||
*/
|
*/
|
||||||
function userFeedForNotice()
|
function userFeedForNotice()
|
||||||
{
|
{
|
||||||
// @fixme this feels VERY hacky...
|
$atom = new AtomUserNoticeFeed($this->user);
|
||||||
// should probably be a cleaner way to do it
|
$atom->addEntryFromNotice($this->notice);
|
||||||
|
$feed = $atom->getString();
|
||||||
|
|
||||||
ob_start();
|
|
||||||
$api = new ApiTimelineUserAction();
|
|
||||||
$api->prepare(array('id' => $this->notice->profile_id,
|
|
||||||
'format' => 'atom',
|
|
||||||
'max_id' => $this->notice->id,
|
|
||||||
'since_id' => $this->notice->id - 1));
|
|
||||||
$api->showTimeline();
|
|
||||||
$feed = ob_get_clean();
|
|
||||||
|
|
||||||
// ...and override the content-type back to something normal... eww!
|
|
||||||
// hope there's no other headers that got set while we weren't looking.
|
|
||||||
header('Content-Type: text/html; charset=utf-8');
|
|
||||||
|
|
||||||
common_log(LOG_DEBUG, $feed);
|
|
||||||
return $feed;
|
return $feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupFeedForNotice($group_id)
|
function groupFeedForNotice($group_id)
|
||||||
{
|
{
|
||||||
// @fixme this feels VERY hacky...
|
$group = User_group::staticGet('id', $group_id);
|
||||||
// should probably be a cleaner way to do it
|
|
||||||
|
|
||||||
ob_start();
|
$atom = new AtomGroupNoticeFeed($group);
|
||||||
$api = new ApiTimelineGroupAction();
|
$atom->addEntryFromNotice($this->notice);
|
||||||
$args = array('id' => $group_id,
|
$feed = $atom->getString();
|
||||||
'format' => 'atom',
|
|
||||||
'max_id' => $this->notice->id,
|
|
||||||
'since_id' => $this->notice->id - 1);
|
|
||||||
$api->prepare($args);
|
|
||||||
$api->handle($args);
|
|
||||||
$feed = ob_get_clean();
|
|
||||||
|
|
||||||
// ...and override the content-type back to something normal... eww!
|
|
||||||
// hope there's no other headers that got set while we weren't looking.
|
|
||||||
header('Content-Type: text/html; charset=utf-8');
|
|
||||||
|
|
||||||
common_log(LOG_DEBUG, $feed);
|
|
||||||
return $feed;
|
return $feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,9 @@ class XRD
|
||||||
throw new Exception("Invalid XML");
|
throw new Exception("Invalid XML");
|
||||||
}
|
}
|
||||||
$xrd_element = $dom->getElementsByTagName('XRD')->item(0);
|
$xrd_element = $dom->getElementsByTagName('XRD')->item(0);
|
||||||
|
if (!$xrd_element) {
|
||||||
|
throw new Exception("Invalid XML, missing XRD root");
|
||||||
|
}
|
||||||
|
|
||||||
// Check for host-meta host
|
// Check for host-meta host
|
||||||
$host = $xrd_element->getElementsByTagName('Host')->item(0);
|
$host = $xrd_element->getElementsByTagName('Host')->item(0);
|
||||||
|
|
|
@ -29,31 +29,23 @@ class XrdAction extends Action
|
||||||
|
|
||||||
public $uri;
|
public $uri;
|
||||||
|
|
||||||
function prepare($args)
|
public $user;
|
||||||
{
|
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$this->uri = $this->trimmed('uri');
|
public $xrd;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle()
|
function handle()
|
||||||
{
|
{
|
||||||
$acct = Discovery::normalize($this->uri);
|
$nick = $this->user->nickname;
|
||||||
|
|
||||||
$xrd = new XRD();
|
if (empty($this->xrd)) {
|
||||||
|
$xrd = new XRD();
|
||||||
list($nick, $domain) = explode('@', substr(urldecode($acct), 5));
|
} else {
|
||||||
$nick = common_canonical_nickname($nick);
|
$xrd = $this->xrd;
|
||||||
|
|
||||||
$this->user = User::staticGet('nickname', $nick);
|
|
||||||
if (!$this->user) {
|
|
||||||
$this->clientError(_('No such user.'), 404);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$xrd->subject = $this->uri;
|
if (empty($xrd->subject)) {
|
||||||
|
$xrd->subject = Discovery::normalize($this->uri);
|
||||||
|
}
|
||||||
$xrd->alias[] = common_profile_url($nick);
|
$xrd->alias[] = common_profile_url($nick);
|
||||||
$xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
|
$xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
|
||||||
'type' => 'text/html',
|
'type' => 'text/html',
|
|
@ -52,7 +52,8 @@ margin-bottom:0;
|
||||||
width:405px;
|
width:405px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aside #entity_subscriptions .more {
|
.aside #entity_subscriptions .more,
|
||||||
|
.aside #entity_groups .more {
|
||||||
float:left;
|
float:left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
131
tests/UserFeedParseTest.php
Normal file
131
tests/UserFeedParseTest.php
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
print "This script must be run from the command line\n";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
|
define('STATUSNET', true);
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/common.php';
|
||||||
|
|
||||||
|
class UserFeedParseTests extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testFeed1()
|
||||||
|
{
|
||||||
|
global $_testfeed1;
|
||||||
|
$dom = DOMDocument::loadXML($_testfeed1);
|
||||||
|
$this->assertFalse(empty($dom));
|
||||||
|
|
||||||
|
$entries = $dom->getElementsByTagName('entry');
|
||||||
|
|
||||||
|
$entry1 = $entries->item(0);
|
||||||
|
$this->assertFalse(empty($entry1));
|
||||||
|
|
||||||
|
$feedEl = $dom->getElementsByTagName('feed')->item(0);
|
||||||
|
$this->assertFalse(empty($feedEl));
|
||||||
|
|
||||||
|
// Test actor (from activity:subject)
|
||||||
|
|
||||||
|
$act1 = new Activity($entry1, $feedEl);
|
||||||
|
$this->assertFalse(empty($act1));
|
||||||
|
$this->assertFalse(empty($act1->actor));
|
||||||
|
$this->assertEquals($act1->actor->type, ActivityObject::PERSON);
|
||||||
|
$this->assertEquals($act1->actor->title, 'Zach Copley');
|
||||||
|
$this->assertEquals($act1->actor->id, 'http://localhost/statusnet/user/1');
|
||||||
|
$this->assertEquals($act1->actor->link, 'http://localhost/statusnet/zach');
|
||||||
|
|
||||||
|
$avatars = $act1->actor->avatarLinks;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$avatars[0]->url,
|
||||||
|
'http://localhost/statusnet/theme/default/default-avatar-profile.png'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$avatars[1]->url,
|
||||||
|
'http://localhost/statusnet/theme/default/default-avatar-stream.png'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$avatars[2]->url,
|
||||||
|
'http://localhost/statusnet/theme/default/default-avatar-mini.png'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals($act1->actor->displayName, 'Zach Copley');
|
||||||
|
|
||||||
|
$poco = $act1->actor->poco;
|
||||||
|
$this->assertEquals($poco->preferredUsername, 'zach');
|
||||||
|
$this->assertEquals($poco->address->formatted, 'El Cerrito, CA');
|
||||||
|
$this->assertEquals($poco->urls[0]->type, 'homepage');
|
||||||
|
$this->assertEquals($poco->urls[0]->value, 'http://zach.copley.name');
|
||||||
|
$this->assertEquals($poco->urls[0]->primary, 'true');
|
||||||
|
$this->assertEquals($poco->note, 'Zach Hack Attack');
|
||||||
|
|
||||||
|
// test the post
|
||||||
|
|
||||||
|
//var_export($act1);
|
||||||
|
$this->assertEquals($act1->object->type, 'http://activitystrea.ms/schema/1.0/note');
|
||||||
|
$this->assertEquals($act1->object->title, 'And now for something completely insane...');
|
||||||
|
|
||||||
|
$this->assertEquals($act1->object->content, 'And now for something completely insane...');
|
||||||
|
$this->assertEquals($act1->object->id, 'http://localhost/statusnet/notice/3');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$_testfeed1 = <<<TESTFEED1
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
|
||||||
|
<id>http://localhost/statusnet/api/statuses/user_timeline/1.atom</id>
|
||||||
|
<title>zach timeline</title>
|
||||||
|
<subtitle>Updates from zach on Zach Dev!</subtitle>
|
||||||
|
<logo>http://localhost/statusnet/theme/default/default-avatar-profile.png</logo>
|
||||||
|
<updated>2010-03-04T01:41:14+00:00</updated>
|
||||||
|
<author>
|
||||||
|
<name>zach</name>
|
||||||
|
<uri>http://localhost/statusnet/user/1</uri>
|
||||||
|
|
||||||
|
</author>
|
||||||
|
<link href="http://localhost/statusnet/zach" rel="alternate" type="text/html"/>
|
||||||
|
<link href="http://localhost/statusnet/main/sup#1" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
|
||||||
|
<link href="http://localhost/statusnet/main/push/hub" rel="hub"/>
|
||||||
|
<link href="http://localhost/statusnet/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
|
||||||
|
<link href="http://localhost/statusnet/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
|
||||||
|
<link href="http://localhost/statusnet/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
|
||||||
|
<activity:subject>
|
||||||
|
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||||
|
<id>http://localhost/statusnet/user/1</id>
|
||||||
|
<title>Zach Copley</title>
|
||||||
|
<link rel="alternate" type="text/html" href="http://localhost/statusnet/zach"/>
|
||||||
|
<link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://localhost/statusnet/theme/default/default-avatar-profile.png"/>
|
||||||
|
<link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://localhost/statusnet/theme/default/default-avatar-stream.png"/>
|
||||||
|
<link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://localhost/statusnet/theme/default/default-avatar-mini.png"/>
|
||||||
|
|
||||||
|
<poco:preferredUsername>zach</poco:preferredUsername>
|
||||||
|
<poco:displayName>Zach Copley</poco:displayName>
|
||||||
|
<poco:note>Zach Hack Attack</poco:note>
|
||||||
|
<poco:address>
|
||||||
|
<poco:formatted>El Cerrito, CA</poco:formatted>
|
||||||
|
</poco:address>
|
||||||
|
<poco:urls>
|
||||||
|
<poco:type>homepage</poco:type>
|
||||||
|
<poco:value>http://zach.copley.name</poco:value>
|
||||||
|
<poco:primary>true</poco:primary>
|
||||||
|
|
||||||
|
</poco:urls>
|
||||||
|
</activity:subject>
|
||||||
|
<entry>
|
||||||
|
<title>And now for something completely insane...</title>
|
||||||
|
<link rel="alternate" type="text/html" href="http://localhost/statusnet/notice/3"/>
|
||||||
|
<id>http://localhost/statusnet/notice/3</id>
|
||||||
|
<published>2010-03-04T01:41:07+00:00</published>
|
||||||
|
<updated>2010-03-04T01:41:07+00:00</updated>
|
||||||
|
<link rel="ostatus:conversation" href="http://localhost/statusnet/conversation/3"/>
|
||||||
|
<content type="html">And now for something completely insane...</content>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
</feed>
|
||||||
|
TESTFEED1;
|
|
@ -771,10 +771,12 @@ display:none;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity_moderation {
|
.entity_moderation,
|
||||||
|
.entity_role {
|
||||||
position:relative;
|
position:relative;
|
||||||
}
|
}
|
||||||
.entity_moderation p {
|
.entity_moderation p,
|
||||||
|
.entity_role p {
|
||||||
border-radius:4px;
|
border-radius:4px;
|
||||||
-moz-border-radius:4px;
|
-moz-border-radius:4px;
|
||||||
-webkit-border-radius:4px;
|
-webkit-border-radius:4px;
|
||||||
|
@ -782,13 +784,14 @@ font-weight:bold;
|
||||||
padding-bottom:2px;
|
padding-bottom:2px;
|
||||||
margin-bottom:7px;
|
margin-bottom:7px;
|
||||||
}
|
}
|
||||||
.entity_moderation ul {
|
.entity_moderation ul,
|
||||||
|
.entity_role ul {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
.entity_moderation:hover ul {
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul {
|
||||||
display:block;
|
display:block;
|
||||||
min-width:21%;
|
width:110%;
|
||||||
width:100%;
|
|
||||||
padding:11px;
|
padding:11px;
|
||||||
position:absolute;
|
position:absolute;
|
||||||
top:-1px;
|
top:-1px;
|
||||||
|
|
|
@ -45,6 +45,11 @@
|
||||||
White pin with green background
|
White pin with green background
|
||||||
White underscore with green background
|
White underscore with green background
|
||||||
White C with green background
|
White C with green background
|
||||||
|
White magic wand with green background
|
||||||
|
Green badge with white background
|
||||||
|
Green sandbox with white background
|
||||||
|
Green speech bubble broken with white background
|
||||||
|
Green person with tie with white background
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Created by various authors
|
Created by various authors
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.0 KiB |
|
@ -49,6 +49,7 @@ box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
|
||||||
.pagination .nav_next a,
|
.pagination .nav_next a,
|
||||||
.form_settings fieldset fieldset,
|
.form_settings fieldset fieldset,
|
||||||
.entity_moderation:hover ul,
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul,
|
||||||
.dialogbox {
|
.dialogbox {
|
||||||
border-color:#DDDDDD;
|
border-color:#DDDDDD;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +68,7 @@ input.submit,
|
||||||
.entity_actions a,
|
.entity_actions a,
|
||||||
.entity_actions input,
|
.entity_actions input,
|
||||||
.entity_moderation p,
|
.entity_moderation p,
|
||||||
|
.entity_role p,
|
||||||
button {
|
button {
|
||||||
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
||||||
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
||||||
|
@ -127,7 +129,8 @@ a,
|
||||||
.notice-options input,
|
.notice-options input,
|
||||||
.entity_actions a,
|
.entity_actions a,
|
||||||
.entity_actions input,
|
.entity_actions input,
|
||||||
.entity_moderation p {
|
.entity_moderation p,
|
||||||
|
.entity_role p {
|
||||||
color:#002FA7;
|
color:#002FA7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +193,9 @@ button.close,
|
||||||
.entity_sandbox input.submit,
|
.entity_sandbox input.submit,
|
||||||
.entity_silence input.submit,
|
.entity_silence input.submit,
|
||||||
.entity_delete input.submit,
|
.entity_delete input.submit,
|
||||||
|
.entity_role p,
|
||||||
|
.entity_role_administrator input.submit,
|
||||||
|
.entity_role_moderator input.submit,
|
||||||
.notice-options .repeated,
|
.notice-options .repeated,
|
||||||
.form_notice label[for=notice_data-geo],
|
.form_notice label[for=notice_data-geo],
|
||||||
button.minimize,
|
button.minimize,
|
||||||
|
@ -229,6 +235,7 @@ border-color:transparent;
|
||||||
#site_nav_local_views .current a,
|
#site_nav_local_views .current a,
|
||||||
.entity_send-a-message .form_notice,
|
.entity_send-a-message .form_notice,
|
||||||
.entity_moderation:hover ul,
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul,
|
||||||
.dialogbox {
|
.dialogbox {
|
||||||
background-color:#FFFFFF;
|
background-color:#FFFFFF;
|
||||||
}
|
}
|
||||||
|
@ -319,6 +326,7 @@ background-position: 5px -852px;
|
||||||
}
|
}
|
||||||
.entity_send-a-message .form_notice,
|
.entity_send-a-message .form_notice,
|
||||||
.entity_moderation:hover ul,
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul,
|
||||||
.dialogbox {
|
.dialogbox {
|
||||||
box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
||||||
-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
||||||
|
@ -350,6 +358,27 @@ background-position: 5px -1445px;
|
||||||
.entity_delete input.submit {
|
.entity_delete input.submit {
|
||||||
background-position: 5px -1511px;
|
background-position: 5px -1511px;
|
||||||
}
|
}
|
||||||
|
.entity_sandbox .form_user_unsandbox input.submit {
|
||||||
|
background-position: 5px -2568px;
|
||||||
|
}
|
||||||
|
.entity_silence .form_user_unsilence input.submit {
|
||||||
|
background-position: 5px -2633px;
|
||||||
|
}
|
||||||
|
.entity_role p {
|
||||||
|
background-position: 5px -2436px;
|
||||||
|
}
|
||||||
|
.entity_role_administrator .form_user_grantrole input.submit {
|
||||||
|
background-position: 5px -983px;
|
||||||
|
}
|
||||||
|
.entity_role_moderator .form_user_grantrole input.submit {
|
||||||
|
background-position: 5px -1313px;
|
||||||
|
}
|
||||||
|
.entity_role_administrator .form_user_revokerole input.submit {
|
||||||
|
background-position: 5px -2699px;
|
||||||
|
}
|
||||||
|
.entity_role_moderator .form_user_revokerole input.submit {
|
||||||
|
background-position: 5px -2501px;
|
||||||
|
}
|
||||||
.form_reset_key input.submit {
|
.form_reset_key input.submit {
|
||||||
background-position: 5px -1973px;
|
background-position: 5px -1973px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
|
||||||
.pagination .nav_next a,
|
.pagination .nav_next a,
|
||||||
.form_settings fieldset fieldset,
|
.form_settings fieldset fieldset,
|
||||||
.entity_moderation:hover ul,
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul,
|
||||||
.dialogbox {
|
.dialogbox {
|
||||||
border-color:#DDDDDD;
|
border-color:#DDDDDD;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +68,7 @@ input.submit,
|
||||||
.entity_actions a,
|
.entity_actions a,
|
||||||
.entity_actions input,
|
.entity_actions input,
|
||||||
.entity_moderation p,
|
.entity_moderation p,
|
||||||
|
.entity_role p,
|
||||||
button {
|
button {
|
||||||
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
||||||
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
|
||||||
|
@ -128,7 +130,8 @@ a,
|
||||||
.notice-options input,
|
.notice-options input,
|
||||||
.entity_actions a,
|
.entity_actions a,
|
||||||
.entity_actions input,
|
.entity_actions input,
|
||||||
.entity_moderation p {
|
.entity_moderation p,
|
||||||
|
.entity_role p {
|
||||||
color:#002FA7;
|
color:#002FA7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +194,9 @@ button.close,
|
||||||
.entity_sandbox input.submit,
|
.entity_sandbox input.submit,
|
||||||
.entity_silence input.submit,
|
.entity_silence input.submit,
|
||||||
.entity_delete input.submit,
|
.entity_delete input.submit,
|
||||||
|
.entity_role p,
|
||||||
|
.entity_role_administrator input.submit,
|
||||||
|
.entity_role_moderator input.submit,
|
||||||
.notice-options .repeated,
|
.notice-options .repeated,
|
||||||
.form_notice label[for=notice_data-geo],
|
.form_notice label[for=notice_data-geo],
|
||||||
button.minimize,
|
button.minimize,
|
||||||
|
@ -230,6 +236,7 @@ border-color:transparent;
|
||||||
#site_nav_local_views .current a,
|
#site_nav_local_views .current a,
|
||||||
.entity_send-a-message .form_notice,
|
.entity_send-a-message .form_notice,
|
||||||
.entity_moderation:hover ul,
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul,
|
||||||
.dialogbox {
|
.dialogbox {
|
||||||
background-color:#FFFFFF;
|
background-color:#FFFFFF;
|
||||||
}
|
}
|
||||||
|
@ -319,6 +326,7 @@ background-position: 5px -852px;
|
||||||
}
|
}
|
||||||
.entity_send-a-message .form_notice,
|
.entity_send-a-message .form_notice,
|
||||||
.entity_moderation:hover ul,
|
.entity_moderation:hover ul,
|
||||||
|
.entity_role:hover ul,
|
||||||
.dialogbox {
|
.dialogbox {
|
||||||
box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
||||||
-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7);
|
||||||
|
@ -350,6 +358,27 @@ background-position: 5px -1445px;
|
||||||
.entity_delete input.submit {
|
.entity_delete input.submit {
|
||||||
background-position: 5px -1511px;
|
background-position: 5px -1511px;
|
||||||
}
|
}
|
||||||
|
.entity_sandbox .form_user_unsandbox input.submit {
|
||||||
|
background-position: 5px -2568px;
|
||||||
|
}
|
||||||
|
.entity_silence .form_user_unsilence input.submit {
|
||||||
|
background-position: 5px -2633px;
|
||||||
|
}
|
||||||
|
.entity_role p {
|
||||||
|
background-position: 5px -2436px;
|
||||||
|
}
|
||||||
|
.entity_role_administrator .form_user_grantrole input.submit {
|
||||||
|
background-position: 5px -983px;
|
||||||
|
}
|
||||||
|
.entity_role_moderator .form_user_grantrole input.submit {
|
||||||
|
background-position: 5px -1313px;
|
||||||
|
}
|
||||||
|
.entity_role_administrator .form_user_revokerole input.submit {
|
||||||
|
background-position: 5px -2699px;
|
||||||
|
}
|
||||||
|
.entity_role_moderator .form_user_revokerole input.submit {
|
||||||
|
background-position: 5px -2501px;
|
||||||
|
}
|
||||||
.form_reset_key input.submit {
|
.form_reset_key input.submit {
|
||||||
background-position: 5px -1973px;
|
background-position: 5px -1973px;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user