forked from GNUsocial/gnu-social
Merge commit 'origin/testing' into 0.9.x
Conflicts: lib/action.php lib/adminpanelaction.php
This commit is contained in:
commit
b218aee94e
26
EVENTS.txt
26
EVENTS.txt
@ -363,6 +363,14 @@ EndProfileRemoteSubscribe: After showing the link to remote subscription
|
||||
- $userprofile: UserProfile widget
|
||||
- &$profile: the profile being shown
|
||||
|
||||
StartGroupSubscribe: Before showing the link to remote subscription
|
||||
- $action: the current action
|
||||
- $group: the group being shown
|
||||
|
||||
EndGroupSubscribe: After showing the link to remote subscription
|
||||
- $action: the current action
|
||||
- $group: the group being shown
|
||||
|
||||
StartProfilePageProfileSection: Starting to show the section of the
|
||||
profile page with the actual profile data;
|
||||
hook to prevent showing the profile (e.g.)
|
||||
@ -770,12 +778,30 @@ StartShowSubscriptionsContent: before showing the subscriptions content
|
||||
EndShowSubscriptionsContent: after showing the subscriptions content
|
||||
- $action: the current action
|
||||
|
||||
StartShowUserGroupsContent: before showing the user groups content
|
||||
- $action: the current action
|
||||
|
||||
EndShowUserGroupsContent: after showing the user groups content
|
||||
- $action: the current action
|
||||
|
||||
StartShowAllContent: before showing the all (you and friends) content
|
||||
- $action: the current action
|
||||
|
||||
EndShowAllContent: after showing the all (you and friends) content
|
||||
- $action: the current action
|
||||
|
||||
StartShowSubscriptionsMiniList: at the start of subscriptions mini list
|
||||
- $action: the current action
|
||||
|
||||
EndShowSubscriptionsMiniList: at the end of subscriptions mini list
|
||||
- $action: the current action
|
||||
|
||||
StartShowGroupsMiniList: at the start of groups mini list
|
||||
- $action: the current action
|
||||
|
||||
EndShowGroupsMiniList: at the end of groups mini list
|
||||
- $action: the current action
|
||||
|
||||
StartDeleteUserForm: starting the data in the form for deleting a user
|
||||
- $action: action being shown
|
||||
- $user: user being deleted
|
||||
|
@ -83,6 +83,7 @@ class AllrssAction extends Rss10Action
|
||||
function getNotices($limit=0)
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$user = $this->user;
|
||||
|
||||
if (!empty($cur) && $cur->id == $user->id) {
|
||||
$notice = $this->user->noticeInbox(0, $limit);
|
||||
@ -90,7 +91,6 @@ class AllrssAction extends Rss10Action
|
||||
$notice = $this->user->noticesWithFriends(0, $limit);
|
||||
}
|
||||
|
||||
$user = $this->user;
|
||||
$notice = $user->noticesWithFriends(0, $limit);
|
||||
$notices = array();
|
||||
|
||||
|
@ -104,30 +104,21 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
||||
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$avatar = $this->group->homepage_logo;
|
||||
$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);
|
||||
// We'll pull common formatting out of this for other formats
|
||||
$atom = new AtomGroupNoticeFeed($this->group);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$atom->title,
|
||||
$this->group->homeUrl(),
|
||||
$subtitle,
|
||||
$atom->subtitle,
|
||||
null,
|
||||
$logo
|
||||
$atom->logo
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
@ -136,38 +127,22 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
||||
|
||||
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->setActivitySubject($this->group->asActivitySubject());
|
||||
|
||||
$atom->addLink($this->group->homeUrl());
|
||||
|
||||
$id = $this->arg('id');
|
||||
$aargs = array('format' => 'atom');
|
||||
if (!empty($id)) {
|
||||
$aargs['id'] = $id;
|
||||
}
|
||||
$self = $this->getSelfUri('ApiTimelineGroup', $aargs);
|
||||
|
||||
$atom->setId($this->getSelfUri('ApiTimelineGroup', $aargs));
|
||||
|
||||
$atom->addLink(
|
||||
$this->getSelfUri('ApiTimelineGroup', $aargs),
|
||||
array('rel' => 'self', 'type' => 'application/atom+xml')
|
||||
);
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
//$this->raw($atom->getString());
|
||||
print $atom->getString(); // temp hack until PuSH feeds are redone cleanly
|
||||
$this->raw($atom->getString());
|
||||
|
||||
} catch (Atom10FeedException $e) {
|
||||
$this->serverError(
|
||||
|
@ -112,19 +112,17 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
function showTimeline()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("%s timeline"), $this->user->nickname);
|
||||
// We'll use the shared params from the Atom stub
|
||||
// for other feed types.
|
||||
$atom = new AtomUserNoticeFeed($this->user);
|
||||
$title = $atom->title;
|
||||
$link = common_local_url(
|
||||
'showstream',
|
||||
array('nickname' => $this->user->nickname)
|
||||
);
|
||||
$subtitle = sprintf(
|
||||
_('Updates from %1$s on %2$s!'),
|
||||
$this->user->nickname, $sitename
|
||||
);
|
||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
$subtitle = $atom->subtitle;
|
||||
$logo = $atom->logo;
|
||||
|
||||
// FriendFeed's SUP protocol
|
||||
// Also added RSS and Atom feeds
|
||||
@ -146,47 +144,18 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
|
||||
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');
|
||||
$aargs = array('format' => 'atom');
|
||||
if (!empty($id)) {
|
||||
$aargs['id'] = $id;
|
||||
}
|
||||
|
||||
$atom->setId($this->getSelfUri('ApiTimelineUser', $aargs));
|
||||
|
||||
$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'
|
||||
)
|
||||
);
|
||||
$self = $this->getSelfUri('ApiTimelineUser', $aargs);
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
#$this->raw($atom->getString());
|
||||
print $atom->getString(); // temporary for output buffering
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
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,7 +99,7 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
|
||||
|
||||
$application = $profile->getApplications($offset, $limit);
|
||||
|
||||
$cnt == 0;
|
||||
$cnt = 0;
|
||||
|
||||
if (!empty($application)) {
|
||||
$al = new ApplicationList($application, $user, $this, true);
|
||||
@ -112,7 +112,7 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > APPS_PER_PAGE,
|
||||
$this->page, 'connectionssettings',
|
||||
array('nickname' => $this->user->nickname));
|
||||
array('nickname' => $user->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
|
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);
|
||||
}
|
||||
}
|
@ -301,19 +301,20 @@ class ShowgroupAction extends GroupDesignAction
|
||||
$this->element('h2', null, _('Group actions'));
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', 'entity_subscribe');
|
||||
$cur = common_current_user();
|
||||
if ($cur) {
|
||||
if ($cur->isMember($this->group)) {
|
||||
$lf = new LeaveForm($this, $this->group);
|
||||
$lf->show();
|
||||
} else if (!Group_block::isBlocked($this->group, $cur->getProfile())) {
|
||||
$jf = new JoinForm($this, $this->group);
|
||||
$jf->show();
|
||||
if (Event::handle('StartGroupSubscribe', array($this, $this->group))) {
|
||||
$cur = common_current_user();
|
||||
if ($cur) {
|
||||
if ($cur->isMember($this->group)) {
|
||||
$lf = new LeaveForm($this, $this->group);
|
||||
$lf->show();
|
||||
} else if (!Group_block::isBlocked($this->group, $cur->getProfile())) {
|
||||
$jf = new JoinForm($this, $this->group);
|
||||
$jf->show();
|
||||
}
|
||||
}
|
||||
Event::handle('EndGroupSubscribe', array($this, $this->group));
|
||||
}
|
||||
|
||||
$this->elementEnd('li');
|
||||
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
|
||||
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()
|
||||
{
|
||||
static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl',
|
||||
'email', 'timezone', 'language',
|
||||
'site', 'textlimit', 'dupelimit'),
|
||||
'snapshot' => array('run', 'reporturl', 'frequency'));
|
||||
static $settings = array(
|
||||
'site' => array('name', 'broughtby', 'broughtbyurl',
|
||||
'email', 'timezone', 'language',
|
||||
'site', 'textlimit', 'dupelimit'),
|
||||
);
|
||||
|
||||
$values = array();
|
||||
|
||||
@ -158,25 +159,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
$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
|
||||
|
||||
if (!Validate::number($values['site']['textlimit'], array('min' => 140))) {
|
||||
@ -277,40 +259,14 @@ class SiteAdminPanelForm extends AdminForm
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->dropdown('language', _('Language'),
|
||||
get_nice_language_list(), _('Default site language'),
|
||||
$this->out->dropdown('language', _('Default language'),
|
||||
get_nice_language_list(), _('Site language when autodetection from browser settings is not available'),
|
||||
false, $this->value('language'));
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$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->element('legend', null, _('Limits'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
201
actions/sitenoticeadminpanel.php
Normal file
201
actions/sitenoticeadminpanel.php
Normal file
@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Site notice 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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
||||
|
||||
/**
|
||||
* Update the site-wide notice text
|
||||
*
|
||||
* @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 SitenoticeadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Site Notice');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using this form.
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Edit site-wide message');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the site notice admin panel form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showForm()
|
||||
{
|
||||
$form = new SiteNoticeAdminPanelForm($this);
|
||||
$form->show();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings from the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
$siteNotice = $this->trimmed('site-notice');
|
||||
|
||||
// assert(all values are valid);
|
||||
// This throws an exception on validation errors
|
||||
|
||||
$this->validate(&$siteNotice);
|
||||
|
||||
$config = new Config();
|
||||
|
||||
$result = Config::save('site', 'notice', $siteNotice);
|
||||
|
||||
if (!result) {
|
||||
$this->ServerError(_("Unable to save site notice."));
|
||||
}
|
||||
}
|
||||
|
||||
function validate(&$siteNotice)
|
||||
{
|
||||
// Validate notice text
|
||||
|
||||
if (mb_strlen($siteNotice) > 255) {
|
||||
$this->clientError(
|
||||
_('Max length for the site-wide notice is 255 chars')
|
||||
);
|
||||
}
|
||||
|
||||
// scrub HTML input
|
||||
|
||||
$config = array(
|
||||
'safe' => 1,
|
||||
'deny_attribute' => 'id,style,on*'
|
||||
);
|
||||
|
||||
$siteNotice = htmLawed($siteNotice, $config);
|
||||
}
|
||||
}
|
||||
|
||||
class SiteNoticeAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_site_notice_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('sitenoticeadminpanel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->textarea(
|
||||
'site-notice',
|
||||
_('Site notice text'),
|
||||
common_config('site', 'notice'),
|
||||
_('Site-wide notice text (255 chars max; HTML okay)')
|
||||
);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit(
|
||||
'submit',
|
||||
_('Save'),
|
||||
'submit',
|
||||
null,
|
||||
_('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')
|
||||
);
|
||||
}
|
||||
}
|
@ -143,9 +143,12 @@ class SubscribersListItem extends SubscriptionListItem
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
$this->showSubscribeButton();
|
||||
// Relevant code!
|
||||
$this->showBlockForm();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showSubscribeButton();
|
||||
// Relevant code!
|
||||
$this->showBlockForm();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
|
@ -130,22 +130,26 @@ class UsergroupsAction extends OwnerDesignAction
|
||||
_('Search for more groups'));
|
||||
$this->elementEnd('p');
|
||||
|
||||
$offset = ($this->page-1) * GROUPS_PER_PAGE;
|
||||
$limit = GROUPS_PER_PAGE + 1;
|
||||
if (Event::handle('StartShowUserGroupsContent', array($this))) {
|
||||
$offset = ($this->page-1) * GROUPS_PER_PAGE;
|
||||
$limit = GROUPS_PER_PAGE + 1;
|
||||
|
||||
$groups = $this->user->getGroups($offset, $limit);
|
||||
$groups = $this->user->getGroups($offset, $limit);
|
||||
|
||||
if ($groups) {
|
||||
$gl = new GroupList($groups, $this->user, $this);
|
||||
$cnt = $gl->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
if ($groups) {
|
||||
$gl = new GroupList($groups, $this->user, $this);
|
||||
$cnt = $gl->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
||||
$this->page, 'usergroups',
|
||||
array('nickname' => $this->user->nickname));
|
||||
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
||||
$this->page, 'usergroups',
|
||||
array('nickname' => $this->user->nickname));
|
||||
|
||||
Event::handle('EndShowUserGroupsContent', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
|
@ -290,5 +290,12 @@ class File extends Memcached_DataObject
|
||||
}
|
||||
return $enclosure;
|
||||
}
|
||||
|
||||
// quick back-compat hack, since there's still code using this
|
||||
function isEnclosure()
|
||||
{
|
||||
$enclosure = $this->getEnclosure();
|
||||
return !empty($enclosure);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +211,8 @@ class Notice extends Memcached_DataObject
|
||||
* extracting ! tags from content
|
||||
* array 'tags' list of hashtag strings to save with the notice
|
||||
* in place of extracting # tags from content
|
||||
* array 'urls' list of attached/referred URLs to save with the
|
||||
* notice in place of extracting links from content
|
||||
* @fixme tag override
|
||||
*
|
||||
* @return Notice
|
||||
@ -380,8 +382,11 @@ class Notice extends Memcached_DataObject
|
||||
$notice->saveTags();
|
||||
}
|
||||
|
||||
// @fixme pass in data for URLs too?
|
||||
$notice->saveUrls();
|
||||
if (isset($urls)) {
|
||||
$notice->saveKnownUrls($urls);
|
||||
} else {
|
||||
$notice->saveUrls();
|
||||
}
|
||||
|
||||
// Prepare inbox delivery, may be queued to background.
|
||||
$notice->distribute();
|
||||
@ -427,6 +432,25 @@ class Notice extends Memcached_DataObject
|
||||
common_replace_urls_callback($this->content, array($this, 'saveUrl'), $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the given URLs as related links/attachments to the db
|
||||
*
|
||||
* follow redirects and save all available file information
|
||||
* (mimetype, date, size, oembed, etc.)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function saveKnownUrls($urls)
|
||||
{
|
||||
// @fixme validation?
|
||||
foreach ($urls as $url) {
|
||||
File::processNew($url, $this->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private callback
|
||||
*/
|
||||
function saveUrl($data) {
|
||||
list($url, $notice_id) = $data;
|
||||
File::processNew($url, $notice_id);
|
||||
@ -853,7 +877,7 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
foreach (array_unique($match[1]) as $nickname) {
|
||||
/* XXX: remote groups. */
|
||||
$group = User_group::getForNickname($nickname);
|
||||
$group = User_group::getForNickname($nickname, $profile);
|
||||
|
||||
if (empty($group)) {
|
||||
continue;
|
||||
@ -1082,7 +1106,7 @@ class Notice extends Memcached_DataObject
|
||||
return $groups;
|
||||
}
|
||||
|
||||
function asAtomEntry($namespace=false, $source=false)
|
||||
function asAtomEntry($namespace=false, $source=false, $author=true)
|
||||
{
|
||||
$profile = $this->getProfile();
|
||||
|
||||
@ -1127,8 +1151,10 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
$xs->element('title', null, $this->content);
|
||||
|
||||
$xs->raw($profile->asAtomAuthor());
|
||||
$xs->raw($profile->asActivityActor());
|
||||
if ($author) {
|
||||
$xs->raw($profile->asAtomAuthor());
|
||||
$xs->raw($profile->asActivityActor());
|
||||
}
|
||||
|
||||
$xs->element('link', array('rel' => 'alternate',
|
||||
'type' => 'text/html',
|
||||
|
@ -282,6 +282,32 @@ class Profile extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
function getGroups($offset=0, $limit=null)
|
||||
{
|
||||
$qry =
|
||||
'SELECT user_group.* ' .
|
||||
'FROM user_group JOIN group_member '.
|
||||
'ON user_group.id = group_member.group_id ' .
|
||||
'WHERE group_member.profile_id = %d ' .
|
||||
'ORDER BY group_member.created DESC ';
|
||||
|
||||
if ($offset>0 && !is_null($limit)) {
|
||||
if ($offset) {
|
||||
if (common_config('db','type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groups = new User_group();
|
||||
|
||||
$cnt = $groups->query(sprintf($qry, $this->id));
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
function avatarUrl($size=AVATAR_PROFILE_SIZE)
|
||||
{
|
||||
$avatar = $this->getAvatar($size);
|
||||
@ -717,6 +743,10 @@ class Profile extends Memcached_DataObject
|
||||
case Right::CONFIGURESITE:
|
||||
$result = $this->hasRole(Profile_role::ADMINISTRATOR);
|
||||
break;
|
||||
case Right::GRANTROLE:
|
||||
case Right::REVOKEROLE:
|
||||
$result = $this->hasRole(Profile_role::OWNER);
|
||||
break;
|
||||
case Right::NEWNOTICE:
|
||||
case Right::NEWMESSAGE:
|
||||
case Right::SUBSCRIBE:
|
||||
|
@ -53,4 +53,21 @@ class Profile_role extends Memcached_DataObject
|
||||
const ADMINISTRATOR = 'administrator';
|
||||
const SANDBOXED = 'sandboxed';
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -613,28 +613,8 @@ class User extends Memcached_DataObject
|
||||
|
||||
function getGroups($offset=0, $limit=null)
|
||||
{
|
||||
$qry =
|
||||
'SELECT user_group.* ' .
|
||||
'FROM user_group JOIN group_member '.
|
||||
'ON user_group.id = group_member.group_id ' .
|
||||
'WHERE group_member.profile_id = %d ' .
|
||||
'ORDER BY group_member.created DESC ';
|
||||
|
||||
if ($offset>0 && !is_null($limit)) {
|
||||
if ($offset) {
|
||||
if (common_config('db','type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$groups = new User_group();
|
||||
|
||||
$cnt = $groups->query(sprintf($qry, $this->id));
|
||||
|
||||
return $groups;
|
||||
$profile = $this->getProfile();
|
||||
return $profile->getGroups($offset, $limit);
|
||||
}
|
||||
|
||||
function getSubscriptions($offset=0, $limit=null)
|
||||
|
@ -279,12 +279,26 @@ class User_group extends Memcached_DataObject
|
||||
return true;
|
||||
}
|
||||
|
||||
static function getForNickname($nickname)
|
||||
static function getForNickname($nickname, $profile=null)
|
||||
{
|
||||
$nickname = common_canonical_nickname($nickname);
|
||||
$group = User_group::staticGet('nickname', $nickname);
|
||||
|
||||
// Are there any matching remote groups this profile's in?
|
||||
if ($profile) {
|
||||
$group = $profile->getGroups();
|
||||
while ($group->fetch()) {
|
||||
if ($group->nickname == $nickname) {
|
||||
// @fixme is this the best way?
|
||||
return clone($group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not, check local groups.
|
||||
|
||||
$group = Local_group::staticGet('nickname', $nickname);
|
||||
if (!empty($group)) {
|
||||
return $group;
|
||||
return User_group::staticGet('id', $group->group_id);
|
||||
}
|
||||
$alias = Group_alias::staticGet('alias', $nickname);
|
||||
if (!empty($alias)) {
|
||||
@ -441,6 +455,11 @@ class User_group extends Memcached_DataObject
|
||||
$group = new User_group();
|
||||
|
||||
$group->query('BEGIN');
|
||||
|
||||
if (empty($uri)) {
|
||||
// fill in later...
|
||||
$uri = null;
|
||||
}
|
||||
|
||||
$group->nickname = $nickname;
|
||||
$group->fullname = $fullname;
|
||||
|
@ -200,7 +200,7 @@ function checkMirror($action_obj, $args)
|
||||
|
||||
function isLoginAction($action)
|
||||
{
|
||||
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds');
|
||||
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds', 'otp');
|
||||
|
||||
$login = null;
|
||||
|
||||
|
86
install.php
86
install.php
@ -31,6 +31,7 @@
|
||||
* @author Robin Millette <millette@controlyourself.ca>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @author Tom Adams <tom@holizz.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
||||
* @version 0.9.x
|
||||
* @link http://status.net
|
||||
@ -490,15 +491,25 @@ function showForm()
|
||||
<p class="form_guide">Database name</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="username">Username</label>
|
||||
<label for="username">DB username</label>
|
||||
<input type="text" id="username" name="username" />
|
||||
<p class="form_guide">Database username</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="password">Password</label>
|
||||
<label for="password">DB password</label>
|
||||
<input type="password" id="password" name="password" />
|
||||
<p class="form_guide">Database password (optional)</p>
|
||||
</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>
|
||||
<input type="submit" name="submit" class="submit" value="Submit" />
|
||||
</fieldset>
|
||||
@ -521,6 +532,10 @@ function handlePost()
|
||||
$password = $_POST['password'];
|
||||
$sitename = $_POST['sitename'];
|
||||
$fancy = !empty($_POST['fancy']);
|
||||
|
||||
$adminNick = $_POST['admin_nickname'];
|
||||
$adminPass = $_POST['admin_password'];
|
||||
|
||||
$server = $_SERVER['HTTP_HOST'];
|
||||
$path = substr(dirname($_SERVER['PHP_SELF']), 1);
|
||||
|
||||
@ -552,6 +567,16 @@ STR;
|
||||
$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) {
|
||||
showForm();
|
||||
return;
|
||||
@ -574,13 +599,29 @@ STR;
|
||||
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
|
||||
*/
|
||||
$link = "http://".$server.'/'.$path;
|
||||
|
||||
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)
|
||||
@ -756,6 +797,33 @@ function runDbScript($filename, $conn, $type = 'mysqli')
|
||||
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 "?>"; ?>
|
||||
<!DOCTYPE html
|
||||
@ -765,10 +833,10 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
<head>
|
||||
<title>Install StatusNet</title>
|
||||
<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"/>
|
||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
|
||||
<!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
|
||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
|
||||
<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" /><![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" /><![endif]-->
|
||||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/install.js"></script>
|
||||
</head>
|
||||
@ -784,8 +852,10 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
</div>
|
||||
<div id="core">
|
||||
<div id="content">
|
||||
<h1>Install StatusNet</h1>
|
||||
<div id="content_inner">
|
||||
<h1>Install StatusNet</h1>
|
||||
<?php main(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
13
js/util.js
13
js/util.js
@ -53,7 +53,7 @@ var SN = { // StatusNet
|
||||
NoticeLocationNs: 'notice_data-location_ns',
|
||||
NoticeGeoName: 'notice_data-geo_name',
|
||||
NoticeDataGeo: 'notice_data-geo',
|
||||
NoticeDataGeoCookie: 'notice_data-geo_cookie',
|
||||
NoticeDataGeoCookie: 'NoticeDataGeo',
|
||||
NoticeDataGeoSelected: 'notice_data-geo_selected',
|
||||
StatusNetInstance:'StatusNetInstance'
|
||||
}
|
||||
@ -423,8 +423,11 @@ var SN = { // StatusNet
|
||||
};
|
||||
|
||||
notice.find('a.attachment').click(function() {
|
||||
$().jOverlay({url: $('address .url')[0].href+'attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
|
||||
return false;
|
||||
var attachId = ($(this).attr('id').substring('attachment'.length + 1));
|
||||
if (attachId) {
|
||||
$().jOverlay({url: $('address .url')[0].href+'attachment/' + attachId + '/ajax'});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if ($('#shownotice').length == 0) {
|
||||
@ -494,7 +497,7 @@ var SN = { // StatusNet
|
||||
$('#'+SN.C.S.NoticeLocationId).val('');
|
||||
$('#'+SN.C.S.NoticeDataGeo).attr('checked', false);
|
||||
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, 'disabled', { path: '/', expires: SN.U.GetFullYear(2029, 0, 1) });
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, 'disabled', { path: '/' });
|
||||
}
|
||||
|
||||
function getJSONgeocodeURL(geocodeURL, data) {
|
||||
@ -537,7 +540,7 @@ var SN = { // StatusNet
|
||||
NDG: true
|
||||
};
|
||||
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, JSON.stringify(cookieValue), { path: '/', expires: SN.U.GetFullYear(2029, 0, 1) });
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, JSON.stringify(cookieValue), { path: '/' });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -420,13 +420,6 @@ class Action extends HTMLOutputter // lawsuit
|
||||
function showPrimaryNav()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$connect = '';
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$connect = 'imsettings';
|
||||
} else if (common_config('sms', 'enabled')) {
|
||||
$connect = 'smssettings';
|
||||
}
|
||||
|
||||
$this->elementStart('dl', array('id' => 'site_nav_global_primary'));
|
||||
$this->element('dt', null, _('Primary site navigation'));
|
||||
$this->elementStart('dd');
|
||||
@ -442,14 +435,12 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$tooltip = _m('TOOLTIP', 'Change your email, avatar, password, profile');
|
||||
// TRANS: Main menu option when logged in for access to user settings
|
||||
$this->menuItem(common_local_url('profilesettings'),
|
||||
_m('MENU', 'Account'), $tooltip, false, 'nav_account');
|
||||
if ($connect) {
|
||||
// TRANS: Tooltip for main menu option "Services"
|
||||
$tooltip = _m('TOOLTIP', 'Connect to services');
|
||||
// TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
|
||||
$this->menuItem(common_local_url($connect),
|
||||
_m('MENU', 'Connect'), $tooltip, false, 'nav_connect');
|
||||
}
|
||||
_('Account'), $tooltip, false, 'nav_account');
|
||||
// TRANS: Tooltip for main menu option "Services"
|
||||
$tooltip = _m('TOOLTIP', 'Connect to services');
|
||||
// TRANS: Main menu option when logged in and connection are possible for access to options to connect to other services
|
||||
$this->menuItem(common_local_url('oauthconnectionssettings'),
|
||||
_('Connect'), $tooltip, false, 'nav_connect');
|
||||
if ($user->hasRight(Right::CONFIGURESITE)) {
|
||||
// TRANS: Tooltip for menu option "Admin"
|
||||
$tooltip = _m('TOOLTIP', 'Change site configuration');
|
||||
|
@ -1044,6 +1044,7 @@ class Activity
|
||||
public $id; // ID of the activity
|
||||
public $title; // title of the activity
|
||||
public $categories = array(); // list of AtomCategory objects
|
||||
public $enclosures = array(); // list of enclosure URL references
|
||||
|
||||
/**
|
||||
* Turns a regular old Atom <entry> into a magical activity
|
||||
@ -1059,6 +1060,18 @@ class Activity
|
||||
}
|
||||
|
||||
$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;
|
||||
|
||||
$pubEl = $this->_child($entry, self::PUBLISHED, self::ATOM);
|
||||
@ -1140,6 +1153,10 @@ class Activity
|
||||
$this->categories[] = new AtomCategory($catEl);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ActivityUtils::getLinks($entry, 'enclosure') as $link) {
|
||||
$this->enclosures[] = $link->getAttribute('href');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,6 +175,34 @@ class AdminPanelAction extends Action
|
||||
$this->showForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show content block. Overrided just to add a special class
|
||||
* to the content div to allow styling.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showContentBlock()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'content', 'class' => 'admin'));
|
||||
$this->showPageTitle();
|
||||
$this->showPageNoticeBlock();
|
||||
$this->elementStart('div', array('id' => 'content_inner'));
|
||||
// show the actual content (forms, lists, whatever)
|
||||
$this->showContent();
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no data for aside, so, we don't output
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showAside()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* show human-readable instructions for the page, or
|
||||
* a success/failure on save.
|
||||
@ -345,32 +373,48 @@ class AdminPanelNav extends Widget
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('User configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('useradminpanel'), _m('MENU', 'User'),
|
||||
$menu_title, $action_name == 'useradminpanel', 'nav_design_admin_panel');
|
||||
$this->out->menuItem(common_local_url('useradminpanel'), _('User'),
|
||||
$menu_title, $action_name == 'useradminpanel', 'nav_user_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('access')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Access configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('accessadminpanel'), _m('MENU', 'Access'),
|
||||
$menu_title, $action_name == 'accessadminpanel', 'nav_design_admin_panel');
|
||||
$this->out->menuItem(common_local_url('accessadminpanel'), _('Access'),
|
||||
$menu_title, $action_name == 'accessadminpanel', 'nav_access_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('paths')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Paths configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('pathsadminpanel'), _m('MENU', 'Paths'),
|
||||
$menu_title, $action_name == 'pathsadminpanel', 'nav_design_admin_panel');
|
||||
$this->out->menuItem(common_local_url('pathsadminpanel'), _('Paths'),
|
||||
$menu_title, $action_name == 'pathsadminpanel', 'nav_paths_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('sessions')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Sessions configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('sessionsadminpanel'), _m('MENU', 'Sessions'),
|
||||
$menu_title, $action_name == 'sessionsadminpanel', 'nav_design_admin_panel');
|
||||
$this->out->menuItem(common_local_url('sessionsadminpanel'), _('Sessions'),
|
||||
$menu_title, $action_name == 'sessionsadminpanel', 'nav_sessions_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('sitenotice')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Edit site notice');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('sitenoticeadminpanel'), _('Site notice'),
|
||||
$menu_title, $action_name == 'sitenoticeadminpanel', 'nav_sitenotice_admin_panel');
|
||||
}
|
||||
|
||||
if (AdminPanelAction::canAdmin('snapshot')) {
|
||||
// TRANS: Menu item title/tooltip
|
||||
$menu_title = _('Snapshots configuration');
|
||||
// TRANS: Menu item for site administration
|
||||
$this->out->menuItem(common_local_url('snapshotadminpanel'), _('Snapshots'),
|
||||
$menu_title, $action_name == 'snapshotadminpanel', 'nav_snapshot_admin_panel');
|
||||
}
|
||||
|
||||
Event::handle('EndAdminPanelNav', array($this));
|
||||
|
@ -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
|
||||
{
|
||||
public $xw;
|
||||
|
||||
// @fixme most of these should probably be read-only properties
|
||||
private $namespaces;
|
||||
private $authors;
|
||||
private $subject;
|
||||
@ -57,10 +59,12 @@ class Atom10Feed extends XMLStringer
|
||||
private $generator;
|
||||
private $icon;
|
||||
private $links;
|
||||
private $logo;
|
||||
private $selfLink;
|
||||
private $selfLinkType;
|
||||
public $logo;
|
||||
private $rights;
|
||||
private $subtitle;
|
||||
private $title;
|
||||
public $subtitle;
|
||||
public $title;
|
||||
private $published;
|
||||
private $updated;
|
||||
private $entries;
|
||||
@ -172,6 +176,14 @@ class Atom10Feed extends XMLStringer
|
||||
}
|
||||
$this->elementStart('feed', $commonAttrs);
|
||||
|
||||
$this->element(
|
||||
'generator', array(
|
||||
'url' => 'http://status.net',
|
||||
'version' => STATUSNET_VERSION
|
||||
),
|
||||
'StatusNet'
|
||||
);
|
||||
|
||||
$this->element('id', null, $this->id);
|
||||
$this->element('title', null, $this->title);
|
||||
$this->element('subtitle', null, $this->subtitle);
|
||||
@ -184,6 +196,10 @@ class Atom10Feed extends XMLStringer
|
||||
|
||||
$this->renderAuthors();
|
||||
|
||||
if ($this->selfLink) {
|
||||
$this->addLink($this->selfLink, array('rel' => 'self',
|
||||
'type' => $this->selfLinkType));
|
||||
}
|
||||
$this->renderLinks();
|
||||
}
|
||||
|
||||
@ -253,6 +269,12 @@ class Atom10Feed extends XMLStringer
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
function setSelfLink($url, $type='application/atom+xml')
|
||||
{
|
||||
$this->selfLink = $url;
|
||||
$this->selfLinkType = $type;
|
||||
}
|
||||
|
||||
function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
@ -49,14 +49,42 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct($group = null, $indent = true) {
|
||||
function __construct($group, $indent = true) {
|
||||
parent::__construct($indent);
|
||||
$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()
|
||||
|
@ -107,9 +107,19 @@ class AtomNoticeFeed extends Atom10Feed
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function __construct($user = null, $indent = true) {
|
||||
function __construct($user, $indent = true) {
|
||||
parent::__construct($indent);
|
||||
$this->user = $user;
|
||||
if (!empty($user)) {
|
||||
$profile = $user->getProfile();
|
||||
$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()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
function showSource()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function showAuthor()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,8 @@ $default =
|
||||
'logdebug' => false,
|
||||
'fancy' => false,
|
||||
'locale_path' => INSTALLDIR.'/locale',
|
||||
'language' => 'en_US',
|
||||
'language' => 'en',
|
||||
'langdetect' => true,
|
||||
'languages' => get_all_languages(),
|
||||
'email' =>
|
||||
array_key_exists('SERVER_ADMIN', $_SERVER) ? $_SERVER['SERVER_ADMIN'] : null,
|
||||
@ -53,10 +54,11 @@ $default =
|
||||
'ssl' => 'never',
|
||||
'sslserver' => null,
|
||||
'shorturllength' => 30,
|
||||
'dupelimit' => 60, # default for same person saying the same thing
|
||||
'dupelimit' => 60, // default for same person saying the same thing
|
||||
'textlimit' => 140,
|
||||
'indent' => true,
|
||||
'use_x_sendfile' => false
|
||||
'use_x_sendfile' => false,
|
||||
'notice' => null // site wide notice text
|
||||
),
|
||||
'db' =>
|
||||
array('database' => 'YOU HAVE TO SET THIS IN config.php',
|
||||
@ -283,7 +285,7 @@ $default =
|
||||
'OpenID' => null),
|
||||
),
|
||||
'admin' =>
|
||||
array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions')),
|
||||
array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions', 'sitenotice')),
|
||||
'singleuser' =>
|
||||
array('enabled' => false,
|
||||
'nickname' => null),
|
||||
|
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);
|
||||
}
|
||||
}
|
@ -105,28 +105,30 @@ class ProfileAction extends OwnerDesignAction
|
||||
|
||||
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
||||
'class' => 'section'));
|
||||
if (Event::handle('StartShowSubscriptionsMiniList', array($this))) {
|
||||
$this->element('h2', null, _('Subscriptions'));
|
||||
|
||||
$this->element('h2', null, _('Subscriptions'));
|
||||
$cnt = 0;
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
if (!empty($profile)) {
|
||||
$pml = new ProfileMiniList($profile, $this);
|
||||
$cnt = $pml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
if (!empty($profile)) {
|
||||
$pml = new ProfileMiniList($profile, $this);
|
||||
$cnt = $pml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > PROFILES_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('subscriptions',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All subscriptions'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
if ($cnt > PROFILES_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('subscriptions',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All subscriptions'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
Event::handle('EndShowSubscriptionsMiniList', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
@ -226,27 +228,29 @@ class ProfileAction extends OwnerDesignAction
|
||||
|
||||
$this->elementStart('div', array('id' => 'entity_groups',
|
||||
'class' => 'section'));
|
||||
if (Event::handle('StartShowGroupsMiniList', array($this))) {
|
||||
$this->element('h2', null, _('Groups'));
|
||||
|
||||
$this->element('h2', null, _('Groups'));
|
||||
|
||||
if ($groups) {
|
||||
$gml = new GroupMiniList($groups, $this->user, $this);
|
||||
$cnt = $gml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
if ($groups) {
|
||||
$gml = new GroupMiniList($groups, $this->user, $this);
|
||||
$cnt = $gml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > GROUPS_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('usergroups',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All groups'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
if ($cnt > GROUPS_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('usergroups',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All groups'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
$this->elementEnd('div');
|
||||
Event::handle('EndShowGroupsMiniList', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,18 +273,12 @@ class ProfileListItem extends Widget
|
||||
$usf = new UnsubscribeForm($this->out, $this->profile);
|
||||
$usf->show();
|
||||
} else {
|
||||
$other = User::staticGet('id', $this->profile->id);
|
||||
if (!empty($other)) {
|
||||
// We can't initiate sub for a remote OMB profile.
|
||||
$remote = Remote_profile::staticGet('id', $this->profile->id);
|
||||
if (empty($remote)) {
|
||||
$sf = new SubscribeForm($this->out, $this->profile);
|
||||
$sf->show();
|
||||
}
|
||||
else {
|
||||
$url = common_local_url('remotesubscribe',
|
||||
array('nickname' => $this->profile->nickname));
|
||||
$this->out->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
_('Subscribe'));
|
||||
}
|
||||
}
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
|
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 EMAILONFAVE = 'emailonfave';
|
||||
const MAKEGROUPADMIN = 'makegroupadmin';
|
||||
const GRANTROLE = 'grantrole';
|
||||
const REVOKEROLE = 'revokerole';
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,7 @@ class Router
|
||||
'groupblock', 'groupunblock',
|
||||
'sandbox', 'unsandbox',
|
||||
'silence', 'unsilence',
|
||||
'grantrole', 'revokerole',
|
||||
'repeat',
|
||||
'deleteuser',
|
||||
'geocode',
|
||||
@ -649,6 +650,8 @@ class Router
|
||||
$m->connect('admin/access', array('action' => 'accessadminpanel'));
|
||||
$m->connect('admin/paths', array('action' => 'pathsadminpanel'));
|
||||
$m->connect('admin/sessions', array('action' => 'sessionsadminpanel'));
|
||||
$m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel'));
|
||||
$m->connect('admin/snapshot', array('action' => 'snapshotadminpanel'));
|
||||
|
||||
$m->connect('getfile/:filename',
|
||||
array('action' => 'getfile'),
|
||||
|
@ -354,10 +354,10 @@ class StatusNet
|
||||
|
||||
class NoConfigException extends Exception
|
||||
{
|
||||
public $config_files;
|
||||
public $configFiles;
|
||||
|
||||
function __construct($msg, $config_files) {
|
||||
function __construct($msg, $configFiles) {
|
||||
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('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()
|
||||
{
|
||||
$url = common_local_url('remotesubscribe',
|
||||
|
14
lib/util.php
14
lib/util.php
@ -105,11 +105,13 @@ function common_language()
|
||||
|
||||
// Otherwise, find the best match for the languages requested by the
|
||||
// user's browser...
|
||||
$httplang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : null;
|
||||
if (!empty($httplang)) {
|
||||
$language = client_prefered_language($httplang);
|
||||
if ($language)
|
||||
return $language;
|
||||
if (common_config('site', 'langdetect')) {
|
||||
$httplang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : null;
|
||||
if (!empty($httplang)) {
|
||||
$language = client_prefered_language($httplang);
|
||||
if ($language)
|
||||
return $language;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, if none of the above worked, use the site's default...
|
||||
@ -853,7 +855,7 @@ function common_valid_profile_tag($str)
|
||||
function common_group_link($sender_id, $nickname)
|
||||
{
|
||||
$sender = Profile::staticGet($sender_id);
|
||||
$group = User_group::getForNickname($nickname);
|
||||
$group = User_group::getForNickname($nickname, $sender);
|
||||
if ($sender && $group && $sender->isMember($group)) {
|
||||
$attrs = array('href' => $group->permalink(),
|
||||
'class' => 'url');
|
||||
|
@ -79,6 +79,25 @@ class FacebookPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there is an API key and secret defined
|
||||
* for Facebook integration.
|
||||
*
|
||||
* @return boolean result
|
||||
*/
|
||||
|
||||
static function hasKeys()
|
||||
{
|
||||
$apiKey = common_config('facebook', 'apikey');
|
||||
$apiSecret = common_config('facebook', 'secret');
|
||||
|
||||
if (!empty($apiKey) && !empty($apiSecret)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Facebook app actions to the router table
|
||||
*
|
||||
@ -91,23 +110,26 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function onStartInitializeRouter($m)
|
||||
{
|
||||
|
||||
// Facebook App stuff
|
||||
|
||||
$m->connect('facebook/app', array('action' => 'facebookhome'));
|
||||
$m->connect('facebook/app/index.php', array('action' => 'facebookhome'));
|
||||
$m->connect('facebook/app/settings.php',
|
||||
array('action' => 'facebooksettings'));
|
||||
$m->connect('facebook/app/invite.php', array('action' => 'facebookinvite'));
|
||||
$m->connect('facebook/app/remove', array('action' => 'facebookremove'));
|
||||
$m->connect('admin/facebook', array('action' => 'facebookadminpanel'));
|
||||
|
||||
// Facebook Connect stuff
|
||||
if (self::hasKeys()) {
|
||||
|
||||
$m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
|
||||
$m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
|
||||
$m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
|
||||
$m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver'));
|
||||
// Facebook App stuff
|
||||
|
||||
$m->connect('facebook/app', array('action' => 'facebookhome'));
|
||||
$m->connect('facebook/app/index.php', array('action' => 'facebookhome'));
|
||||
$m->connect('facebook/app/settings.php',
|
||||
array('action' => 'facebooksettings'));
|
||||
$m->connect('facebook/app/invite.php', array('action' => 'facebookinvite'));
|
||||
$m->connect('facebook/app/remove', array('action' => 'facebookremove'));
|
||||
|
||||
// Facebook Connect stuff
|
||||
|
||||
$m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
|
||||
$m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
|
||||
$m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
|
||||
$m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -338,6 +360,9 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function reqFbScripts($action)
|
||||
{
|
||||
if (!self::hasKeys()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If you're logged in w/FB Connect, you always need the FB stuff
|
||||
|
||||
@ -410,42 +435,35 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function onStartPrimaryNav($action)
|
||||
{
|
||||
$user = common_current_user();
|
||||
if (self::hasKeys()) {
|
||||
$user = common_current_user();
|
||||
if (!empty($user)) {
|
||||
|
||||
$connect = 'FBConnectSettings';
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$connect = 'imsettings';
|
||||
} else if (common_config('sms', 'enabled')) {
|
||||
$connect = 'smssettings';
|
||||
}
|
||||
$fbuid = $this->loggedIn();
|
||||
|
||||
if (!empty($user)) {
|
||||
if (!empty($fbuid)) {
|
||||
|
||||
$fbuid = $this->loggedIn();
|
||||
/* Default FB silhouette pic for FB users who haven't
|
||||
uploaded a profile pic yet. */
|
||||
|
||||
if (!empty($fbuid)) {
|
||||
$silhouetteUrl =
|
||||
'http://static.ak.fbcdn.net/pics/q_silhouette.gif';
|
||||
|
||||
/* Default FB silhouette pic for FB users who haven't
|
||||
uploaded a profile pic yet. */
|
||||
$url = $this->getProfilePicURL($fbuid);
|
||||
|
||||
$silhouetteUrl =
|
||||
'http://static.ak.fbcdn.net/pics/q_silhouette.gif';
|
||||
$action->elementStart('li', array('id' => 'nav_fb'));
|
||||
|
||||
$url = $this->getProfilePicURL($fbuid);
|
||||
$action->element('img', array('id' => 'fbc_profile-pic',
|
||||
'src' => (!empty($url)) ? $url : $silhouetteUrl,
|
||||
'alt' => 'Facebook Connect User',
|
||||
'width' => '16'), '');
|
||||
|
||||
$action->elementStart('li', array('id' => 'nav_fb'));
|
||||
|
||||
$action->element('img', array('id' => 'fbc_profile-pic',
|
||||
'src' => (!empty($url)) ? $url : $silhouetteUrl,
|
||||
'alt' => 'Facebook Connect User',
|
||||
'width' => '16'), '');
|
||||
|
||||
$iconurl = common_path('plugins/Facebook/fbfavicon.ico');
|
||||
$action->element('img', array('id' => 'fb_favicon',
|
||||
'src' => $iconurl));
|
||||
|
||||
$action->elementEnd('li');
|
||||
$iconurl = common_path('plugins/Facebook/fbfavicon.ico');
|
||||
$action->element('img', array('id' => 'fb_favicon',
|
||||
'src' => $iconurl));
|
||||
|
||||
$action->elementEnd('li');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,14 +480,15 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function onEndLoginGroupNav(&$action)
|
||||
{
|
||||
if (self::hasKeys()) {
|
||||
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(common_local_url('FBConnectLogin'),
|
||||
_m('Facebook'),
|
||||
_m('Login or register using Facebook'),
|
||||
'FBConnectLogin' === $action_name);
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(common_local_url('FBConnectLogin'),
|
||||
_m('Facebook'),
|
||||
_m('Login or register using Facebook'),
|
||||
'FBConnectLogin' === $action_name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -483,13 +502,15 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function onEndConnectSettingsNav(&$action)
|
||||
{
|
||||
$action_name = $action->trimmed('action');
|
||||
if (self::hasKeys()) {
|
||||
|
||||
$action->menuItem(common_local_url('FBConnectSettings'),
|
||||
_m('Facebook'),
|
||||
_m('Facebook Connect Settings'),
|
||||
$action_name === 'FBConnectSettings');
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(common_local_url('FBConnectSettings'),
|
||||
_m('Facebook'),
|
||||
_m('Facebook Connect Settings'),
|
||||
$action_name === 'FBConnectSettings');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -503,20 +524,22 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function onStartLogout($action)
|
||||
{
|
||||
$action->logout();
|
||||
$fbuid = $this->loggedIn();
|
||||
if (self::hasKeys()) {
|
||||
|
||||
if (!empty($fbuid)) {
|
||||
try {
|
||||
$facebook = getFacebook();
|
||||
$facebook->expire_session();
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
|
||||
'Could\'t logout of Facebook: ' .
|
||||
$e->getMessage());
|
||||
$action->logout();
|
||||
$fbuid = $this->loggedIn();
|
||||
|
||||
if (!empty($fbuid)) {
|
||||
try {
|
||||
$facebook = getFacebook();
|
||||
$facebook->expire_session();
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
|
||||
'Could\'t logout of Facebook: ' .
|
||||
$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -562,7 +585,9 @@ class FacebookPlugin extends Plugin
|
||||
|
||||
function onStartEnqueueNotice($notice, &$transports)
|
||||
{
|
||||
array_push($transports, 'facebook');
|
||||
if (self::hasKeys()) {
|
||||
array_push($transports, 'facebook');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -575,7 +600,9 @@ class FacebookPlugin extends Plugin
|
||||
*/
|
||||
function onEndInitializeQueueManager($manager)
|
||||
{
|
||||
$manager->connect('facebook', 'FacebookQueueHandler');
|
||||
if (self::hasKeys()) {
|
||||
$manager->connect('facebook', 'FacebookQueueHandler');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -307,23 +307,14 @@ class MobileProfilePlugin extends WAP20Plugin
|
||||
function _showPrimaryNav($action)
|
||||
{
|
||||
$user = common_current_user();
|
||||
$connect = '';
|
||||
if (common_config('xmpp', 'enabled')) {
|
||||
$connect = 'imsettings';
|
||||
} else if (common_config('sms', 'enabled')) {
|
||||
$connect = 'smssettings';
|
||||
}
|
||||
|
||||
$action->elementStart('ul', array('id' => 'site_nav_global_primary'));
|
||||
if ($user) {
|
||||
$action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
||||
_('Home'));
|
||||
$action->menuItem(common_local_url('profilesettings'),
|
||||
_('Account'));
|
||||
if ($connect) {
|
||||
$action->menuItem(common_local_url($connect),
|
||||
$action->menuItem(common_local_url('oauthconnectionssettings'),
|
||||
_('Connect'));
|
||||
}
|
||||
if ($user->hasRight(Right::CONFIGURESITE)) {
|
||||
$action->menuItem(common_local_url('siteadminpanel'),
|
||||
_('Admin'), _('Change site configuration'), false, 'nav_admin');
|
||||
|
@ -44,15 +44,19 @@ class OStatusPlugin extends Plugin
|
||||
$m->connect('.well-known/host-meta',
|
||||
array('action' => 'hostmeta'));
|
||||
$m->connect('main/xrd',
|
||||
array('action' => 'xrd'));
|
||||
array('action' => 'userxrd'));
|
||||
$m->connect('main/ownerxrd',
|
||||
array('action' => 'ownerxrd'));
|
||||
$m->connect('main/ostatus',
|
||||
array('action' => 'ostatusinit'));
|
||||
$m->connect('main/ostatus?nickname=:nickname',
|
||||
array('action' => 'ostatusinit'), array('nickname' => '[A-Za-z0-9_-]+'));
|
||||
$m->connect('main/ostatus?group=:group',
|
||||
array('action' => 'ostatusinit'), array('group' => '[A-Za-z0-9_-]+'));
|
||||
$m->connect('main/ostatussub',
|
||||
array('action' => 'ostatussub'));
|
||||
$m->connect('main/ostatussub',
|
||||
array('action' => 'ostatussub'), array('feed' => '[A-Za-z0-9\.\/\:]+'));
|
||||
$m->connect('main/ostatusgroup',
|
||||
array('action' => 'ostatusgroup'));
|
||||
|
||||
// PuSH actions
|
||||
$m->connect('main/push/hub', array('action' => 'pushhub'));
|
||||
@ -109,13 +113,13 @@ class OStatusPlugin extends Plugin
|
||||
{
|
||||
if ($action instanceof ShowstreamAction) {
|
||||
$acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server');
|
||||
$url = common_local_url('xrd');
|
||||
$url = common_local_url('userxrd');
|
||||
$url.= '?uri='. $acct;
|
||||
|
||||
|
||||
header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="application/xrd+xml"');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up a PuSH hub link to our internal link for canonical timeline
|
||||
* Atom feeds for users and groups.
|
||||
@ -210,6 +214,22 @@ class OStatusPlugin extends Plugin
|
||||
return false;
|
||||
}
|
||||
|
||||
function onStartGroupSubscribe($output, $group)
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($cur)) {
|
||||
// Add an OStatus subscribe
|
||||
$url = common_local_url('ostatusinit',
|
||||
array('group' => $group->nickname));
|
||||
$output->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
_m('Join'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we've got remote replies to send via Salmon.
|
||||
*
|
||||
@ -233,70 +253,70 @@ class OStatusPlugin extends Plugin
|
||||
|
||||
function onEndFindMentions($sender, $text, &$mentions)
|
||||
{
|
||||
preg_match_all('!(?:^|\s+)
|
||||
@( # Webfinger:
|
||||
(?:\w+\.)*\w+ # user
|
||||
@ # @
|
||||
(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+ # domain
|
||||
| # Profile:
|
||||
(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+ # domain
|
||||
(?:/\w+)+ # /path1(/path2...)
|
||||
)!x',
|
||||
$matches = array();
|
||||
|
||||
// Webfinger matches: @user@example.com
|
||||
if (preg_match_all('!(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)!',
|
||||
$text,
|
||||
$wmatches,
|
||||
PREG_OFFSET_CAPTURE);
|
||||
|
||||
foreach ($wmatches[1] as $wmatch) {
|
||||
$target = $wmatch[0];
|
||||
$oprofile = null;
|
||||
|
||||
if (strpos($target, '/') === false) {
|
||||
$this->log(LOG_INFO, "Checking Webfinger for address '$target'");
|
||||
PREG_OFFSET_CAPTURE)) {
|
||||
foreach ($wmatches[1] as $wmatch) {
|
||||
list($target, $pos) = $wmatch;
|
||||
$this->log(LOG_INFO, "Checking webfinger '$target'");
|
||||
try {
|
||||
$oprofile = Ostatus_profile::ensureWebfinger($target);
|
||||
if ($oprofile && !$oprofile->isGroup()) {
|
||||
$profile = $oprofile->localProfile();
|
||||
$matches[$pos] = array('mentioned' => array($profile),
|
||||
'text' => $target,
|
||||
'position' => $pos,
|
||||
'url' => $profile->profileurl);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->log(LOG_ERR, "Webfinger check failed: " . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$schemes = array('https', 'http');
|
||||
}
|
||||
}
|
||||
|
||||
// Profile matches: @example.com/mublog/user
|
||||
if (preg_match_all('!(?:^|\s+)@((?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+(?:/\w+)+)!',
|
||||
$text,
|
||||
$wmatches,
|
||||
PREG_OFFSET_CAPTURE)) {
|
||||
foreach ($wmatches[1] as $wmatch) {
|
||||
list($target, $pos) = $wmatch;
|
||||
$schemes = array('http', 'https');
|
||||
foreach ($schemes as $scheme) {
|
||||
$url = "$scheme://$target";
|
||||
$this->log(LOG_INFO, "Checking profile address '$url'");
|
||||
try {
|
||||
$oprofile = Ostatus_profile::ensureProfile($url);
|
||||
if ($oprofile) {
|
||||
continue;
|
||||
if ($oprofile && !$oprofile->isGroup()) {
|
||||
$profile = $oprofile->localProfile();
|
||||
$matches[$pos] = array('mentioned' => array($profile),
|
||||
'text' => $target,
|
||||
'position' => $pos,
|
||||
'url' => $profile->profileurl);
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->log(LOG_ERR, "Profile check failed: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($oprofile)) {
|
||||
$this->log(LOG_INFO, "No Ostatus_profile found for address '$target'");
|
||||
} else {
|
||||
|
||||
$this->log(LOG_INFO, "Ostatus_profile found for address '$target'");
|
||||
|
||||
if ($oprofile->isGroup()) {
|
||||
continue;
|
||||
}
|
||||
$profile = $oprofile->localProfile();
|
||||
|
||||
$pos = $wmatch[1];
|
||||
foreach ($mentions as $i => $other) {
|
||||
// If we share a common prefix with a local user, override it!
|
||||
if ($other['position'] == $pos) {
|
||||
unset($mentions[$i]);
|
||||
}
|
||||
}
|
||||
$mentions[] = array('mentioned' => array($profile),
|
||||
'text' => $target,
|
||||
'position' => $pos,
|
||||
'url' => $profile->profileurl);
|
||||
foreach ($mentions as $i => $other) {
|
||||
// If we share a common prefix with a local user, override it!
|
||||
$pos = $other['position'];
|
||||
if (isset($matches[$pos])) {
|
||||
$mentions[$i] = $matches[$pos];
|
||||
unset($matches[$pos]);
|
||||
}
|
||||
}
|
||||
foreach ($matches as $mention) {
|
||||
$mentions[] = $mention;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -567,7 +587,6 @@ class OStatusPlugin extends Plugin
|
||||
// Drop the PuSH subscription if there are no other subscribers.
|
||||
$oprofile->garbageCollect();
|
||||
|
||||
|
||||
$member = Profile::staticGet($user->id);
|
||||
|
||||
$act = new Activity();
|
||||
@ -711,23 +730,37 @@ class OStatusPlugin extends Plugin
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartShowAllContent($action)
|
||||
function onStartShowUserGroupsContent($action)
|
||||
{
|
||||
$this->showEntityRemoteSubscribe($action, 'ostatusgroup');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onEndShowSubscriptionsMiniList($action)
|
||||
{
|
||||
$this->showEntityRemoteSubscribe($action);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function showEntityRemoteSubscribe($action)
|
||||
function onEndShowGroupsMiniList($action)
|
||||
{
|
||||
$this->showEntityRemoteSubscribe($action, 'ostatusgroup');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function showEntityRemoteSubscribe($action, $target='ostatussub')
|
||||
{
|
||||
$user = common_current_user();
|
||||
if ($user && ($user->id == $action->profile->id)) {
|
||||
$action->elementStart('div', 'entity_actions');
|
||||
$action->elementStart('p', array('id' => 'entity_remote_subscribe',
|
||||
'class' => 'entity_subscribe'));
|
||||
$action->element('a', array('href' => common_local_url('ostatussub'),
|
||||
$action->element('a', array('href' => common_local_url($target),
|
||||
'class' => 'entity_remote_subscribe')
|
||||
, _m('Subscribe to remote user'));
|
||||
, _m('Remote'));
|
||||
$action->elementEnd('p');
|
||||
$action->elementEnd('div');
|
||||
}
|
||||
@ -779,4 +812,28 @@ class OStatusPlugin extends Plugin
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartProfileListItemActionElements($item)
|
||||
{
|
||||
if (!common_logged_in()) {
|
||||
|
||||
$profileUser = User::staticGet('id', $item->profile->id);
|
||||
|
||||
if (!empty($profileUser)) {
|
||||
|
||||
$output = $item->out;
|
||||
|
||||
// Add an OStatus subscribe
|
||||
$output->elementStart('li', 'entity_subscribe');
|
||||
$url = common_local_url('ostatusinit',
|
||||
array('nickname' => $profileUser->nickname));
|
||||
$output->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
_m('Subscribe'));
|
||||
$output->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class HostMetaAction extends Action
|
||||
parent::handle();
|
||||
|
||||
$domain = common_config('site', 'server');
|
||||
$url = common_local_url('xrd');
|
||||
$url = common_local_url('userxrd');
|
||||
$url.= '?uri={uri}';
|
||||
|
||||
$xrd = new XRD();
|
||||
|
181
plugins/OStatus/actions/ostatusgroup.php
Normal file
181
plugins/OStatus/actions/ostatusgroup.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2009-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 Brion Vibber <brion@status.net>
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Key UI methods:
|
||||
*
|
||||
* showInputForm() - form asking for a remote profile account or URL
|
||||
* We end up back here on errors
|
||||
*
|
||||
* showPreviewForm() - surrounding form for preview-and-confirm
|
||||
* preview() - display profile for a remote group
|
||||
*
|
||||
* success() - redirects to groups page on join
|
||||
*/
|
||||
class OStatusGroupAction extends OStatusSubAction
|
||||
{
|
||||
protected $profile_uri; // provided acct: or URI of remote entity
|
||||
protected $oprofile; // Ostatus_profile of remote entity, if valid
|
||||
|
||||
|
||||
function validateRemoteProfile()
|
||||
{
|
||||
if (!$this->oprofile->isGroup()) {
|
||||
// Send us to the user subscription form for conf
|
||||
$target = common_local_url('ostatussub', array(), array('profile' => $this->profile_uri));
|
||||
common_redirect($target, 303);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the initial form, when we haven't yet been given a valid
|
||||
* remote profile.
|
||||
*/
|
||||
function showInputForm()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_ostatus_sub',
|
||||
'class' => 'form_settings',
|
||||
'action' => $this->selfLink()));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_feeds'));
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('profile',
|
||||
_m('Join group'),
|
||||
$this->profile_uri,
|
||||
_m("OStatus group's address, like http://example.net/group/nickname"));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->submit('validate', _m('Continue'));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a preview for a remote group's profile
|
||||
* @return boolean true if we're ok to try joining
|
||||
*/
|
||||
function preview()
|
||||
{
|
||||
$oprofile = $this->oprofile;
|
||||
$group = $oprofile->localGroup();
|
||||
|
||||
$cur = common_current_user();
|
||||
if ($cur->isMember($group)) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
_m("You are already a member of this group."));
|
||||
$ok = false;
|
||||
} else {
|
||||
$ok = true;
|
||||
}
|
||||
|
||||
$this->showEntity($group,
|
||||
$group->getProfileUrl(),
|
||||
$group->homepage_logo,
|
||||
$group->description);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect on successful remote group join
|
||||
*/
|
||||
function success()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$url = common_local_url('usergroups', array('nickname' => $cur->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to finalize subscription.
|
||||
* validateFeed must have been run first.
|
||||
*
|
||||
* Calls showForm on failure or success on success.
|
||||
*/
|
||||
function saveFeed()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$group = $this->oprofile->localGroup();
|
||||
if ($user->isMember($group)) {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Already a member!'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Event::handle('StartJoinGroup', array($group, $user))) {
|
||||
$ok = Group_member::join($this->oprofile->group_id, $user->id);
|
||||
if ($ok) {
|
||||
Event::handle('EndJoinGroup', array($group, $user));
|
||||
$this->success();
|
||||
} else {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Remote group join failed!'));
|
||||
}
|
||||
} else {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Remote group join aborted!'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title for OStatus remote group join form
|
||||
return _m('Confirm joining remote group');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _m('You can subscribe to groups from other supported sites. Paste the group\'s profile URI below:');
|
||||
}
|
||||
|
||||
function selfLink()
|
||||
{
|
||||
return common_local_url('ostatusgroup');
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ class OStatusInitAction extends Action
|
||||
{
|
||||
|
||||
var $nickname;
|
||||
var $group;
|
||||
var $profile;
|
||||
var $err;
|
||||
|
||||
@ -41,8 +42,9 @@ class OStatusInitAction extends Action
|
||||
return false;
|
||||
}
|
||||
|
||||
// Local user the remote wants to subscribe to
|
||||
// Local user or group the remote wants to subscribe to
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->group = $this->trimmed('group');
|
||||
|
||||
// Webfinger or profile URL of the remote user
|
||||
$this->profile = $this->trimmed('profile');
|
||||
@ -89,25 +91,33 @@ class OStatusInitAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if ($this->group) {
|
||||
$header = sprintf(_m('Join group %s'), $this->group);
|
||||
$submit = _m('Join');
|
||||
} else {
|
||||
$header = sprintf(_m('Subscribe to %s'), $this->nickname);
|
||||
$submit = _m('Subscribe');
|
||||
}
|
||||
$this->elementStart('form', array('id' => 'form_ostatus_connect',
|
||||
'method' => 'post',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('ostatusinit')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, sprintf(_m('Subscribe to %s'), $this->nickname));
|
||||
$this->element('legend', null, $header);
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li', array('id' => 'ostatus_nickname'));
|
||||
$this->input('nickname', _m('User nickname'), $this->nickname,
|
||||
_m('Nickname of the user you want to follow'));
|
||||
$this->hidden('group', $this->group); // pass-through for magic links
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li', array('id' => 'ostatus_profile'));
|
||||
$this->input('profile', _m('Profile Account'), $this->profile,
|
||||
_m('Your account id (i.e. user@identi.ca)'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('submit', _m('Subscribe'));
|
||||
$this->submit('submit', $submit);
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
@ -131,19 +141,17 @@ class OStatusInitAction extends Action
|
||||
|
||||
function connectWebfinger($acct)
|
||||
{
|
||||
$disco = new Discovery;
|
||||
$target_profile = $this->targetProfile();
|
||||
|
||||
$disco = new Discovery;
|
||||
$result = $disco->lookup($acct);
|
||||
if (!$result) {
|
||||
$this->clientError(_m("Couldn't look up OStatus account profile."));
|
||||
}
|
||||
|
||||
foreach ($result->links as $link) {
|
||||
if ($link['rel'] == 'http://ostatus.org/schema/1.0/subscribe') {
|
||||
// We found a URL - let's redirect!
|
||||
|
||||
$user = User::staticGet('nickname', $this->nickname);
|
||||
$target_profile = common_local_url('userbyid', array('id' => $user->id));
|
||||
|
||||
$url = Discovery::applyTemplate($link['template'], $target_profile);
|
||||
common_log(LOG_INFO, "Sending remote subscriber $acct to $url");
|
||||
common_redirect($url, 303);
|
||||
@ -155,8 +163,7 @@ class OStatusInitAction extends Action
|
||||
|
||||
function connectProfile($subscriber_profile)
|
||||
{
|
||||
$user = User::staticGet('nickname', $this->nickname);
|
||||
$target_profile = common_local_url('userbyid', array('id' => $user->id));
|
||||
$target_profile = $this->targetProfile();
|
||||
|
||||
// @fixme hack hack! We should look up the remote sub URL from XRDS
|
||||
$suburl = preg_replace('!^(.*)/(.*?)$!', '$1/main/ostatussub', $subscriber_profile);
|
||||
@ -166,6 +173,30 @@ class OStatusInitAction extends Action
|
||||
common_redirect($suburl, 303);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the canonical profile URI+URL of the requested user or group
|
||||
*/
|
||||
function targetProfile()
|
||||
{
|
||||
if ($this->nickname) {
|
||||
$user = User::staticGet('nickname', $this->nickname);
|
||||
if ($user) {
|
||||
return common_local_url('userbyid', array('id' => $user->id));
|
||||
} else {
|
||||
$this->clientError("No such user.");
|
||||
}
|
||||
} else if ($this->group) {
|
||||
$group = Local_group::staticGet('id', $this->group);
|
||||
if ($group) {
|
||||
return common_local_url('groupbyid', array('id' => $group->group_id));
|
||||
} else {
|
||||
$this->clientError("No such group.");
|
||||
}
|
||||
} else {
|
||||
$this->clientError("No local user or group nickname provided.");
|
||||
}
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _m('OStatus Connect');
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2009, StatusNet, Inc.
|
||||
* Copyright (C) 2009-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
|
||||
@ -31,11 +31,9 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
* We end up back here on errors
|
||||
*
|
||||
* showPreviewForm() - surrounding form for preview-and-confirm
|
||||
* previewUser() - display profile for a remote user
|
||||
* previewGroup() - display profile for a remote group
|
||||
* preview() - display profile for a remote user
|
||||
*
|
||||
* successUser() - redirects to subscriptions page on subscribe
|
||||
* successGroup() - redirects to groups page on join
|
||||
* success() - redirects to subscriptions page on subscribe
|
||||
*/
|
||||
class OStatusSubAction extends Action
|
||||
{
|
||||
@ -55,8 +53,7 @@ class OStatusSubAction extends Action
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_ostatus_sub',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
common_local_url('ostatussub')));
|
||||
'action' => $this->selfLink()));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
@ -65,9 +62,9 @@ class OStatusSubAction extends Action
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('profile',
|
||||
_m('Address or profile URL'),
|
||||
_m('Subscribe to'),
|
||||
$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('ul');
|
||||
|
||||
@ -87,11 +84,7 @@ class OStatusSubAction extends Action
|
||||
*/
|
||||
function showPreviewForm()
|
||||
{
|
||||
if ($this->oprofile->isGroup()) {
|
||||
$ok = $this->previewGroup();
|
||||
} else {
|
||||
$ok = $this->previewUser();
|
||||
}
|
||||
$ok = $this->preview();
|
||||
if (!$ok) {
|
||||
// @fixme maybe provide a cancel button or link back?
|
||||
return;
|
||||
@ -104,7 +97,7 @@ class OStatusSubAction extends Action
|
||||
'id' => 'form_ostatus_sub',
|
||||
'class' => 'form_remote_authorize',
|
||||
'action' =>
|
||||
common_local_url('ostatussub')));
|
||||
$this->selfLink()));
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->hidden('profile', $this->profile_uri);
|
||||
@ -126,7 +119,7 @@ class OStatusSubAction extends Action
|
||||
* Show a preview for a remote user's profile
|
||||
* @return boolean true if we're ok to try subscribing
|
||||
*/
|
||||
function previewUser()
|
||||
function preview()
|
||||
{
|
||||
$oprofile = $this->oprofile;
|
||||
$profile = $oprofile->localProfile();
|
||||
@ -150,32 +143,6 @@ class OStatusSubAction extends Action
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a preview for a remote group's profile
|
||||
* @return boolean true if we're ok to try joining
|
||||
*/
|
||||
function previewGroup()
|
||||
{
|
||||
$oprofile = $this->oprofile;
|
||||
$group = $oprofile->localGroup();
|
||||
|
||||
$cur = common_current_user();
|
||||
if ($cur->isMember($group)) {
|
||||
$this->element('div', array('class' => 'error'),
|
||||
_m("You are already a member of this group."));
|
||||
$ok = false;
|
||||
} else {
|
||||
$ok = true;
|
||||
}
|
||||
|
||||
$this->showEntity($group,
|
||||
$group->getProfileUrl(),
|
||||
$group->homepage_logo,
|
||||
$group->description);
|
||||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
function showEntity($entity, $profile, $avatar, $note)
|
||||
{
|
||||
$nickname = $entity->nickname;
|
||||
@ -254,23 +221,13 @@ class OStatusSubAction extends Action
|
||||
/**
|
||||
* Redirect on successful remote user subscription
|
||||
*/
|
||||
function successUser()
|
||||
function success()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$url = common_local_url('subscriptions', array('nickname' => $cur->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect on successful remote group join
|
||||
*/
|
||||
function successGroup()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$url = common_local_url('usergroups', array('nickname' => $cur->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull data for a remote profile and check if it's valid.
|
||||
* Fills out error UI string in $this->error
|
||||
@ -278,88 +235,75 @@ class OStatusSubAction extends Action
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function validateFeed()
|
||||
function pullRemoteProfile()
|
||||
{
|
||||
$profile_uri = trim($this->arg('profile'));
|
||||
|
||||
if ($profile_uri == '') {
|
||||
$this->showForm(_m('Empty remote profile URL!'));
|
||||
return;
|
||||
}
|
||||
$this->profile_uri = $profile_uri;
|
||||
|
||||
$this->profile_uri = $this->trimmed('profile');
|
||||
try {
|
||||
if (Validate::email($this->profile_uri)) {
|
||||
$this->oprofile = Ostatus_profile::ensureWebfinger($this->profile_uri);
|
||||
} else if (Validate::uri($this->profile_uri)) {
|
||||
$this->oprofile = Ostatus_profile::ensureProfile($this->profile_uri);
|
||||
} 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 true;
|
||||
} 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) {
|
||||
$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) {
|
||||
$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) {
|
||||
$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) {
|
||||
$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) {
|
||||
$this->error = _m('Not a recognized feed type.');
|
||||
} catch (FeedSubException $e) {
|
||||
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||
common_debug('Not a recognized feed type.', __FILE__);
|
||||
} catch (Exception $e) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
function validateRemoteProfile()
|
||||
{
|
||||
if ($this->oprofile->isGroup()) {
|
||||
// Send us to the group subscription form for conf
|
||||
$target = common_local_url('ostatusgroup', array(), array('profile' => $this->profile_uri));
|
||||
common_redirect($target, 303);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to finalize subscription.
|
||||
* validateFeed must have been run first.
|
||||
*
|
||||
* Calls showForm on failure or successUser/successGroup on success.
|
||||
* Calls showForm on failure or success on success.
|
||||
*/
|
||||
function saveFeed()
|
||||
{
|
||||
// And subscribe the current user to the local profile
|
||||
$user = common_current_user();
|
||||
|
||||
if ($this->oprofile->isGroup()) {
|
||||
$group = $this->oprofile->localGroup();
|
||||
if ($user->isMember($group)) {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Already a member!'));
|
||||
return;
|
||||
}
|
||||
if (Event::handle('StartJoinGroup', array($group, $user))) {
|
||||
$ok = Group_member::join($this->oprofile->group_id, $user->id);
|
||||
if ($ok) {
|
||||
Event::handle('EndJoinGroup', array($group, $user));
|
||||
$this->successGroup();
|
||||
} else {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Remote group join failed!'));
|
||||
}
|
||||
} else {
|
||||
// TRANS: OStatus remote group subscription dialog error.
|
||||
$this->showForm(_m('Remote group join aborted!'));
|
||||
}
|
||||
$local = $this->oprofile->localProfile();
|
||||
if ($user->isSubscribed($local)) {
|
||||
// TRANS: OStatus remote subscription dialog error.
|
||||
$this->showForm(_m('Already subscribed!'));
|
||||
} elseif ($this->oprofile->subscribeLocalToRemote($user)) {
|
||||
$this->success();
|
||||
} else {
|
||||
$local = $this->oprofile->localProfile();
|
||||
if ($user->isSubscribed($local)) {
|
||||
// TRANS: OStatus remote subscription dialog error.
|
||||
$this->showForm(_m('Already subscribed!'));
|
||||
} elseif ($this->oprofile->subscribeLocalToRemote($user)) {
|
||||
$this->successUser();
|
||||
} else {
|
||||
// TRANS: OStatus remote subscription dialog error.
|
||||
$this->showForm(_m('Remote subscription failed!'));
|
||||
}
|
||||
// TRANS: OStatus remote subscription dialog error.
|
||||
$this->showForm(_m('Remote subscription failed!'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,8 +320,9 @@ class OStatusSubAction extends Action
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->profile_uri = $this->arg('profile');
|
||||
|
||||
if ($this->pullRemoteProfile()) {
|
||||
$this->validateRemoteProfile();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -390,9 +335,6 @@ class OStatusSubAction extends Action
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->handlePost();
|
||||
} else {
|
||||
if ($this->arg('profile')) {
|
||||
$this->validateFeed();
|
||||
}
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
@ -414,7 +356,7 @@ class OStatusSubAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->validateFeed()) {
|
||||
if ($this->oprofile) {
|
||||
if ($this->arg('submit')) {
|
||||
$this->saveFeed();
|
||||
return;
|
||||
@ -456,7 +398,7 @@ class OStatusSubAction extends Action
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title for OStatus remote subscription form
|
||||
return _m('Authorize subscription');
|
||||
return _m('Confirm');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,4 +442,9 @@ class OStatusSubAction extends Action
|
||||
parent::showScripts();
|
||||
$this->autofocus('feedurl');
|
||||
}
|
||||
|
||||
function selfLink()
|
||||
{
|
||||
return common_local_url('ostatussub');
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
}
|
||||
}
|
@ -550,7 +550,8 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
'rendered' => $rendered,
|
||||
'replies' => array(),
|
||||
'groups' => array(),
|
||||
'tags' => array());
|
||||
'tags' => array(),
|
||||
'urls' => array());
|
||||
|
||||
// Check for optional attributes...
|
||||
|
||||
@ -595,6 +596,12 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
// Atom enclosures -> attachment URLs
|
||||
foreach ($activity->enclosures as $href) {
|
||||
// @fixme save these locally or....?
|
||||
$options['urls'][] = $href;
|
||||
}
|
||||
|
||||
try {
|
||||
$saved = Notice::saveNew($oprofile->profile_id,
|
||||
$content,
|
||||
@ -620,7 +627,8 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
protected function purify($html)
|
||||
{
|
||||
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
||||
$config = array('safe' => 1);
|
||||
$config = array('safe' => 1,
|
||||
'deny_attribute' => 'id,style,on*');
|
||||
return htmLawed($html, $config);
|
||||
}
|
||||
|
||||
@ -1259,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)
|
||||
{
|
||||
// First, try the cache
|
||||
@ -1267,7 +1280,8 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
|
||||
if ($uri !== false) {
|
||||
if (is_null($uri)) {
|
||||
return null;
|
||||
// Negative cache entry
|
||||
throw new Exception('Not a valid webfinger address.');
|
||||
}
|
||||
$oprofile = Ostatus_profile::staticGet('uri', $uri);
|
||||
if (!empty($oprofile)) {
|
||||
@ -1291,20 +1305,24 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
try {
|
||||
$result = $disco->lookup($addr);
|
||||
} 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);
|
||||
return null;
|
||||
throw new Exception('Not a valid webfinger address.');
|
||||
}
|
||||
|
||||
$hints = array('webfinger' => $addr);
|
||||
|
||||
foreach ($result->links as $link) {
|
||||
switch ($link['rel']) {
|
||||
case Discovery::PROFILEPAGE:
|
||||
$profileUrl = $link['href'];
|
||||
$hints['profileurl'] = $profileUrl = $link['href'];
|
||||
break;
|
||||
case Salmon::NS_REPLIES:
|
||||
$salmonEndpoint = $link['href'];
|
||||
$hints['salmon'] = $salmonEndpoint = $link['href'];
|
||||
break;
|
||||
case Discovery::UPDATESFROM:
|
||||
$feedUrl = $link['href'];
|
||||
$hints['feedurl'] = $feedUrl = $link['href'];
|
||||
break;
|
||||
case Discovery::HCARD:
|
||||
$hcardUrl = $link['href'];
|
||||
@ -1315,11 +1333,6 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
$hints = array('webfinger' => $addr,
|
||||
'profileurl' => $profileUrl,
|
||||
'feedurl' => $feedUrl,
|
||||
'salmon' => $salmonEndpoint);
|
||||
|
||||
if (isset($hcardUrl)) {
|
||||
$hcardHints = self::slurpHcard($hcardUrl);
|
||||
// Note: Webfinger > hcard
|
||||
@ -1402,7 +1415,7 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
return $oprofile;
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new Exception("Couldn't find a valid profile for '$addr'");
|
||||
}
|
||||
|
||||
function saveHTMLFile($title, $rendered)
|
||||
@ -1492,7 +1505,7 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
if (array_key_exists('url', $hcard)) {
|
||||
if (is_string($hcard['url'])) {
|
||||
$hints['homepage'] = $hcard['url'];
|
||||
} else if (is_array($hcard['adr'])) {
|
||||
} else if (is_array($hcard['url'])) {
|
||||
// HACK get the last one; that's how our hcards look
|
||||
$hints['homepage'] = $hcard['url'][count($hcard['url'])-1];
|
||||
}
|
||||
|
@ -156,18 +156,32 @@ class MagicEnvelope
|
||||
public function verify($env)
|
||||
{
|
||||
if ($env['alg'] != 'RSA-SHA256') {
|
||||
common_log(LOG_DEBUG, "Salmon error: bad algorithm");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($env['encoding'] != MagicEnvelope::ENCODING) {
|
||||
common_log(LOG_DEBUG, "Salmon error: bad encoding");
|
||||
return false;
|
||||
}
|
||||
|
||||
$text = base64_decode($env['data']);
|
||||
$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']);
|
||||
}
|
||||
|
||||
|
@ -164,46 +164,21 @@ class OStatusQueueHandler extends QueueHandler
|
||||
*/
|
||||
function userFeedForNotice()
|
||||
{
|
||||
// @fixme this feels VERY hacky...
|
||||
// should probably be a cleaner way to do it
|
||||
$atom = new AtomUserNoticeFeed($this->user);
|
||||
$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;
|
||||
}
|
||||
|
||||
function groupFeedForNotice($group_id)
|
||||
{
|
||||
// @fixme this feels VERY hacky...
|
||||
// should probably be a cleaner way to do it
|
||||
$group = User_group::staticGet('id', $group_id);
|
||||
|
||||
ob_start();
|
||||
$api = new ApiTimelineGroupAction();
|
||||
$args = array('id' => $group_id,
|
||||
'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');
|
||||
$atom = new AtomGroupNoticeFeed($group);
|
||||
$atom->addEntryFromNotice($this->notice);
|
||||
$feed = $atom->getString();
|
||||
|
||||
common_log(LOG_DEBUG, $feed);
|
||||
return $feed;
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,9 @@ class XRD
|
||||
throw new Exception("Invalid XML");
|
||||
}
|
||||
$xrd_element = $dom->getElementsByTagName('XRD')->item(0);
|
||||
if (!$xrd_element) {
|
||||
throw new Exception("Invalid XML, missing XRD root");
|
||||
}
|
||||
|
||||
// Check for host-meta host
|
||||
$host = $xrd_element->getElementsByTagName('Host')->item(0);
|
||||
@ -149,9 +152,11 @@ class XRD
|
||||
$link['href'] = $element->getAttribute('href');
|
||||
$link['template'] = $element->getAttribute('template');
|
||||
foreach ($element->childNodes as $node) {
|
||||
switch($node->tagName) {
|
||||
case 'Title':
|
||||
$link['title'][] = $node->nodeValue;
|
||||
if ($node instanceof DOMElement) {
|
||||
switch($node->tagName) {
|
||||
case 'Title':
|
||||
$link['title'][] = $node->nodeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,32 +28,24 @@ class XrdAction extends Action
|
||||
{
|
||||
|
||||
public $uri;
|
||||
|
||||
public $user;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->uri = $this->trimmed('uri');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public $xrd;
|
||||
|
||||
function handle()
|
||||
{
|
||||
$acct = Discovery::normalize($this->uri);
|
||||
$nick = $this->user->nickname;
|
||||
|
||||
$xrd = new XRD();
|
||||
|
||||
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;
|
||||
if (empty($this->xrd)) {
|
||||
$xrd = new XRD();
|
||||
} else {
|
||||
$xrd = $this->xrd;
|
||||
}
|
||||
|
||||
$xrd->subject = $this->uri;
|
||||
if (empty($xrd->subject)) {
|
||||
$xrd->subject = Discovery::normalize($this->uri);
|
||||
}
|
||||
$xrd->alias[] = common_profile_url($nick);
|
||||
$xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
|
||||
'type' => 'text/html',
|
@ -41,8 +41,34 @@ min-width:96px;
|
||||
#entity_remote_subscribe {
|
||||
padding:0;
|
||||
float:right;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
#all #entity_remote_subscribe {
|
||||
margin-top:-52px;
|
||||
.section .entity_actions {
|
||||
margin-bottom:0;
|
||||
}
|
||||
|
||||
#entity_remote_subscribe .dialogbox {
|
||||
width:405px;
|
||||
}
|
||||
|
||||
.aside #entity_subscriptions .more,
|
||||
.aside #entity_groups .more {
|
||||
float:left;
|
||||
}
|
||||
|
||||
.section #entity_remote_subscribe {
|
||||
border:0;
|
||||
}
|
||||
|
||||
.section .entity_remote_subscribe {
|
||||
color:#002FA7;
|
||||
box-shadow:none;
|
||||
-moz-box-shadow:none;
|
||||
-webkit-box-shadow:none;
|
||||
background-color:transparent;
|
||||
background-position:0 -1183px;
|
||||
padding:0 0 0 23px;
|
||||
border:0;
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ on Twitter (http://twitter.com/apps). During the application
|
||||
registration process your application will be assigned a "consumer" key
|
||||
and secret, which the plugin will use to make OAuth requests to Twitter.
|
||||
You can either pass the consumer key and secret in when you enable the
|
||||
plugin, or set it using the Twitter administration panel.
|
||||
plugin, or set it using the Twitter administration panel**.
|
||||
|
||||
When registering your application with Twitter set the type to "Browser"
|
||||
and your Callback URL to:
|
||||
@ -42,11 +42,26 @@ To enable the plugin, add the following to your config.php:
|
||||
)
|
||||
);
|
||||
|
||||
or just:
|
||||
|
||||
addPlugin('TwitterBridge');
|
||||
|
||||
if you want to set the consumer key and secret from the Twitter bridge
|
||||
administration panel. (The Twitter bridge wont work at all
|
||||
unless you configure it with a consumer key and secret.)
|
||||
|
||||
* Note: The plugin will still push notices to Twitter for users who
|
||||
have previously set up the Twitter bridge using their Twitter name and
|
||||
password under an older version of StatusNet, but all new Twitter
|
||||
bridge connections will use OAuth.
|
||||
|
||||
** For multi-site setups you can also set a global consumer key and
|
||||
secret. The Twitter bridge will fall back on the global key pair if
|
||||
it can't find a local pair, e.g.:
|
||||
|
||||
$config['twitter']['global_consumer_key'] = 'YOUR_CONSUMER_KEY'
|
||||
$config['twitter']['global_consumer_secret'] = 'YOUR_CONSUMER_SECRET'
|
||||
|
||||
Administration panel
|
||||
--------------------
|
||||
|
||||
|
@ -79,6 +79,30 @@ class TwitterBridgePlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there is a consumer key and secret defined
|
||||
* for Twitter integration.
|
||||
*
|
||||
* @return boolean result
|
||||
*/
|
||||
|
||||
static function hasKeys()
|
||||
{
|
||||
$ckey = common_config('twitter', 'consumer_key');
|
||||
$csecret = common_config('twitter', 'consumer_secret');
|
||||
|
||||
if (empty($ckey) && empty($csecret)) {
|
||||
$ckey = common_config('twitter', 'global_consumer_key');
|
||||
$csecret = common_config('twitter', 'global_consumer_secret');
|
||||
}
|
||||
|
||||
if (!empty($ckey) && !empty($csecret)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Twitter-related paths to the router table
|
||||
*
|
||||
@ -91,18 +115,26 @@ class TwitterBridgePlugin extends Plugin
|
||||
|
||||
function onRouterInitialized($m)
|
||||
{
|
||||
$m->connect(
|
||||
'twitter/authorization',
|
||||
array('action' => 'twitterauthorization')
|
||||
);
|
||||
$m->connect('settings/twitter', array('action' => 'twittersettings'));
|
||||
|
||||
if (common_config('twitter', 'signin')) {
|
||||
$m->connect('main/twitterlogin', array('action' => 'twitterlogin'));
|
||||
}
|
||||
|
||||
$m->connect('admin/twitter', array('action' => 'twitteradminpanel'));
|
||||
|
||||
if (self::hasKeys()) {
|
||||
$m->connect(
|
||||
'twitter/authorization',
|
||||
array('action' => 'twitterauthorization')
|
||||
);
|
||||
$m->connect(
|
||||
'settings/twitter', array(
|
||||
'action' => 'twittersettings'
|
||||
)
|
||||
);
|
||||
if (common_config('twitter', 'signin')) {
|
||||
$m->connect(
|
||||
'main/twitterlogin',
|
||||
array('action' => 'twitterlogin')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -117,7 +149,7 @@ class TwitterBridgePlugin extends Plugin
|
||||
{
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
if (common_config('twitter', 'signin')) {
|
||||
if (self::hasKeys() && common_config('twitter', 'signin')) {
|
||||
$action->menuItem(
|
||||
common_local_url('twitterlogin'),
|
||||
_m('Twitter'),
|
||||
@ -138,15 +170,16 @@ class TwitterBridgePlugin extends Plugin
|
||||
*/
|
||||
function onEndConnectSettingsNav(&$action)
|
||||
{
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(
|
||||
common_local_url('twittersettings'),
|
||||
_m('Twitter'),
|
||||
_m('Twitter integration options'),
|
||||
$action_name === 'twittersettings'
|
||||
);
|
||||
if (self::hasKeys()) {
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(
|
||||
common_local_url('twittersettings'),
|
||||
_m('Twitter'),
|
||||
_m('Twitter integration options'),
|
||||
$action_name === 'twittersettings'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -188,12 +221,12 @@ class TwitterBridgePlugin extends Plugin
|
||||
*/
|
||||
function onStartEnqueueNotice($notice, &$transports)
|
||||
{
|
||||
// Avoid a possible loop
|
||||
|
||||
if ($notice->source != 'twitter') {
|
||||
array_push($transports, 'twitter');
|
||||
if (self::hasKeys()) {
|
||||
// Avoid a possible loop
|
||||
if ($notice->source != 'twitter') {
|
||||
array_push($transports, 'twitter');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -206,18 +239,19 @@ class TwitterBridgePlugin extends Plugin
|
||||
*/
|
||||
function onGetValidDaemons($daemons)
|
||||
{
|
||||
array_push(
|
||||
$daemons,
|
||||
INSTALLDIR
|
||||
. '/plugins/TwitterBridge/daemons/synctwitterfriends.php'
|
||||
);
|
||||
|
||||
if (common_config('twitterimport', 'enabled')) {
|
||||
if (self::hasKeys()) {
|
||||
array_push(
|
||||
$daemons,
|
||||
INSTALLDIR
|
||||
. '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php'
|
||||
. '/plugins/TwitterBridge/daemons/synctwitterfriends.php'
|
||||
);
|
||||
if (common_config('twitterimport', 'enabled')) {
|
||||
array_push(
|
||||
$daemons,
|
||||
INSTALLDIR
|
||||
. '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -232,7 +266,9 @@ class TwitterBridgePlugin extends Plugin
|
||||
*/
|
||||
function onEndInitializeQueueManager($manager)
|
||||
{
|
||||
$manager->connect('twitter', 'TwitterQueueHandler');
|
||||
if (self::hasKeys()) {
|
||||
$manager->connect('twitter', 'TwitterQueueHandler');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,15 @@ class TwitterAdminPanelForm extends AdminForm
|
||||
);
|
||||
$this->unli();
|
||||
|
||||
$globalConsumerKey = common_config('twitter', 'global_consumer_key');
|
||||
$globalConsumerSec = common_config('twitter', 'global_consumer_secret');
|
||||
|
||||
if (!empty($globalConsumerKey) && !empty($globalConsumerSec)) {
|
||||
$this->li();
|
||||
$this->out->element('p', 'form_guide', _('Note: a global consumer key and secret are set.'));
|
||||
$this->unli();
|
||||
}
|
||||
|
||||
$this->li();
|
||||
$this->input(
|
||||
'source',
|
||||
|
@ -22,7 +22,7 @@
|
||||
* @category Integration
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -61,8 +61,23 @@ class TwitterOAuthClient extends OAuthClient
|
||||
$consumer_key = common_config('twitter', 'consumer_key');
|
||||
$consumer_secret = common_config('twitter', 'consumer_secret');
|
||||
|
||||
parent::__construct($consumer_key, $consumer_secret,
|
||||
$oauth_token, $oauth_token_secret);
|
||||
if (empty($consumer_key) && empty($consumer_secret)) {
|
||||
$consumer_key = common_config(
|
||||
'twitter',
|
||||
'global_consumer_key'
|
||||
);
|
||||
$consumer_secret = common_config(
|
||||
'twitter',
|
||||
'global_consumer_secret'
|
||||
);
|
||||
}
|
||||
|
||||
parent::__construct(
|
||||
$consumer_key,
|
||||
$consumer_secret,
|
||||
$oauth_token,
|
||||
$oauth_token_secret
|
||||
);
|
||||
}
|
||||
|
||||
// XXX: the following two functions are to support the horrible hack
|
||||
|
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;
|
@ -452,6 +452,13 @@ width:100%;
|
||||
float:left;
|
||||
}
|
||||
|
||||
#content.admin {
|
||||
width:95.5%;
|
||||
}
|
||||
#content.admin #content_inner {
|
||||
width:66.3%;
|
||||
}
|
||||
|
||||
#aside_primary {
|
||||
width:27.917%;
|
||||
min-height:259px;
|
||||
@ -764,10 +771,12 @@ display:none;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.entity_moderation {
|
||||
.entity_moderation,
|
||||
.entity_role {
|
||||
position:relative;
|
||||
}
|
||||
.entity_moderation p {
|
||||
.entity_moderation p,
|
||||
.entity_role p {
|
||||
border-radius:4px;
|
||||
-moz-border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
@ -775,13 +784,14 @@ font-weight:bold;
|
||||
padding-bottom:2px;
|
||||
margin-bottom:7px;
|
||||
}
|
||||
.entity_moderation ul {
|
||||
.entity_moderation ul,
|
||||
.entity_role ul {
|
||||
display:none;
|
||||
}
|
||||
.entity_moderation:hover ul {
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul {
|
||||
display:block;
|
||||
min-width:21%;
|
||||
width:100%;
|
||||
width:110%;
|
||||
padding:11px;
|
||||
position:absolute;
|
||||
top:-1px;
|
||||
|
@ -45,6 +45,11 @@
|
||||
White pin with green background
|
||||
White underscore 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
|
||||
|
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,
|
||||
.form_settings fieldset fieldset,
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul,
|
||||
.dialogbox {
|
||||
border-color:#DDDDDD;
|
||||
}
|
||||
@ -67,6 +68,7 @@ input.submit,
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_moderation p,
|
||||
.entity_role p,
|
||||
button {
|
||||
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,
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_moderation p {
|
||||
.entity_moderation p,
|
||||
.entity_role p {
|
||||
color:#002FA7;
|
||||
}
|
||||
|
||||
@ -190,6 +193,9 @@ button.close,
|
||||
.entity_sandbox input.submit,
|
||||
.entity_silence input.submit,
|
||||
.entity_delete input.submit,
|
||||
.entity_role p,
|
||||
.entity_role_administrator input.submit,
|
||||
.entity_role_moderator input.submit,
|
||||
.notice-options .repeated,
|
||||
.form_notice label[for=notice_data-geo],
|
||||
button.minimize,
|
||||
@ -229,6 +235,7 @@ border-color:transparent;
|
||||
#site_nav_local_views .current a,
|
||||
.entity_send-a-message .form_notice,
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul,
|
||||
.dialogbox {
|
||||
background-color:#FFFFFF;
|
||||
}
|
||||
@ -319,6 +326,7 @@ background-position: 5px -852px;
|
||||
}
|
||||
.entity_send-a-message .form_notice,
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul,
|
||||
.dialogbox {
|
||||
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 {
|
||||
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 {
|
||||
background-position: 5px -1973px;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
|
||||
.pagination .nav_next a,
|
||||
.form_settings fieldset fieldset,
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul,
|
||||
.dialogbox {
|
||||
border-color:#DDDDDD;
|
||||
}
|
||||
@ -67,6 +68,7 @@ input.submit,
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_moderation p,
|
||||
.entity_role p,
|
||||
button {
|
||||
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,
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_moderation p {
|
||||
.entity_moderation p,
|
||||
.entity_role p {
|
||||
color:#002FA7;
|
||||
}
|
||||
|
||||
@ -191,6 +194,9 @@ button.close,
|
||||
.entity_sandbox input.submit,
|
||||
.entity_silence input.submit,
|
||||
.entity_delete input.submit,
|
||||
.entity_role p,
|
||||
.entity_role_administrator input.submit,
|
||||
.entity_role_moderator input.submit,
|
||||
.notice-options .repeated,
|
||||
.form_notice label[for=notice_data-geo],
|
||||
button.minimize,
|
||||
@ -230,6 +236,7 @@ border-color:transparent;
|
||||
#site_nav_local_views .current a,
|
||||
.entity_send-a-message .form_notice,
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul,
|
||||
.dialogbox {
|
||||
background-color:#FFFFFF;
|
||||
}
|
||||
@ -319,6 +326,7 @@ background-position: 5px -852px;
|
||||
}
|
||||
.entity_send-a-message .form_notice,
|
||||
.entity_moderation:hover ul,
|
||||
.entity_role:hover ul,
|
||||
.dialogbox {
|
||||
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 {
|
||||
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 {
|
||||
background-position: 5px -1973px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user