forked from GNUsocial/gnu-social
Merge branch 'testing'
Conflicts: theme/base/css/display.css
This commit is contained in:
commit
5e1a9ad04d
@ -150,6 +150,12 @@ StartAddressData: Allows the site owner to provide additional information about
|
||||
EndAddressData: At the end of <address>
|
||||
- $action: the current action
|
||||
|
||||
StartShowSiteNotice: Before showing site notice
|
||||
- $action: the current action
|
||||
|
||||
EndShowSiteNotice: After showing site notice
|
||||
- $action: the current action
|
||||
|
||||
StartLoginGroupNav: Before showing the login and register navigation menu
|
||||
- $action: the current action
|
||||
|
||||
|
46
README
46
README
@ -2,8 +2,8 @@
|
||||
README
|
||||
------
|
||||
|
||||
StatusNet 0.9.0 ("Stand") Beta 3
|
||||
20 Jan 2010
|
||||
StatusNet 0.9.0 ("Stand") Beta 4
|
||||
27 Jan 2010
|
||||
|
||||
This is the README file for StatusNet (formerly Laconica), the Open
|
||||
Source microblogging platform. It includes installation instructions,
|
||||
@ -597,26 +597,19 @@ server is probably a good idea for high-volume sites.
|
||||
needs as a parameter the install path; if you run it from the
|
||||
StatusNet dir, "." should suffice.
|
||||
|
||||
This will run eight (for now) queue handlers:
|
||||
This will run the queue handlers:
|
||||
|
||||
* queuedaemon.php - polls for queued items for inbox processing and
|
||||
pushing out to OMB, SMS, XMPP, etc.
|
||||
* xmppdaemon.php - listens for new XMPP messages from users and stores
|
||||
them as notices in the database.
|
||||
* jabberqueuehandler.php - sends queued notices in the database to
|
||||
registered users who should receive them.
|
||||
* publicqueuehandler.php - sends queued notices in the database to
|
||||
public feed listeners.
|
||||
* ombqueuehandler.php - sends queued notices to OpenMicroBlogging
|
||||
recipients on foreign servers.
|
||||
* smsqueuehandler.php - sends queued notices to SMS-over-email addresses
|
||||
of registered users.
|
||||
* xmppconfirmhandler.php - sends confirmation messages to registered
|
||||
users.
|
||||
them as notices in the database; also pulls queued XMPP output from
|
||||
queuedaemon.php to push out to clients.
|
||||
|
||||
Note that these queue daemons are pretty raw, and need your care. In
|
||||
particular, they leak memory, and you may want to restart them on a
|
||||
regular (daily or so) basis with a cron job. Also, if they lose
|
||||
the connection to the XMPP server for too long, they'll simply die. It
|
||||
may be a good idea to use a daemon-monitoring service, like 'monit',
|
||||
These two daemons will automatically restart in most cases of failure
|
||||
including memory leaks (if a memory_limit is set), but may still die
|
||||
or behave oddly if they lose connections to the XMPP or queue servers.
|
||||
|
||||
It may be a good idea to use a daemon-monitoring service, like 'monit',
|
||||
to check their status and keep them running.
|
||||
|
||||
All the daemons write their process IDs (pids) to /var/run/ by
|
||||
@ -626,7 +619,7 @@ daemons.
|
||||
Since version 0.8.0, it's now possible to use a STOMP server instead of
|
||||
our kind of hacky home-grown DB-based queue solution. See the "queues"
|
||||
config section below for how to configure to use STOMP. As of this
|
||||
writing, the software has been tested with ActiveMQ (
|
||||
writing, the software has been tested with ActiveMQ.
|
||||
|
||||
Sitemaps
|
||||
--------
|
||||
@ -712,10 +705,12 @@ subdirectory to add a new language to your system. You'll need to
|
||||
compile the ".po" files into ".mo" files, however.
|
||||
|
||||
Contributions of translation information to StatusNet are very easy:
|
||||
you can use the Web interface at http://status.net/pootle/ to add one
|
||||
you can use the Web interface at TranslateWiki.net to add one
|
||||
or a few or lots of new translations -- or even new languages. You can
|
||||
also download more up-to-date .po files there, if you so desire.
|
||||
|
||||
For info on helping with translations, see http://status.net/wiki/Translations
|
||||
|
||||
Backups
|
||||
-------
|
||||
|
||||
@ -1492,6 +1487,15 @@ disabled: whether to enable this command. If enabled, users who send
|
||||
should enable it only after you've convinced yourself that
|
||||
it is safe. Default is 'false'.
|
||||
|
||||
singleuser
|
||||
----------
|
||||
|
||||
If an installation has only one user, this can simplify a lot of the
|
||||
interface. It also makes the user's profile the root URL.
|
||||
|
||||
enabled: Whether to run in "single user mode". Default false.
|
||||
nickname: nickname of the single user.
|
||||
|
||||
Plugins
|
||||
=======
|
||||
|
||||
|
192
actions/accessadminpanel.php
Normal file
192
actions/accessadminpanel.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Site access 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Administer site access settings
|
||||
*
|
||||
* @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 AccessadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Access');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using this form.
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Site access settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the site admin panel form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showForm()
|
||||
{
|
||||
$form = new AccessAdminPanelForm($this);
|
||||
$form->show();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings from the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
static $booleans = array('site' => array('private', 'inviteonly', 'closed'));
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
$values[$section][$setting] = ($this->boolean($setting)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
$config = new Config();
|
||||
|
||||
$config->query('BEGIN');
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
Config::save($section, $setting, $values[$section][$setting]);
|
||||
}
|
||||
}
|
||||
|
||||
$config->query('COMMIT');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AccessAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_site_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('accessadminpanel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_access'));
|
||||
$this->out->element('legend', null, _('Registration'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$this->out->checkbox('private', _('Private'),
|
||||
(bool) $this->value('private'),
|
||||
_('Prohibit anonymous users (not logged in) from viewing site?'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->checkbox('inviteonly', _('Invite only'),
|
||||
(bool) $this->value('inviteonly'),
|
||||
_('Make registration invitation only.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->checkbox('closed', _('Closed'),
|
||||
(bool) $this->value('closed'),
|
||||
_('Disable new registrations.'));
|
||||
$this->unli();
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Save'), 'submit', null, _('Save access settings'));
|
||||
}
|
||||
|
||||
}
|
@ -105,7 +105,22 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||
print json_encode($out);
|
||||
}
|
||||
|
||||
$this->endDocument($this->format);
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -82,4 +82,18 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*
|
||||
**/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -116,4 +116,19 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -87,7 +87,6 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether this API resource requires auth. Overloaded to look
|
||||
* return true in case source_id and source_screen_name are both empty
|
||||
@ -165,4 +164,19 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -119,4 +119,19 @@ class ApiGroupIsMemberAction extends ApiBareAuthAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -149,4 +149,19 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -92,5 +92,20 @@ class ApiHelpTestAction extends ApiPrivateAuthAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
94
actions/apioauthaccesstoken.php
Normal file
94
actions/apioauthaccesstoken.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Exchange an authorized OAuth request token for an access token
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @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 . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Exchange an authorized OAuth request token for an access token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthAccessTokenAction extends ApiOauthAction
|
||||
{
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$datastore = new ApiStatusNetOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
$atok = null;
|
||||
|
||||
try {
|
||||
$req = OAuthRequest::from_request();
|
||||
$atok = $server->fetch_access_token($req);
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
common_debug(var_export($req, true));
|
||||
$this->outputError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($atok)) {
|
||||
common_debug('couldn\'t get access token.');
|
||||
print "Token exchange failed. Has the request token been authorized?\n";
|
||||
} else {
|
||||
print $atok;
|
||||
}
|
||||
}
|
||||
|
||||
function outputError($msg)
|
||||
{
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print $msg . "\n";
|
||||
}
|
||||
}
|
||||
|
377
actions/apioauthauthorize.php
Normal file
377
actions/apioauthauthorize.php
Normal file
@ -0,0 +1,377 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @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 . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthAuthorizeAction extends ApiOauthAction
|
||||
{
|
||||
var $oauth_token;
|
||||
var $callback;
|
||||
var $app;
|
||||
var $nickname;
|
||||
var $password;
|
||||
var $store;
|
||||
|
||||
/**
|
||||
* Is this a read-only action?
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
common_debug("apioauthauthorize");
|
||||
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->password = $this->arg('password');
|
||||
$this->oauth_token = $this->arg('oauth_token');
|
||||
$this->callback = $this->arg('oauth_callback');
|
||||
$this->store = new ApiStatusNetOAuthDataStore();
|
||||
$this->app = $this->store->getAppByRequestToken($this->oauth_token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* Switches on request method; either shows the form or handles its input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
$this->handlePost();
|
||||
|
||||
} else {
|
||||
|
||||
// XXX: make better error messages
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
|
||||
common_debug("No request token found.");
|
||||
|
||||
$this->clientError(_('Bad request.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->app)) {
|
||||
common_debug('No app for that token.');
|
||||
$this->clientError(_('Bad request.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $this->app->name;
|
||||
common_debug("Requesting auth for app: " . $name);
|
||||
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
common_debug("handlePost()");
|
||||
|
||||
// check session token for CSRF protection.
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// check creds
|
||||
|
||||
$user = null;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$user = common_check_user($this->nickname, $this->password);
|
||||
if (empty($user)) {
|
||||
$this->showForm(_("Invalid nickname / password!"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$user = common_current_user();
|
||||
}
|
||||
|
||||
if ($this->arg('allow')) {
|
||||
|
||||
// mark the req token as authorized
|
||||
|
||||
$this->store->authorize_token($this->oauth_token);
|
||||
|
||||
// Check to see if there was a previous token associated
|
||||
// with this user/app and kill it. If the user is doing this she
|
||||
// probably doesn't want any old tokens anyway.
|
||||
|
||||
$appUser = Oauth_application_user::getByKeys($user, $this->app);
|
||||
|
||||
if (!empty($appUser)) {
|
||||
$result = $appUser->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($appUser, 'DELETE', __FILE__);
|
||||
throw new ServerException(_('DB error deleting OAuth app user.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// associated the authorized req token with the user and the app
|
||||
|
||||
$appUser = new Oauth_application_user();
|
||||
|
||||
$appUser->profile_id = $user->id;
|
||||
$appUser->application_id = $this->app->id;
|
||||
|
||||
// Note: do not copy the access type from the application.
|
||||
// The access type should always be 0 when the OAuth app
|
||||
// user record has a request token associated with it.
|
||||
// Access type gets assigned once an access token has been
|
||||
// granted. The OAuth app user record then gets updated
|
||||
// with the new access token and access type.
|
||||
|
||||
$appUser->token = $this->oauth_token;
|
||||
$appUser->created = common_sql_now();
|
||||
|
||||
$result = $appUser->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($appUser, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('DB error inserting OAuth app user.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// if we have a callback redirect and provide the token
|
||||
|
||||
// A callback specified in the app setup overrides whatever
|
||||
// is passed in with the request.
|
||||
|
||||
common_debug("Req token is authorized - doing callback");
|
||||
|
||||
if (!empty($this->app->callback_url)) {
|
||||
$this->callback = $this->app->callback_url;
|
||||
}
|
||||
|
||||
if (!empty($this->callback)) {
|
||||
|
||||
// XXX: Need better way to build this redirect url.
|
||||
|
||||
$target_url = $this->getCallback($this->callback,
|
||||
array('oauth_token' => $this->oauth_token));
|
||||
|
||||
common_debug("Doing callback to $target_url");
|
||||
|
||||
common_redirect($target_url, 303);
|
||||
} else {
|
||||
common_debug("callback was empty!");
|
||||
}
|
||||
|
||||
// otherwise inform the user that the rt was authorized
|
||||
|
||||
$this->elementStart('p');
|
||||
|
||||
// XXX: Do OAuth 1.0a verifier code
|
||||
|
||||
$this->raw(sprintf(_("The request token %s has been authorized. " .
|
||||
'Please exchange it for an access token.'),
|
||||
$this->oauth_token));
|
||||
|
||||
$this->elementEnd('p');
|
||||
|
||||
} else if ($this->arg('deny')) {
|
||||
|
||||
$this->elementStart('p');
|
||||
|
||||
$this->raw(sprintf(_("The request token %s has been denied."),
|
||||
$this->oauth_token));
|
||||
|
||||
$this->elementEnd('p');
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($error=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
parent::showScripts();
|
||||
if (!common_logged_in()) {
|
||||
$this->autofocus('nickname');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('An application would like to connect to your account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the authorization form.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_apioauthauthorize',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('apioauthauthorize')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
|
||||
_('Allow or deny access'));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->hidden('oauth_token', $this->oauth_token);
|
||||
$this->hidden('oauth_callback', $this->callback);
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->elementStart('p');
|
||||
if (!empty($this->app->icon)) {
|
||||
$this->element('img', array('src' => $this->app->icon));
|
||||
}
|
||||
|
||||
$access = ($this->app->access_type & Oauth_application::$writeAccess) ?
|
||||
'access and update' : 'access';
|
||||
|
||||
$msg = _('The application <strong>%1$s</strong> by ' .
|
||||
'<strong>%2$s</strong> would like the ability ' .
|
||||
'to <strong>%3$s</strong> your account data.');
|
||||
|
||||
$this->raw(sprintf($msg,
|
||||
$this->app->name,
|
||||
$this->app->organization,
|
||||
$access));
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
if (!common_logged_in()) {
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Account'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('password', _('Password'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
}
|
||||
|
||||
$this->element('input', array('id' => 'deny_submit',
|
||||
'class' => 'submit submit form_action-primary',
|
||||
'name' => 'deny',
|
||||
'type' => 'submit',
|
||||
'value' => _('Deny')));
|
||||
|
||||
$this->element('input', array('id' => 'allow_submit',
|
||||
'class' => 'submit submit form_action-secondary',
|
||||
'name' => 'allow',
|
||||
'type' => 'submit',
|
||||
'value' => _('Allow')));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using the form
|
||||
*
|
||||
* For "remembered" logins, we make the user re-login when they
|
||||
* try to change settings. Different instructions for this case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Allow or deny access to your account information.');
|
||||
}
|
||||
|
||||
/**
|
||||
* A local menu
|
||||
*
|
||||
* Shows different login/register actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showLocalNav()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
99
actions/apioauthrequesttoken.php
Normal file
99
actions/apioauthrequesttoken.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get an OAuth request token
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @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 . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Get an OAuth request token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthRequestTokenAction extends ApiOauthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->callback = $this->arg('oauth_callback');
|
||||
|
||||
if (!empty($this->callback)) {
|
||||
common_debug("callback: $this->callback");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$datastore = new ApiStatusNetOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
try {
|
||||
$req = OAuthRequest::from_request();
|
||||
$token = $server->fetch_request_token($req);
|
||||
print $token;
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @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/
|
||||
*/
|
||||
@ -79,12 +79,16 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->status = $this->trimmed('status');
|
||||
$this->source = $this->trimmed('source');
|
||||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
|
||||
// try to set the source attr from OAuth app
|
||||
if (empty($this->source)) {
|
||||
$this->source = $this->oauth_source;
|
||||
}
|
||||
|
||||
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
|
||||
$this->source = 'api';
|
||||
}
|
||||
@ -140,7 +144,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
if (empty($this->auth_user)) {
|
||||
$this->clientError(_('No such user.'), 404, $this->format);
|
||||
return;
|
||||
}
|
||||
@ -167,7 +171,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
// Check for commands
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
$cmd = $inter->handle_command($this->user, $status_shortened);
|
||||
$cmd = $inter->handle_command($this->auth_user, $status_shortened);
|
||||
|
||||
if ($cmd) {
|
||||
|
||||
@ -179,7 +183,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
// And, it returns your last status whether the cmd was successful
|
||||
// or not!
|
||||
|
||||
$this->notice = $this->user->getCurrentNotice();
|
||||
$this->notice = $this->auth_user->getCurrentNotice();
|
||||
|
||||
} else {
|
||||
|
||||
@ -206,7 +210,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
$upload = null;
|
||||
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->user);
|
||||
$upload = MediaFile::fromUpload('media', $this->auth_user);
|
||||
} catch (ClientException $ce) {
|
||||
$this->clientError($ce->getMessage());
|
||||
return;
|
||||
@ -229,19 +233,19 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
|
||||
$options = array('reply_to' => $reply_to);
|
||||
|
||||
if ($this->user->shareLocation()) {
|
||||
if ($this->auth_user->shareLocation()) {
|
||||
|
||||
$locOptions = Notice::locationOptions($this->lat,
|
||||
$this->lon,
|
||||
null,
|
||||
null,
|
||||
$this->user->getProfile());
|
||||
$this->auth_user->getProfile());
|
||||
|
||||
$options = array_merge($options, $locOptions);
|
||||
}
|
||||
|
||||
$this->notice =
|
||||
Notice::saveNew($this->user->id,
|
||||
Notice::saveNew($this->auth_user->id,
|
||||
$content,
|
||||
$this->source,
|
||||
$options);
|
||||
@ -250,7 +254,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$this->showNotice();
|
||||
|
@ -138,5 +138,20 @@ class ApiStatusnetConfigAction extends ApiAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -98,5 +98,20 @@ class ApiStatusnetVersionAction extends ApiPrivateAuthAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -123,4 +123,19 @@ class ApiUserShowAction extends ApiPrivateAuthAction
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -416,8 +416,8 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
parent::showScripts();
|
||||
|
||||
if ($this->mode == 'crop') {
|
||||
$this->script('js/jcrop/jquery.Jcrop.min.js');
|
||||
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
||||
$this->script('jcrop/jquery.Jcrop.min.js');
|
||||
$this->script('jcrop/jquery.Jcrop.go.js');
|
||||
}
|
||||
|
||||
$this->autofocus('avatarfile');
|
||||
|
@ -302,8 +302,8 @@ class DesignadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
parent::showScripts();
|
||||
|
||||
$this->script('js/farbtastic/farbtastic.js');
|
||||
$this->script('js/userdesign.go.js');
|
||||
$this->script('farbtastic/farbtastic.js');
|
||||
$this->script('userdesign.go.js');
|
||||
|
||||
$this->autofocus('design_background-image_file');
|
||||
}
|
||||
|
152
actions/doc.php
152
actions/doc.php
@ -45,11 +45,23 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
*/
|
||||
class DocAction extends Action
|
||||
{
|
||||
var $filename;
|
||||
var $title;
|
||||
var $output = null;
|
||||
var $filename = null;
|
||||
var $title = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->title = $this->trimmed('title');
|
||||
$this->output = null;
|
||||
|
||||
$this->loadDoc();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
@ -58,51 +70,51 @@ class DocAction extends Action
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$this->title = $this->trimmed('title');
|
||||
$this->output = null;
|
||||
|
||||
if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
|
||||
|
||||
$this->filename = INSTALLDIR.'/doc-src/'.$this->title;
|
||||
if (!file_exists($this->filename)) {
|
||||
$this->clientError(_('No such document.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$c = file_get_contents($this->filename);
|
||||
$this->output = common_markup_to_html($c);
|
||||
|
||||
Event::handle('EndLoadDoc', array($this->title, &$this->output));
|
||||
}
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
// overrrided to add entry-title class
|
||||
function showPageTitle() {
|
||||
/**
|
||||
* Page title
|
||||
*
|
||||
* Gives the page title of the document. Override default for hAtom entry.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showPageTitle()
|
||||
{
|
||||
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
||||
}
|
||||
|
||||
// overrided to add hentry, and content-inner classes
|
||||
/**
|
||||
* Block for content.
|
||||
*
|
||||
* Overrides default from Action to wrap everything in an hAtom entry.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
|
||||
function showContentBlock()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
|
||||
$this->showPageTitle();
|
||||
$this->showPageNoticeBlock();
|
||||
$this->elementStart('div', array('id' => 'content_inner',
|
||||
'class' => 'entry-content'));
|
||||
// show the actual content (forms, lists, whatever)
|
||||
$this->showContent();
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
|
||||
$this->showPageTitle();
|
||||
$this->showPageNoticeBlock();
|
||||
$this->elementStart('div', array('id' => 'content_inner',
|
||||
'class' => 'entry-content'));
|
||||
// show the actual content (forms, lists, whatever)
|
||||
$this->showContent();
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display content.
|
||||
*
|
||||
* @return nothing
|
||||
* Shows the content of the document.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->raw($this->output);
|
||||
@ -111,6 +123,8 @@ class DocAction extends Action
|
||||
/**
|
||||
* Page title.
|
||||
*
|
||||
* Uses the title of the document.
|
||||
*
|
||||
* @return page title
|
||||
*/
|
||||
function title()
|
||||
@ -118,8 +132,74 @@ class DocAction extends Action
|
||||
return ucfirst($this->title);
|
||||
}
|
||||
|
||||
/**
|
||||
* These pages are read-only.
|
||||
*
|
||||
* @param array $args unused.
|
||||
*
|
||||
* @return boolean read-only flag (false)
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function loadDoc()
|
||||
{
|
||||
if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
|
||||
|
||||
$this->filename = $this->getFilename();
|
||||
|
||||
if (empty($this->filename)) {
|
||||
throw new ClientException(sprintf(_('No such document "%s"'), $this->title), 404);
|
||||
}
|
||||
|
||||
$c = file_get_contents($this->filename);
|
||||
|
||||
$this->output = common_markup_to_html($c);
|
||||
|
||||
Event::handle('EndLoadDoc', array($this->title, &$this->output));
|
||||
}
|
||||
}
|
||||
|
||||
function getFilename()
|
||||
{
|
||||
if (file_exists(INSTALLDIR.'/local/doc-src/'.$this->title)) {
|
||||
$localDef = INSTALLDIR.'/local/doc-src/'.$this->title;
|
||||
}
|
||||
|
||||
$local = glob(INSTALLDIR.'/local/doc-src/'.$this->title.'.*');
|
||||
|
||||
if (count($local) || isset($localDef)) {
|
||||
return $this->negotiateLanguage($local, $localDef);
|
||||
}
|
||||
|
||||
if (file_exists(INSTALLDIR.'/doc-src/'.$this->title)) {
|
||||
$distDef = INSTALLDIR.'/doc-src/'.$this->title;
|
||||
}
|
||||
|
||||
$dist = glob(INSTALLDIR.'/doc-src/'.$this->title.'.*');
|
||||
|
||||
if (count($dist) || isset($distDef)) {
|
||||
return $this->negotiateLanguage($dist, $distDef);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function negotiateLanguage($filenames, $defaultFilename=null)
|
||||
{
|
||||
// XXX: do this better
|
||||
|
||||
$langcode = common_language();
|
||||
|
||||
foreach ($filenames as $filename) {
|
||||
if (preg_match('/\.'.$langcode.'$/', $filename)) {
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
return $defaultFilename;
|
||||
}
|
||||
}
|
||||
|
264
actions/editapplication.php
Normal file
264
actions/editapplication.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Edit an OAuth Application
|
||||
*
|
||||
* 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 Applications
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the details of an OAuth application
|
||||
*
|
||||
* This is the form for editing an application
|
||||
*
|
||||
* @category Application
|
||||
* @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 EditApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
var $msg = null;
|
||||
var $owner = null;
|
||||
var $app = null;
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Edit Application');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to edit an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = (int)$this->arg('id');
|
||||
|
||||
$this->app = Oauth_application::staticGet($id);
|
||||
$this->owner = User::staticGet($this->app->owner);
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur->id != $this->owner->id) {
|
||||
$this->clientError(_('You are not the owner of this application.'), 401);
|
||||
}
|
||||
|
||||
if (!$this->app) {
|
||||
$this->clientError(_('No such application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On GET, show the form. On POST, try to save the app.
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->handlePost($args);
|
||||
} else {
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost($args)
|
||||
{
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
$msg = _('The server was unable to handle that much POST ' .
|
||||
'data (%s bytes) due to its current configuration.');
|
||||
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($this->arg('cancel')) {
|
||||
common_redirect(common_local_url('showapplication',
|
||||
array('id' => $this->app->id)), 303);
|
||||
} elseif ($this->arg('save')) {
|
||||
$this->trySave();
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($msg=null)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$form = new ApplicationEditForm($this, $this->app);
|
||||
$form->show();
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if (!empty($this->msg)) {
|
||||
$this->element('p', 'error', $this->msg);
|
||||
} else {
|
||||
$this->element('p', 'instructions',
|
||||
_('Use this form to edit your application.'));
|
||||
}
|
||||
}
|
||||
|
||||
function trySave()
|
||||
{
|
||||
$name = $this->trimmed('name');
|
||||
$description = $this->trimmed('description');
|
||||
$source_url = $this->trimmed('source_url');
|
||||
$organization = $this->trimmed('organization');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$callback_url = $this->trimmed('callback_url');
|
||||
$type = $this->arg('app_type');
|
||||
$access_type = $this->arg('default_access_type');
|
||||
|
||||
if (empty($name)) {
|
||||
$this->showForm(_('Name is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($name) > 255) {
|
||||
$this->showForm(_('Name is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($description)) {
|
||||
$this->showForm(_('Description is required.'));
|
||||
return;
|
||||
} elseif (Oauth_application::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(
|
||||
_('Description is too long (max %d chars).'),
|
||||
Oauth_application::maxDescription()));
|
||||
return;
|
||||
} elseif (mb_strlen($source_url) > 255) {
|
||||
$this->showForm(_('Source URL is too long.'));
|
||||
return;
|
||||
} elseif ((mb_strlen($source_url) > 0)
|
||||
&& !Validate::uri($source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))))
|
||||
{
|
||||
$this->showForm(_('Source URL is not valid.'));
|
||||
return;
|
||||
} elseif (empty($organization)) {
|
||||
$this->showForm(_('Organization is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($organization) > 255) {
|
||||
$this->showForm(_('Organization is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($homepage)) {
|
||||
$this->showForm(_('Organization homepage is required.'));
|
||||
return;
|
||||
} elseif ((mb_strlen($homepage) > 0)
|
||||
&& !Validate::uri($homepage,
|
||||
array('allowed_schemes' => array('http', 'https'))))
|
||||
{
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} elseif (mb_strlen($callback_url) > 255) {
|
||||
$this->showForm(_('Callback is too long.'));
|
||||
return;
|
||||
} elseif (mb_strlen($callback_url) > 0
|
||||
&& !Validate::uri($source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
))
|
||||
{
|
||||
$this->showForm(_('Callback URL is not valid.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
// Checked in prepare() above
|
||||
|
||||
assert(!is_null($cur));
|
||||
assert(!is_null($this->app));
|
||||
|
||||
$orig = clone($this->app);
|
||||
|
||||
$this->app->name = $name;
|
||||
$this->app->description = $description;
|
||||
$this->app->source_url = $source_url;
|
||||
$this->app->organization = $organization;
|
||||
$this->app->homepage = $homepage;
|
||||
$this->app->callback_url = $callback_url;
|
||||
$this->app->type = $type;
|
||||
|
||||
common_debug("access_type = $access_type");
|
||||
|
||||
if ($access_type == 'r') {
|
||||
$this->app->access_type = 1;
|
||||
} else {
|
||||
$this->app->access_type = 3;
|
||||
}
|
||||
|
||||
$result = $this->app->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($this->app, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Could not update application.'));
|
||||
}
|
||||
|
||||
$this->app->uploadLogo();
|
||||
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -437,8 +437,8 @@ class GrouplogoAction extends GroupDesignAction
|
||||
parent::showScripts();
|
||||
|
||||
if ($this->mode == 'crop') {
|
||||
$this->script('js/jcrop/jquery.Jcrop.min.js');
|
||||
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
||||
$this->script('jcrop/jquery.Jcrop.min.js');
|
||||
$this->script('jcrop/jquery.Jcrop.go.js');
|
||||
}
|
||||
|
||||
$this->autofocus('avatarfile');
|
||||
|
@ -56,10 +56,10 @@ class InboxAction extends MailboxAction
|
||||
function title()
|
||||
{
|
||||
if ($this->page > 1) {
|
||||
return sprintf(_("Inbox for %1$s - page %2$d"), $this->user->nickname,
|
||||
return sprintf(_('Inbox for %1$s - page %2$d'), $this->user->nickname,
|
||||
$this->page);
|
||||
} else {
|
||||
return sprintf(_("Inbox for %s"), $this->user->nickname);
|
||||
return sprintf(_('Inbox for %s'), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
|
||||
|
277
actions/newapplication.php
Normal file
277
actions/newapplication.php
Normal file
@ -0,0 +1,277 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Register a new OAuth Application
|
||||
*
|
||||
* 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 Applications
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new application
|
||||
*
|
||||
* This is the form for adding a new application
|
||||
*
|
||||
* @category Application
|
||||
* @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 NewApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
var $msg;
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('New Application');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to register an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On GET, show the form. On POST, try to save the app.
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->handlePost($args);
|
||||
} else {
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost($args)
|
||||
{
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
$msg = _('The server was unable to handle that much POST ' .
|
||||
'data (%s bytes) due to its current configuration.');
|
||||
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($this->arg('cancel')) {
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
} elseif ($this->arg('save')) {
|
||||
$this->trySave();
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($msg=null)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$form = new ApplicationEditForm($this);
|
||||
$form->show();
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->msg) {
|
||||
$this->element('p', 'error', $this->msg);
|
||||
} else {
|
||||
$this->element('p', 'instructions',
|
||||
_('Use this form to register a new application.'));
|
||||
}
|
||||
}
|
||||
|
||||
function trySave()
|
||||
{
|
||||
$name = $this->trimmed('name');
|
||||
$description = $this->trimmed('description');
|
||||
$source_url = $this->trimmed('source_url');
|
||||
$organization = $this->trimmed('organization');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$callback_url = $this->trimmed('callback_url');
|
||||
$type = $this->arg('app_type');
|
||||
$access_type = $this->arg('default_access_type');
|
||||
|
||||
if (empty($name)) {
|
||||
$this->showForm(_('Name is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($name) > 255) {
|
||||
$this->showForm(_('Name is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($description)) {
|
||||
$this->showForm(_('Description is required.'));
|
||||
return;
|
||||
} elseif (Oauth_application::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(
|
||||
_('Description is too long (max %d chars).'),
|
||||
Oauth_application::maxDescription()));
|
||||
return;
|
||||
} elseif (empty($source_url)) {
|
||||
$this->showForm(_('Source URL is required.'));
|
||||
return;
|
||||
} elseif ((strlen($source_url) > 0)
|
||||
&& !Validate::uri(
|
||||
$source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
)
|
||||
)
|
||||
{
|
||||
$this->showForm(_('Source URL is not valid.'));
|
||||
return;
|
||||
} elseif (empty($organization)) {
|
||||
$this->showForm(_('Organization is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($organization) > 255) {
|
||||
$this->showForm(_('Organization is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($homepage)) {
|
||||
$this->showForm(_('Organization homepage is required.'));
|
||||
return;
|
||||
} elseif ((strlen($homepage) > 0)
|
||||
&& !Validate::uri(
|
||||
$homepage,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
)
|
||||
)
|
||||
{
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} elseif (mb_strlen($callback_url) > 255) {
|
||||
$this->showForm(_('Callback is too long.'));
|
||||
return;
|
||||
} elseif (strlen($callback_url) > 0
|
||||
&& !Validate::uri(
|
||||
$source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
)
|
||||
)
|
||||
{
|
||||
$this->showForm(_('Callback URL is not valid.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
// Checked in prepare() above
|
||||
|
||||
assert(!is_null($cur));
|
||||
|
||||
$app = new Oauth_application();
|
||||
|
||||
$app->query('BEGIN');
|
||||
|
||||
$app->name = $name;
|
||||
$app->owner = $cur->id;
|
||||
$app->description = $description;
|
||||
$app->source_url = $source_url;
|
||||
$app->organization = $organization;
|
||||
$app->homepage = $homepage;
|
||||
$app->callback_url = $callback_url;
|
||||
$app->type = $type;
|
||||
|
||||
// Yeah, I dunno why I chose bit flags. I guess so I could
|
||||
// copy this value directly to Oauth_application_user
|
||||
// access_type which I think does need bit flags -- Z
|
||||
|
||||
if ($access_type == 'r') {
|
||||
$app->setAccessFlags(true, false);
|
||||
} else {
|
||||
$app->setAccessFlags(true, true);
|
||||
}
|
||||
|
||||
$app->created = common_sql_now();
|
||||
|
||||
// generate consumer key and secret
|
||||
|
||||
$consumer = Consumer::generateNew();
|
||||
|
||||
$result = $consumer->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'INSERT', __FILE__);
|
||||
$this->serverError(_('Could not create application.'));
|
||||
}
|
||||
|
||||
$app->consumer_key = $consumer->consumer_key;
|
||||
|
||||
$this->app_id = $app->insert();
|
||||
|
||||
if (!$this->app_id) {
|
||||
common_log_db_error($app, 'INSERT', __FILE__);
|
||||
$this->serverError(_('Could not create application.'));
|
||||
$app->query('ROLLBACK');
|
||||
}
|
||||
|
||||
$app->uploadLogo();
|
||||
|
||||
$app->query('COMMIT');
|
||||
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
166
actions/oauthappssettings.php
Normal file
166
actions/oauthappssettings.php
Normal file
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List the OAuth applications that a user has registered with this instance
|
||||
*
|
||||
* 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 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/settingsaction.php';
|
||||
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
|
||||
/**
|
||||
* Show a user's registered OAuth applications
|
||||
*
|
||||
* @category Settings
|
||||
* @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/
|
||||
*
|
||||
* @see SettingsAction
|
||||
*/
|
||||
|
||||
class OauthappssettingsAction extends SettingsAction
|
||||
{
|
||||
var $page = 0;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to list your applications.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('OAuth applications');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Applications you have registered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||
$limit = APPS_PER_PAGE + 1;
|
||||
|
||||
$application = new Oauth_application();
|
||||
$application->owner = $user->id;
|
||||
$application->limit($offset, $limit);
|
||||
$application->orderBy('created DESC');
|
||||
$application->find();
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
if ($application) {
|
||||
$al = new ApplicationList($application, $user, $this);
|
||||
$cnt = $al->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementStart('p', array('id' => 'application_register'));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('newapplication'),
|
||||
'class' => 'more'
|
||||
),
|
||||
'Register a new application');
|
||||
$this->elementEnd('p');
|
||||
|
||||
$this->pagination(
|
||||
$this->page > 1,
|
||||
$cnt > APPS_PER_PAGE,
|
||||
$this->page,
|
||||
'oauthappssettings'
|
||||
);
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('You have not registered any applications yet.'));
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posts to this form
|
||||
*
|
||||
* Based on the button that was pressed, muxes out to other functions
|
||||
* to do the actual task requested.
|
||||
*
|
||||
* All sub-functions reload the form with a message -- success or failure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
// CSRF protection
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
212
actions/oauthconnectionssettings.php
Normal file
212
actions/oauthconnectionssettings.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a user's OAuth connected applications
|
||||
*
|
||||
* 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 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/connectsettingsaction.php';
|
||||
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
|
||||
/**
|
||||
* Show connected OAuth applications
|
||||
*
|
||||
* @category Settings
|
||||
* @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/
|
||||
*
|
||||
* @see SettingsAction
|
||||
*/
|
||||
|
||||
class OauthconnectionssettingsAction extends ConnectSettingsAction
|
||||
{
|
||||
|
||||
var $page = null;
|
||||
var $id = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->id = (int)$this->arg('id');
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Connected applications');
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('You have allowed the following applications to access you account.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||
$limit = APPS_PER_PAGE + 1;
|
||||
|
||||
$application = $profile->getApplications($offset, $limit);
|
||||
|
||||
$cnt == 0;
|
||||
|
||||
if (!empty($application)) {
|
||||
$al = new ApplicationList($application, $user, $this, true);
|
||||
$cnt = $al->show();
|
||||
}
|
||||
|
||||
if ($cnt == 0) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > APPS_PER_PAGE,
|
||||
$this->page, 'connectionssettings',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posts to this form
|
||||
*
|
||||
* Based on the button that was pressed, muxes out to other functions
|
||||
* to do the actual task requested.
|
||||
*
|
||||
* All sub-functions reload the form with a message -- success or failure.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
// CSRF protection
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->arg('revoke')) {
|
||||
$this->revokeAccess($this->id);
|
||||
|
||||
// XXX: Show some indicator to the user of what's been done.
|
||||
|
||||
$this->showPage();
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'), 401);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function revokeAccess($appId)
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
$app = Oauth_application::staticGet('id', $appId);
|
||||
|
||||
if (empty($app)) {
|
||||
$this->clientError(_('No such application.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$appUser = Oauth_application_user::getByKeys($cur, $app);
|
||||
|
||||
if (empty($appUser)) {
|
||||
$this->clientError(_('You are not a user of that application.'), 401);
|
||||
return false;
|
||||
}
|
||||
|
||||
$orig = clone($appUser);
|
||||
$appUser->access_type = 0; // No access
|
||||
$result = $appUser->update();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($orig, 'UPDATE', __FILE__);
|
||||
$this->clientError(_('Unable to revoke access for app: ' . $app->id));
|
||||
return false;
|
||||
}
|
||||
|
||||
$msg = 'User %s (id: %d) revoked access to app %s (id: %d)';
|
||||
common_log(LOG_INFO, sprintf($msg, $cur->nickname,
|
||||
$cur->id, $app->name, $app->id));
|
||||
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('You have not authorized any applications to use your account.'));
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
$this->element('h2', null, 'Developers');
|
||||
$this->elementStart('p');
|
||||
$this->raw(_('Developers can edit the registration settings for their applications '));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('oauthappssettings')),
|
||||
'here.');
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
}
|
@ -55,10 +55,10 @@ class OutboxAction extends MailboxAction
|
||||
function title()
|
||||
{
|
||||
if ($this->page > 1) {
|
||||
return sprintf(_("Outbox for %1$s - page %2$d"),
|
||||
return sprintf(_('Outbox for %1$s - page %2$d'),
|
||||
$this->user->nickname, $page);
|
||||
} else {
|
||||
return sprintf(_("Outbox for %s"), $this->user->nickname);
|
||||
return sprintf(_('Outbox for %s'), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -98,6 +98,11 @@ class PathsadminpanelAction extends AdminPanelAction
|
||||
'background' => array('server', 'dir', 'path')
|
||||
);
|
||||
|
||||
// XXX: If we're only going to have one boolean on thi page we
|
||||
// can remove some of the boolean processing code --Z
|
||||
|
||||
static $booleans = array('site' => array('fancy'));
|
||||
|
||||
$values = array();
|
||||
|
||||
foreach ($settings as $section => $parts) {
|
||||
@ -106,6 +111,12 @@ class PathsadminpanelAction extends AdminPanelAction
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
$values[$section][$setting] = ($this->boolean($setting)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
$this->validate($values);
|
||||
|
||||
// assert(all values are valid);
|
||||
@ -120,7 +131,13 @@ class PathsadminpanelAction extends AdminPanelAction
|
||||
}
|
||||
}
|
||||
|
||||
$config->query('COMMIT');
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
Config::save($section, $setting, $values[$section][$setting]);
|
||||
}
|
||||
}
|
||||
|
||||
$config->query('COMMIT');
|
||||
|
||||
return;
|
||||
}
|
||||
@ -213,10 +230,14 @@ class PathsAdminPanelForm extends AdminForm
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_paths_locale'));
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_paths_locale'));
|
||||
$this->out->element('legend', null, _('Site'), 'site');
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->li();
|
||||
$this->input('server', _('Server'), _('Site\'s server hostname.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->input('path', _('Path'), _('Site path'));
|
||||
$this->unli();
|
||||
@ -225,6 +246,12 @@ class PathsAdminPanelForm extends AdminForm
|
||||
$this->input('locale_path', _('Path to locales'), _('Directory path to locales'), 'site');
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->checkbox('fancy', _('Fancy URLs'),
|
||||
(bool) $this->value('fancy'),
|
||||
_('Use fancy (more readable and memorable) URLs?'));
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
|
@ -124,7 +124,7 @@ class RepliesAction extends OwnerDesignAction
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("Replies to %s"), $this->user->nickname);
|
||||
} else {
|
||||
return sprintf(_("Replies to %1$s, page %2$d"),
|
||||
return sprintf(_('Replies to %1$s, page %2$d'),
|
||||
$this->user->nickname,
|
||||
$this->page);
|
||||
}
|
||||
|
327
actions/showapplication.php
Normal file
327
actions/showapplication.php
Normal file
@ -0,0 +1,327 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show an OAuth application
|
||||
*
|
||||
* 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 Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an OAuth application
|
||||
*
|
||||
* @category Application
|
||||
* @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 ShowApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
/**
|
||||
* Application to show
|
||||
*/
|
||||
|
||||
var $application = null;
|
||||
|
||||
/**
|
||||
* User who owns the app
|
||||
*/
|
||||
|
||||
var $owner = null;
|
||||
|
||||
var $msg = null;
|
||||
|
||||
var $success = null;
|
||||
|
||||
/**
|
||||
* Load attributes based on database arguments
|
||||
*
|
||||
* Loads all the DB stuff
|
||||
*
|
||||
* @param array $args $_REQUEST array
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = (int)$this->arg('id');
|
||||
|
||||
$this->application = Oauth_application::staticGet($id);
|
||||
$this->owner = User::staticGet($this->application->owner);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to view an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->application)) {
|
||||
$this->clientError(_('No such application.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur->id != $this->owner->id) {
|
||||
$this->clientError(_('You are not the owner of this application.'), 401);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Shows info about the app
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->arg('reset')) {
|
||||
$this->resetKey();
|
||||
}
|
||||
} else {
|
||||
$this->showPage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->application->name)) {
|
||||
return 'Application: ' . $this->application->name;
|
||||
}
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if (!empty($this->msg)) {
|
||||
$this->element('div', ($this->success) ? 'success' : 'error', $this->msg);
|
||||
}
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
$consumer = $this->application->getConsumer();
|
||||
|
||||
$this->elementStart('div', 'entity_profile vcard');
|
||||
$this->element('h2', null, _('Application profile'));
|
||||
$this->elementStart('dl', 'entity_depiction');
|
||||
$this->element('dt', null, _('Icon'));
|
||||
$this->elementStart('dd');
|
||||
if (!empty($this->application->icon)) {
|
||||
$this->element('img', array('src' => $this->application->icon,
|
||||
'class' => 'photo logo'));
|
||||
}
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_fn');
|
||||
$this->element('dt', null, _('Name'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $this->application->source_url,
|
||||
'class' => 'url fn'),
|
||||
$this->application->name);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_org');
|
||||
$this->element('dt', null, _('Organization'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $this->application->homepage,
|
||||
'class' => 'url'),
|
||||
$this->application->organization);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_note');
|
||||
$this->element('dt', null, _('Description'));
|
||||
$this->element('dd', 'note', $this->application->description);
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_statistics');
|
||||
$this->element('dt', null, _('Statistics'));
|
||||
$this->elementStart('dd');
|
||||
$defaultAccess = ($this->application->access_type & Oauth_application::$writeAccess)
|
||||
? 'read-write' : 'read-only';
|
||||
$profile = Profile::staticGet($this->application->owner);
|
||||
|
||||
$appUsers = new Oauth_application_user();
|
||||
$appUsers->application_id = $this->application->id;
|
||||
$userCnt = $appUsers->count();
|
||||
|
||||
$this->raw(sprintf(
|
||||
_('created by %1$s - %2$s access by default - %3$d users'),
|
||||
$profile->getBestName(),
|
||||
$defaultAccess,
|
||||
$userCnt
|
||||
));
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_actions');
|
||||
$this->element('h2', null, _('Application actions'));
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', 'entity_edit');
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('editapplication',
|
||||
array('id' => $this->application->id))),
|
||||
'Edit');
|
||||
$this->elementEnd('li');
|
||||
|
||||
$this->elementStart('li', 'entity_reset_keysecret');
|
||||
$this->elementStart('form', array(
|
||||
'id' => 'forma_reset_key',
|
||||
'class' => 'form_reset_key',
|
||||
'method' => 'POST',
|
||||
'action' => common_local_url('showapplication',
|
||||
array('id' => $this->application->id))));
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->submit('reset', _('Reset key & secret'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_data');
|
||||
$this->element('h2', null, _('Application info'));
|
||||
$this->elementStart('dl', 'entity_consumer_key');
|
||||
$this->element('dt', null, _('Consumer key'));
|
||||
$this->element('dd', null, $consumer->consumer_key);
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_consumer_secret');
|
||||
$this->element('dt', null, _('Consumer secret'));
|
||||
$this->element('dd', null, $consumer->consumer_secret);
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_request_token_url');
|
||||
$this->element('dt', null, _('Request token URL'));
|
||||
$this->element('dd', null, common_local_url('apioauthrequesttoken'));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_access_token_url');
|
||||
$this->element('dt', null, _('Access token URL'));
|
||||
$this->element('dd', null, common_local_url('apioauthaccesstoken'));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_authorize_url');
|
||||
$this->element('dt', null, _('Authorize URL'));
|
||||
$this->element('dd', null, common_local_url('apioauthauthorize'));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->element('p', 'note',
|
||||
_('Note: We support HMAC-SHA1 signatures. We do not support the plaintext signature method.'));
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('p', array('id' => 'application_action'));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('oauthappssettings'),
|
||||
'class' => 'more'),
|
||||
'View your applications');
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
function resetKey()
|
||||
{
|
||||
$this->application->query('BEGIN');
|
||||
|
||||
$consumer = $this->application->getConsumer();
|
||||
$result = $consumer->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'DELETE', __FILE__);
|
||||
$this->success = false;
|
||||
$this->msg = ('Unable to reset consumer key and secret.');
|
||||
$this->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$consumer = Consumer::generateNew();
|
||||
|
||||
$result = $consumer->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'INSERT', __FILE__);
|
||||
$this->application->query('ROLLBACK');
|
||||
$this->success = false;
|
||||
$this->msg = ('Unable to reset consumer key and secret.');
|
||||
$this->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$orig = clone($this->application);
|
||||
$this->application->consumer_key = $consumer->consumer_key;
|
||||
$result = $this->application->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($application, 'UPDATE', __FILE__);
|
||||
$this->application->query('ROLLBACK');
|
||||
$this->success = false;
|
||||
$this->msg = ('Unable to reset consumer key and secret.');
|
||||
$this->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->application->query('COMMIT');
|
||||
|
||||
$this->success = true;
|
||||
$this->msg = ('Consumer key and secret reset.');
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
}
|
@ -74,9 +74,9 @@ class ShowfavoritesAction extends OwnerDesignAction
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("%s's favorite notices"), $this->user->nickname);
|
||||
return sprintf(_('%s\'s favorite notices'), $this->user->nickname);
|
||||
} else {
|
||||
return sprintf(_("%1$s's favorite notices, page %2$d"),
|
||||
return sprintf(_('%1$s\'s favorite notices, page %2$d'),
|
||||
$this->user->nickname,
|
||||
$this->page);
|
||||
}
|
||||
|
@ -79,9 +79,9 @@ class ShowgroupAction extends GroupDesignAction
|
||||
}
|
||||
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("%s group"), $base);
|
||||
return sprintf(_('%s group'), $base);
|
||||
} else {
|
||||
return sprintf(_("%1$s group, page %2$d"),
|
||||
return sprintf(_('%1$s group, page %2$d'),
|
||||
$base,
|
||||
$this->page);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class ShowstreamAction extends ProfileAction
|
||||
if ($this->page == 1) {
|
||||
return $base;
|
||||
} else {
|
||||
return sprintf(_("%1$s, page %2$d"),
|
||||
return sprintf(_('%1$s, page %2$d'),
|
||||
$base,
|
||||
$this->page);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -95,8 +95,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
'site', 'textlimit', 'dupelimit'),
|
||||
'snapshot' => array('run', 'reporturl', 'frequency'));
|
||||
|
||||
static $booleans = array('site' => array('private', 'inviteonly', 'closed', 'fancy'));
|
||||
|
||||
$values = array();
|
||||
|
||||
foreach ($settings as $section => $parts) {
|
||||
@ -105,12 +103,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
$values[$section][$setting] = ($this->boolean($setting)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This throws an exception on validation errors
|
||||
|
||||
$this->validate($values);
|
||||
@ -127,12 +119,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
Config::save($section, $setting, $values[$section][$setting]);
|
||||
}
|
||||
}
|
||||
|
||||
$config->query('COMMIT');
|
||||
|
||||
return;
|
||||
@ -299,44 +285,6 @@ class SiteAdminPanelForm extends AdminForm
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_urls'));
|
||||
$this->out->element('legend', null, _('URLs'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$this->input('server', _('Server'), _('Site\'s server hostname.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->checkbox('fancy', _('Fancy URLs'),
|
||||
(bool) $this->value('fancy'),
|
||||
_('Use fancy (more readable and memorable) URLs?'));
|
||||
$this->unli();
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_access'));
|
||||
$this->out->element('legend', null, _('Access'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$this->out->checkbox('private', _('Private'),
|
||||
(bool) $this->value('private'),
|
||||
_('Prohibit anonymous users (not logged in) from viewing site?'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->checkbox('inviteonly', _('Invite only'),
|
||||
(bool) $this->value('inviteonly'),
|
||||
_('Make registration invitation only.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->checkbox('closed', _('Closed'),
|
||||
(bool) $this->value('closed'),
|
||||
_('Disable new registrations.'));
|
||||
$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');
|
||||
|
@ -63,9 +63,9 @@ class TagAction extends Action
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("Notices tagged with %s"), $this->tag);
|
||||
return sprintf(_('Notices tagged with %s'), $this->tag);
|
||||
} else {
|
||||
return sprintf(_("Notices tagged with %1$s, page %2$d"),
|
||||
return sprintf(_('Notices tagged with %1$s, page %2$d'),
|
||||
$this->tag,
|
||||
$this->page);
|
||||
}
|
||||
|
@ -59,9 +59,9 @@ class UsergroupsAction extends OwnerDesignAction
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("%s groups"), $this->user->nickname);
|
||||
return sprintf(_('%s groups'), $this->user->nickname);
|
||||
} else {
|
||||
return sprintf(_("%1$s groups, page %2$d"),
|
||||
return sprintf(_('%1$s groups, page %2$d'),
|
||||
$this->user->nickname,
|
||||
$this->page);
|
||||
}
|
||||
|
@ -11,9 +11,10 @@ class Consumer extends Memcached_DataObject
|
||||
|
||||
public $__table = 'consumer'; // table name
|
||||
public $consumer_key; // varchar(255) primary_key not_null
|
||||
public $consumer_secret; // varchar(255) not_null
|
||||
public $seed; // char(32) not_null
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
@ -21,4 +22,18 @@ class Consumer extends Memcached_DataObject
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function generateNew()
|
||||
{
|
||||
$cons = new Consumer();
|
||||
$rand = common_good_rand(16);
|
||||
|
||||
$cons->seed = $rand;
|
||||
$cons->consumer_key = md5(time() + $rand);
|
||||
$cons->consumer_secret = md5(md5(time() + time() + $rand));
|
||||
$cons->created = common_sql_now();
|
||||
|
||||
return $cons;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ class Memcached_DataObject extends DB_DataObject
|
||||
// Clear this out so we don't accidentally break global
|
||||
// state in *this* process.
|
||||
$this->_DB_resultid = null;
|
||||
|
||||
// We don't have any local DBO refs, so clear these out.
|
||||
$this->_link_loaded = false;
|
||||
}
|
||||
@ -91,9 +90,7 @@ class Memcached_DataObject extends DB_DataObject
|
||||
unset($i);
|
||||
}
|
||||
$i = Memcached_DataObject::getcached($cls, $k, $v);
|
||||
if ($i) {
|
||||
return $i;
|
||||
} else {
|
||||
if ($i === false) { // false == cache miss
|
||||
$i = DB_DataObject::factory($cls);
|
||||
if (empty($i)) {
|
||||
$i = false;
|
||||
@ -101,22 +98,34 @@ class Memcached_DataObject extends DB_DataObject
|
||||
}
|
||||
$result = $i->get($k, $v);
|
||||
if ($result) {
|
||||
// Hit!
|
||||
$i->encache();
|
||||
return $i;
|
||||
} else {
|
||||
// save the fact that no such row exists
|
||||
$c = self::memcache();
|
||||
if (!empty($c)) {
|
||||
$ck = self::cachekey($cls, $k, $v);
|
||||
$c->set($ck, null);
|
||||
}
|
||||
$i = false;
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return $i;
|
||||
}
|
||||
|
||||
function &pkeyGet($cls, $kv)
|
||||
/**
|
||||
* @fixme Should this return false on lookup fail to match staticGet?
|
||||
*/
|
||||
function pkeyGet($cls, $kv)
|
||||
{
|
||||
$i = Memcached_DataObject::multicache($cls, $kv);
|
||||
if ($i) {
|
||||
if ($i !== false) { // false == cache miss
|
||||
return $i;
|
||||
} else {
|
||||
$i = new $cls();
|
||||
$i = DB_DataObject::factory($cls);
|
||||
if (empty($i)) {
|
||||
return false;
|
||||
}
|
||||
foreach ($kv as $k => $v) {
|
||||
$i->$k = $v;
|
||||
}
|
||||
@ -124,6 +133,11 @@ class Memcached_DataObject extends DB_DataObject
|
||||
$i->encache();
|
||||
} else {
|
||||
$i = null;
|
||||
$c = self::memcache();
|
||||
if (!empty($c)) {
|
||||
$ck = self::multicacheKey($cls, $kv);
|
||||
$c->set($ck, null);
|
||||
}
|
||||
}
|
||||
return $i;
|
||||
}
|
||||
@ -132,6 +146,9 @@ class Memcached_DataObject extends DB_DataObject
|
||||
function insert()
|
||||
{
|
||||
$result = parent::insert();
|
||||
if ($result) {
|
||||
$this->encache(); // in case of cached negative lookups
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -186,6 +203,17 @@ class Memcached_DataObject extends DB_DataObject
|
||||
|
||||
function keyTypes()
|
||||
{
|
||||
// ini-based classes return number-indexed arrays. handbuilt
|
||||
// classes return column => keytype. Make this uniform.
|
||||
|
||||
$keys = $this->keys();
|
||||
|
||||
$keyskeys = array_keys($keys);
|
||||
|
||||
if (is_string($keyskeys[0])) {
|
||||
return $keys;
|
||||
}
|
||||
|
||||
global $_DB_DATAOBJECT;
|
||||
if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
|
||||
$this->databaseStructure();
|
||||
@ -197,6 +225,7 @@ class Memcached_DataObject extends DB_DataObject
|
||||
function encache()
|
||||
{
|
||||
$c = $this->memcache();
|
||||
|
||||
if (!$c) {
|
||||
return false;
|
||||
} else if ($this->tableName() == 'user' && is_object($this->id)) {
|
||||
@ -206,64 +235,86 @@ class Memcached_DataObject extends DB_DataObject
|
||||
str_replace("\n", " ", $e->getTraceAsString()));
|
||||
return false;
|
||||
} else {
|
||||
$pkey = array();
|
||||
$pval = array();
|
||||
$types = $this->keyTypes();
|
||||
ksort($types);
|
||||
foreach ($types as $key => $type) {
|
||||
if ($type == 'K') {
|
||||
$pkey[] = $key;
|
||||
$pval[] = $this->$key;
|
||||
} else {
|
||||
$c->set($this->cacheKey($this->tableName(), $key, $this->$key), $this);
|
||||
}
|
||||
}
|
||||
# XXX: should work for both compound and scalar pkeys
|
||||
$pvals = implode(',', $pval);
|
||||
$pkeys = implode(',', $pkey);
|
||||
$c->set($this->cacheKey($this->tableName(), $pkeys, $pvals), $this);
|
||||
$keys = $this->_allCacheKeys();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$c->set($key, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decache()
|
||||
{
|
||||
$c = $this->memcache();
|
||||
|
||||
if (!$c) {
|
||||
return false;
|
||||
} else {
|
||||
$pkey = array();
|
||||
$pval = array();
|
||||
$types = $this->keyTypes();
|
||||
ksort($types);
|
||||
foreach ($types as $key => $type) {
|
||||
if ($type == 'K') {
|
||||
$pkey[] = $key;
|
||||
$pval[] = $this->$key;
|
||||
} else {
|
||||
$c->delete($this->cacheKey($this->tableName(), $key, $this->$key));
|
||||
}
|
||||
}
|
||||
# should work for both compound and scalar pkeys
|
||||
# XXX: comma works for now but may not be safe separator for future keys
|
||||
$pvals = implode(',', $pval);
|
||||
$pkeys = implode(',', $pkey);
|
||||
$c->delete($this->cacheKey($this->tableName(), $pkeys, $pvals));
|
||||
}
|
||||
|
||||
$keys = $this->_allCacheKeys();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$c->delete($key, $this);
|
||||
}
|
||||
}
|
||||
|
||||
function _allCacheKeys()
|
||||
{
|
||||
$ckeys = array();
|
||||
|
||||
$types = $this->keyTypes();
|
||||
ksort($types);
|
||||
|
||||
$pkey = array();
|
||||
$pval = array();
|
||||
|
||||
foreach ($types as $key => $type) {
|
||||
|
||||
assert(!empty($key));
|
||||
|
||||
if ($type == 'U') {
|
||||
if (empty($this->$key)) {
|
||||
continue;
|
||||
}
|
||||
$ckeys[] = $this->cacheKey($this->tableName(), $key, $this->$key);
|
||||
} else if ($type == 'K' || $type == 'N') {
|
||||
$pkey[] = $key;
|
||||
$pval[] = $this->$key;
|
||||
} else {
|
||||
throw new Exception("Unknown key type $key => $type for " . $this->tableName());
|
||||
}
|
||||
}
|
||||
|
||||
assert(count($pkey) > 0);
|
||||
|
||||
// XXX: should work for both compound and scalar pkeys
|
||||
$pvals = implode(',', $pval);
|
||||
$pkeys = implode(',', $pkey);
|
||||
|
||||
$ckeys[] = $this->cacheKey($this->tableName(), $pkeys, $pvals);
|
||||
|
||||
return $ckeys;
|
||||
}
|
||||
|
||||
function multicache($cls, $kv)
|
||||
{
|
||||
ksort($kv);
|
||||
$c = Memcached_DataObject::memcache();
|
||||
$c = self::memcache();
|
||||
if (!$c) {
|
||||
return false;
|
||||
} else {
|
||||
$pkeys = implode(',', array_keys($kv));
|
||||
$pvals = implode(',', array_values($kv));
|
||||
return $c->get(Memcached_DataObject::cacheKey($cls, $pkeys, $pvals));
|
||||
return $c->get(self::multicacheKey($cls, $kv));
|
||||
}
|
||||
}
|
||||
|
||||
static function multicacheKey($cls, $kv)
|
||||
{
|
||||
ksort($kv);
|
||||
$pkeys = implode(',', array_keys($kv));
|
||||
$pvals = implode(',', array_values($kv));
|
||||
return self::cacheKey($cls, $pkeys, $pvals);
|
||||
}
|
||||
|
||||
function getSearchEngine($table)
|
||||
{
|
||||
require_once INSTALLDIR.'/lib/search_engines.php';
|
||||
@ -298,7 +349,8 @@ class Memcached_DataObject extends DB_DataObject
|
||||
$key_part = common_keyize($cls).':'.md5($qry);
|
||||
$ckey = common_cache_key($key_part);
|
||||
$stored = $c->get($ckey);
|
||||
if ($stored) {
|
||||
|
||||
if ($stored !== false) {
|
||||
return new ArrayWrapper($stored);
|
||||
}
|
||||
|
||||
@ -313,6 +365,39 @@ class Memcached_DataObject extends DB_DataObject
|
||||
return new ArrayWrapper($cached);
|
||||
}
|
||||
|
||||
/**
|
||||
* sends query to database - this is the private one that must work
|
||||
* - internal functions use this rather than $this->query()
|
||||
*
|
||||
* Overridden to do logging.
|
||||
*
|
||||
* @param string $string
|
||||
* @access private
|
||||
* @return mixed none or PEAR_Error
|
||||
*/
|
||||
function _query($string)
|
||||
{
|
||||
$start = microtime(true);
|
||||
$result = parent::_query($string);
|
||||
$delta = microtime(true) - $start;
|
||||
|
||||
$limit = common_config('db', 'log_slow_queries');
|
||||
if (($limit > 0 && $delta >= $limit) || common_config('db', 'log_queries')) {
|
||||
$clean = $this->sanitizeQuery($string);
|
||||
common_log(LOG_DEBUG, sprintf("DB query (%0.3fs): %s", $delta, $clean));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Sanitize a query for logging
|
||||
// @fixme don't trim spaces in string literals
|
||||
function sanitizeQuery($string)
|
||||
{
|
||||
$string = preg_replace('/\s+/', ' ', $string);
|
||||
$string = trim($string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
// We overload so that 'SET NAMES "utf8"' is called for
|
||||
// each connection
|
||||
|
||||
|
@ -326,9 +326,13 @@ class Notice extends Memcached_DataObject
|
||||
# XXX: someone clever could prepend instead of clearing the cache
|
||||
$notice->blowOnInsert();
|
||||
|
||||
$qm = QueueManager::get();
|
||||
|
||||
$qm->enqueue($notice, 'distrib');
|
||||
if (common_config('queue', 'inboxes')) {
|
||||
$qm = QueueManager::get();
|
||||
$qm->enqueue($notice, 'distrib');
|
||||
} else {
|
||||
$handler = new DistribQueueHandler();
|
||||
$handler->handle($notice);
|
||||
}
|
||||
|
||||
return $notice;
|
||||
}
|
||||
|
140
classes/Oauth_application.php
Normal file
140
classes/Oauth_application.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for oauth_application
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Oauth_application extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'oauth_application'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $owner; // int(4) not_null
|
||||
public $consumer_key; // varchar(255) not_null
|
||||
public $name; // varchar(255) not_null
|
||||
public $description; // varchar(255)
|
||||
public $icon; // varchar(255) not_null
|
||||
public $source_url; // varchar(255)
|
||||
public $organization; // varchar(255)
|
||||
public $homepage; // varchar(255)
|
||||
public $callback_url; // varchar(255) not_null
|
||||
public $type; // tinyint(1)
|
||||
public $access_type; // tinyint(1)
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) {
|
||||
return Memcached_DataObject::staticGet('Oauth_application',$k,$v);
|
||||
}
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
// Bit flags
|
||||
public static $readAccess = 1;
|
||||
public static $writeAccess = 2;
|
||||
|
||||
public static $browser = 1;
|
||||
public static $desktop = 2;
|
||||
|
||||
function getConsumer()
|
||||
{
|
||||
return Consumer::staticGet('consumer_key', $this->consumer_key);
|
||||
}
|
||||
|
||||
static function maxDesc()
|
||||
{
|
||||
$desclimit = common_config('application', 'desclimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($desclimit)) {
|
||||
$desclimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $desclimit;
|
||||
}
|
||||
|
||||
static function descriptionTooLong($desc)
|
||||
{
|
||||
$desclimit = self::maxDesc();
|
||||
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
|
||||
}
|
||||
|
||||
function setAccessFlags($read, $write)
|
||||
{
|
||||
if ($read) {
|
||||
$this->access_type |= self::$readAccess;
|
||||
} else {
|
||||
$this->access_type &= ~self::$readAccess;
|
||||
}
|
||||
|
||||
if ($write) {
|
||||
$this->access_type |= self::$writeAccess;
|
||||
} else {
|
||||
$this->access_type &= ~self::$writeAccess;
|
||||
}
|
||||
}
|
||||
|
||||
function setOriginal($filename)
|
||||
{
|
||||
$imagefile = new ImageFile($this->id, Avatar::path($filename));
|
||||
|
||||
// XXX: Do we want to have a bunch of different size icons? homepage, stream, mini?
|
||||
// or just one and control size via CSS? --Zach
|
||||
|
||||
$orig = clone($this);
|
||||
$this->icon = Avatar::url($filename);
|
||||
common_debug(common_log_objstring($this));
|
||||
return $this->update($orig);
|
||||
}
|
||||
|
||||
static function getByConsumerKey($key)
|
||||
{
|
||||
if (empty($key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$app = new Oauth_application();
|
||||
$app->consumer_key = $key;
|
||||
$app->limit(1);
|
||||
$result = $app->find(true);
|
||||
|
||||
return empty($result) ? null : $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an image upload
|
||||
*
|
||||
* Does all the magic for handling an image upload, and crops the
|
||||
* image by default.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function uploadLogo()
|
||||
{
|
||||
if ($_FILES['app_icon']['error'] ==
|
||||
UPLOAD_ERR_OK) {
|
||||
|
||||
try {
|
||||
$imagefile = ImageFile::fromUpload('app_icon');
|
||||
} catch (Exception $e) {
|
||||
common_debug("damn that sucks");
|
||||
$this->showForm($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$filename = Avatar::filename($this->id,
|
||||
image_type_to_extension($imagefile->type),
|
||||
null,
|
||||
'oauth-app-icon-'.common_timestamp());
|
||||
|
||||
$filepath = Avatar::path($filename);
|
||||
|
||||
move_uploaded_file($imagefile->filepath, $filepath);
|
||||
|
||||
$this->setOriginal($filename);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
44
classes/Oauth_application_user.php
Normal file
44
classes/Oauth_application_user.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for oauth_application_user
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Oauth_application_user extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'oauth_application_user'; // table name
|
||||
public $profile_id; // int(4) primary_key not_null
|
||||
public $application_id; // int(4) primary_key not_null
|
||||
public $access_type; // tinyint(1)
|
||||
public $token; // varchar(255)
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) {
|
||||
return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v);
|
||||
}
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function getByKeys($user, $app)
|
||||
{
|
||||
if (empty($user) || empty($app)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$oau = new Oauth_application_user();
|
||||
|
||||
$oau->profile_id = $user->id;
|
||||
$oau->application_id = $app->id;
|
||||
$oau->limit(1);
|
||||
|
||||
$result = $oau->find(true);
|
||||
|
||||
return empty($result) ? null : $oau;
|
||||
}
|
||||
|
||||
}
|
@ -352,6 +352,31 @@ class Profile extends Memcached_DataObject
|
||||
return $profile;
|
||||
}
|
||||
|
||||
function getApplications($offset = 0, $limit = null)
|
||||
{
|
||||
$qry =
|
||||
'SELECT a.* ' .
|
||||
'FROM oauth_application_user u, oauth_application a ' .
|
||||
'WHERE u.profile_id = %d ' .
|
||||
'AND a.id = u.application_id ' .
|
||||
'AND u.access_type > 0 ' .
|
||||
'ORDER BY u.created DESC ';
|
||||
|
||||
if ($offset > 0) {
|
||||
if (common_config('db','type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
}
|
||||
|
||||
$application = new Oauth_application();
|
||||
|
||||
$cnt = $application->query(sprintf($qry, $this->id));
|
||||
|
||||
return $application;
|
||||
}
|
||||
|
||||
function subscriptionCount()
|
||||
{
|
||||
$c = common_memcache();
|
||||
|
@ -39,9 +39,19 @@ class Status_network extends DB_DataObject
|
||||
public $logo; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $tags; // text
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Status_network',$k,$v); }
|
||||
function staticGet($k,$v=NULL) {
|
||||
$i = DB_DataObject::staticGet('Status_network',$k,$v);
|
||||
|
||||
// Don't use local process cache; if we're fetching multiple
|
||||
// times it's because we're reloading it in a long-running
|
||||
// process; we need a fresh copy!
|
||||
global $_DB_DATAOBJECT;
|
||||
unset($_DB_DATAOBJECT['CACHE']['status_network']);
|
||||
return $i;
|
||||
}
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
@ -245,4 +255,23 @@ class Status_network extends DB_DataObject
|
||||
return $this->nickname . '.' . self::$wildcard;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return site meta-info tags as an array
|
||||
* @return array of strings
|
||||
*/
|
||||
function getTags()
|
||||
{
|
||||
return array_filter(explode("|", strval($this->tags)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this site record has a particular meta-info tag attached.
|
||||
* @param string $tag
|
||||
* @return bool
|
||||
*/
|
||||
function hasTag($tag)
|
||||
{
|
||||
return in_array($tag, $this->getTags());
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ class Token extends Memcached_DataObject
|
||||
public $secret; // char(32) not_null
|
||||
public $type; // tinyint(1) not_null
|
||||
public $state; // tinyint(1)
|
||||
public $verifier; // varchar(255)
|
||||
public $verified_callback; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
|
@ -39,6 +39,7 @@ code = K
|
||||
|
||||
[consumer]
|
||||
consumer_key = 130
|
||||
consumer_secret = 130
|
||||
seed = 130
|
||||
created = 142
|
||||
modified = 384
|
||||
@ -348,6 +349,37 @@ created = 142
|
||||
tag = K
|
||||
notice_id = K
|
||||
|
||||
[oauth_application]
|
||||
id = 129
|
||||
owner = 129
|
||||
consumer_key = 130
|
||||
name = 130
|
||||
description = 2
|
||||
icon = 130
|
||||
source_url = 2
|
||||
organization = 2
|
||||
homepage = 2
|
||||
callback_url = 130
|
||||
type = 17
|
||||
access_type = 17
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[oauth_application__keys]
|
||||
id = N
|
||||
|
||||
[oauth_application_user]
|
||||
profile_id = 129
|
||||
application_id = 129
|
||||
access_type = 17
|
||||
token = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[oauth_application_user__keys]
|
||||
profile_id = K
|
||||
application_id = K
|
||||
|
||||
[profile]
|
||||
id = 129
|
||||
nickname = 130
|
||||
@ -484,6 +516,8 @@ tok = 130
|
||||
secret = 130
|
||||
type = 145
|
||||
state = 17
|
||||
verifier = 2
|
||||
verified_callback = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
create table queue_item_new (
|
||||
id integer auto_increment primary key comment 'unique identifier',
|
||||
frame blob not null comment 'data: object reference or opaque string',
|
||||
transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
|
||||
created datetime not null comment 'date this record was created',
|
||||
claimed datetime comment 'date this item was claimed',
|
||||
|
||||
index queue_item_created_idx (created)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
insert into queue_item_new (frame,transport,created,claimed)
|
||||
select notice_id,transport,created,claimed from queue_item;
|
||||
alter table queue_item rename to queue_item_old;
|
||||
alter table queue_item_new rename to queue_item;
|
||||
|
50
db/rc3torc4.sql
Normal file
50
db/rc3torc4.sql
Normal file
@ -0,0 +1,50 @@
|
||||
create table queue_item_new (
|
||||
id integer auto_increment primary key comment 'unique identifier',
|
||||
frame blob not null comment 'data: object reference or opaque string',
|
||||
transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
|
||||
created datetime not null comment 'date this record was created',
|
||||
claimed datetime comment 'date this item was claimed',
|
||||
|
||||
index queue_item_created_idx (created)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
insert into queue_item_new (frame,transport,created,claimed)
|
||||
select notice_id,transport,created,claimed from queue_item;
|
||||
alter table queue_item rename to queue_item_old;
|
||||
alter table queue_item_new rename to queue_item;
|
||||
|
||||
alter table consumer
|
||||
add consumer_secret varchar(255) not null comment 'secret value';
|
||||
|
||||
alter table token
|
||||
add verifier varchar(255) comment 'verifier string for OAuth 1.0a',
|
||||
add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a';
|
||||
|
||||
create table oauth_application (
|
||||
id integer auto_increment primary key comment 'unique identifier',
|
||||
owner integer not null comment 'owner of the application' references profile (id),
|
||||
consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key),
|
||||
name varchar(255) not null comment 'name of the application',
|
||||
description varchar(255) comment 'description of the application',
|
||||
icon varchar(255) not null comment 'application icon',
|
||||
source_url varchar(255) comment 'application homepage - used for source link',
|
||||
organization varchar(255) comment 'name of the organization running the application',
|
||||
homepage varchar(255) comment 'homepage for the organization',
|
||||
callback_url varchar(255) comment 'url to redirect to after authentication',
|
||||
type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop',
|
||||
access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified'
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table oauth_application_user (
|
||||
profile_id integer not null comment 'user of the application' references profile (id),
|
||||
application_id integer not null comment 'id of the application' references oauth_application (id),
|
||||
access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked',
|
||||
token varchar(255) comment 'request or access token',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
constraint primary key (profile_id, application_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
@ -15,6 +15,8 @@ create table status_network (
|
||||
theme varchar(255) comment 'theme name',
|
||||
logo varchar(255) comment 'site logo',
|
||||
|
||||
tags text comment 'site meta-info tags (pipe-separated)',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified'
|
||||
|
||||
|
@ -176,6 +176,7 @@ create table fave (
|
||||
|
||||
create table consumer (
|
||||
consumer_key varchar(255) primary key comment 'unique identifier, root URL',
|
||||
consumer_secret varchar(255) not null comment 'secret value',
|
||||
seed char(32) not null comment 'seed for new tokens by this consumer',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
@ -188,6 +189,8 @@ create table token (
|
||||
secret char(32) not null comment 'secret value',
|
||||
type tinyint not null default 0 comment 'request or access',
|
||||
state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
|
||||
verifier varchar(255) comment 'verifier string for OAuth 1.0a',
|
||||
verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
@ -207,6 +210,33 @@ create table nonce (
|
||||
constraint primary key (consumer_key, ts, nonce)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table oauth_application (
|
||||
id integer auto_increment primary key comment 'unique identifier',
|
||||
owner integer not null comment 'owner of the application' references profile (id),
|
||||
consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key),
|
||||
name varchar(255) not null comment 'name of the application',
|
||||
description varchar(255) comment 'description of the application',
|
||||
icon varchar(255) not null comment 'application icon',
|
||||
source_url varchar(255) comment 'application homepage - used for source link',
|
||||
organization varchar(255) comment 'name of the organization running the application',
|
||||
homepage varchar(255) comment 'homepage for the organization',
|
||||
callback_url varchar(255) comment 'url to redirect to after authentication',
|
||||
type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop',
|
||||
access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified'
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table oauth_application_user (
|
||||
profile_id integer not null comment 'user of the application' references profile (id),
|
||||
application_id integer not null comment 'id of the application' references oauth_application (id),
|
||||
access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked',
|
||||
token varchar(255) comment 'request or access token',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
constraint primary key (profile_id, application_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
/* These are used by JanRain OpenID library */
|
||||
|
||||
create table oid_associations (
|
||||
|
133
js/geometa.js
133
js/geometa.js
@ -1,5 +1,5 @@
|
||||
// A shim to implement the W3C Geolocation API Specification using Gears
|
||||
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) (function(){
|
||||
// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API
|
||||
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){
|
||||
|
||||
// -- BEGIN GEARS_INIT
|
||||
(function() {
|
||||
@ -23,8 +23,7 @@ if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim )
|
||||
}
|
||||
} catch (e) {
|
||||
// Safari
|
||||
if ((typeof navigator.mimeTypes != 'undefined')
|
||||
&& navigator.mimeTypes["application/x-googlegears"]) {
|
||||
if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
|
||||
factory = document.createElement("object");
|
||||
factory.style.display = "none";
|
||||
factory.width = 0;
|
||||
@ -64,8 +63,8 @@ var GearsGeoLocation = (function() {
|
||||
return function(position) {
|
||||
callback(position);
|
||||
self.lastPosition = position;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// -- PUBLIC
|
||||
return {
|
||||
@ -96,9 +95,123 @@ var GearsGeoLocation = (function() {
|
||||
};
|
||||
});
|
||||
|
||||
// If you have Gears installed use that
|
||||
if (window.google && google.gears) {
|
||||
navigator.geolocation = GearsGeoLocation();
|
||||
}
|
||||
var AjaxGeoLocation = (function() {
|
||||
// -- PRIVATE
|
||||
var loading = false;
|
||||
var loadGoogleLoader = function() {
|
||||
if (!hasGoogleLoader() && !loading) {
|
||||
loading = true;
|
||||
var s = document.createElement('script');
|
||||
s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded';
|
||||
s.type = "text/javascript";
|
||||
document.getElementsByTagName('body')[0].appendChild(s);
|
||||
}
|
||||
};
|
||||
|
||||
var queue = [];
|
||||
var addLocationQueue = function(callback) {
|
||||
queue.push(callback);
|
||||
};
|
||||
|
||||
var runLocationQueue = function() {
|
||||
if (hasGoogleLoader()) {
|
||||
while (queue.length > 0) {
|
||||
var call = queue.pop();
|
||||
call();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window['_google_loader_apiLoaded'] = function() {
|
||||
runLocationQueue();
|
||||
};
|
||||
|
||||
var hasGoogleLoader = function() {
|
||||
return (window['google'] && google['loader']);
|
||||
};
|
||||
|
||||
var checkGoogleLoader = function(callback) {
|
||||
if (hasGoogleLoader()) { return true; }
|
||||
|
||||
addLocationQueue(callback);
|
||||
|
||||
loadGoogleLoader();
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
loadGoogleLoader(); // start to load as soon as possible just in case
|
||||
|
||||
// -- PUBLIC
|
||||
return {
|
||||
shim: true,
|
||||
|
||||
type: "ClientLocation",
|
||||
|
||||
lastPosition: null,
|
||||
|
||||
getCurrentPosition: function(successCallback, errorCallback, options) {
|
||||
var self = this;
|
||||
if (!checkGoogleLoader(function() {
|
||||
self.getCurrentPosition(successCallback, errorCallback, options);
|
||||
})) { return; }
|
||||
|
||||
if (google.loader.ClientLocation) {
|
||||
var cl = google.loader.ClientLocation;
|
||||
|
||||
var position = {
|
||||
coords: {
|
||||
latitude: cl.latitude,
|
||||
longitude: cl.longitude,
|
||||
altitude: null,
|
||||
accuracy: 43000, // same as Gears accuracy over wifi?
|
||||
altitudeAccuracy: null,
|
||||
heading: null,
|
||||
speed: null
|
||||
},
|
||||
// extra info that is outside of the bounds of the core API
|
||||
address: {
|
||||
city: cl.address.city,
|
||||
country: cl.address.country,
|
||||
country_code: cl.address.country_code,
|
||||
region: cl.address.region
|
||||
},
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
successCallback(position);
|
||||
|
||||
this.lastPosition = position;
|
||||
} else if (errorCallback === "function") {
|
||||
errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."});
|
||||
}
|
||||
},
|
||||
|
||||
watchPosition: function(successCallback, errorCallback, options) {
|
||||
this.getCurrentPosition(successCallback, errorCallback, options);
|
||||
|
||||
var self = this;
|
||||
var watchId = setInterval(function() {
|
||||
self.getCurrentPosition(successCallback, errorCallback, options);
|
||||
}, 10000);
|
||||
|
||||
return watchId;
|
||||
},
|
||||
|
||||
clearWatch: function(watchId) {
|
||||
clearInterval(watchId);
|
||||
},
|
||||
|
||||
getPermission: function(siteName, imageUrl, extraMessage) {
|
||||
// for now just say yes :)
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
// If you have Gears installed use that, else use Ajax ClientLocation
|
||||
navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation();
|
||||
|
||||
})();
|
||||
}
|
||||
|
@ -246,18 +246,18 @@ class Action extends HTMLOutputter // lawsuit
|
||||
{
|
||||
if (Event::handle('StartShowScripts', array($this))) {
|
||||
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
||||
$this->script('js/jquery.min.js');
|
||||
$this->script('js/jquery.form.js');
|
||||
$this->script('js/jquery.cookie.js');
|
||||
$this->script('js/json2.js');
|
||||
$this->script('js/jquery.joverlay.min.js');
|
||||
$this->script('jquery.min.js');
|
||||
$this->script('jquery.form.js');
|
||||
$this->script('jquery.cookie.js');
|
||||
$this->script('json2.js');
|
||||
$this->script('jquery.joverlay.min.js');
|
||||
Event::handle('EndShowJQueryScripts', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
||||
Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||
$this->script('js/xbImportNode.js');
|
||||
$this->script('js/util.js');
|
||||
$this->script('js/geometa.js');
|
||||
$this->script('xbImportNode.js');
|
||||
$this->script('util.js');
|
||||
$this->script('geometa.js');
|
||||
// Frame-busting code to avoid clickjacking attacks.
|
||||
$this->element('script', array('type' => 'text/javascript'),
|
||||
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||
@ -369,7 +369,11 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->elementStart('div', array('id' => 'header'));
|
||||
$this->showLogo();
|
||||
$this->showPrimaryNav();
|
||||
$this->showSiteNotice();
|
||||
if (Event::handle('StartShowSiteNotice', array($this))) {
|
||||
$this->showSiteNotice();
|
||||
|
||||
Event::handle('EndShowSiteNotice', array($this));
|
||||
}
|
||||
if (common_logged_in()) {
|
||||
$this->showNoticeForm();
|
||||
} else {
|
||||
@ -388,8 +392,14 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->elementStart('address', array('id' => 'site_contact',
|
||||
'class' => 'vcard'));
|
||||
if (Event::handle('StartAddressData', array($this))) {
|
||||
if (common_config('singleuser', 'enabled')) {
|
||||
$url = common_local_url('showstream',
|
||||
array('nickname' => common_config('singleuser', 'nickname')));
|
||||
} else {
|
||||
$url = common_local_url('public');
|
||||
}
|
||||
$this->elementStart('a', array('class' => 'url home bookmark',
|
||||
'href' => common_local_url('public')));
|
||||
'href' => $url));
|
||||
if (common_config('site', 'logo') || file_exists(Theme::file('logo.png'))) {
|
||||
$this->element('img', array('class' => 'logo photo',
|
||||
'src' => (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'),
|
||||
|
@ -319,12 +319,17 @@ class AdminPanelNav extends Widget
|
||||
|
||||
if ($this->canAdmin('user')) {
|
||||
$this->out->menuItem(common_local_url('useradminpanel'), _('User'),
|
||||
_('Paths configuration'), $action_name == 'useradminpanel', 'nav_design_admin_panel');
|
||||
_('User configuration'), $action_name == 'useradminpanel', 'nav_design_admin_panel');
|
||||
}
|
||||
|
||||
if ($this->canAdmin('paths')) {
|
||||
$this->out->menuItem(common_local_url('pathsadminpanel'), _('Paths'),
|
||||
_('Paths configuration'), $action_name == 'pathsadminpanel', 'nav_design_admin_panel');
|
||||
if ($this->canAdmin('access')) {
|
||||
$this->out->menuItem(common_local_url('accessadminpanel'), _('Access'),
|
||||
_('Access configuration'), $action_name == 'accessadminpanel', 'nav_design_admin_panel');
|
||||
}
|
||||
|
||||
if ($this->canAdmin('paths')) {
|
||||
$this->out->menuItem(common_local_url('pathsadminpanel'), _('Paths'),
|
||||
_('Paths configuration'), $action_name == 'pathsadminpanel', 'nav_design_admin_panel');
|
||||
}
|
||||
|
||||
Event::handle('EndAdminPanelNav', array($this));
|
||||
|
@ -53,6 +53,9 @@ if (!defined('STATUSNET')) {
|
||||
|
||||
class ApiAction extends Action
|
||||
{
|
||||
const READ_ONLY = 1;
|
||||
const READ_WRITE = 2;
|
||||
|
||||
var $format = null;
|
||||
var $user = null;
|
||||
var $auth_user = null;
|
||||
@ -62,6 +65,8 @@ class ApiAction extends Action
|
||||
var $since_id = null;
|
||||
var $since = null;
|
||||
|
||||
var $access = self::READ_ONLY; // read (default) or read-write
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
|
194
lib/apiauth.php
194
lib/apiauth.php
@ -29,7 +29,7 @@
|
||||
* @author mEDI <medi@milaro.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @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/
|
||||
*/
|
||||
@ -39,6 +39,7 @@ if (!defined('STATUSNET')) {
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/api.php';
|
||||
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Actions extending this class will require auth
|
||||
@ -52,6 +53,10 @@ require_once INSTALLDIR . '/lib/api.php';
|
||||
|
||||
class ApiAuthAction extends ApiAction
|
||||
{
|
||||
var $auth_user_nickname = null;
|
||||
var $auth_user_password = null;
|
||||
var $access_token = null;
|
||||
var $oauth_source = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running, and output basic auth header if needed
|
||||
@ -66,13 +71,130 @@ class ApiAuthAction extends ApiAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->consumer_key = $this->arg('oauth_consumer_key');
|
||||
$this->access_token = $this->arg('oauth_token');
|
||||
|
||||
// NOTE: $this->auth_user has to get set in prepare(), not handle(),
|
||||
// because subclasses do stuff with it in their prepares.
|
||||
|
||||
if ($this->requiresAuth()) {
|
||||
$this->checkBasicAuthUser();
|
||||
if (!empty($this->access_token)) {
|
||||
$this->checkOAuthRequest();
|
||||
} else {
|
||||
$this->checkBasicAuthUser(true);
|
||||
}
|
||||
} else {
|
||||
|
||||
// Check to see if a basic auth user is there even
|
||||
// if one's not required
|
||||
|
||||
if (empty($this->access_token)) {
|
||||
$this->checkBasicAuthUser(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Reject API calls with the wrong access level
|
||||
|
||||
if ($this->isReadOnly($args) == false) {
|
||||
if ($this->access != self::READ_WRITE) {
|
||||
$msg = _('API resource requires read-write access, ' .
|
||||
'but you only have read access.');
|
||||
$this->clientError($msg, 401, $this->format);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
}
|
||||
|
||||
function checkOAuthRequest()
|
||||
{
|
||||
$datastore = new ApiStatusNetOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
ApiOauthAction::cleanRequest();
|
||||
|
||||
try {
|
||||
|
||||
$req = OAuthRequest::from_request();
|
||||
$server->verify_request($req);
|
||||
|
||||
$app = Oauth_application::getByConsumerKey($this->consumer_key);
|
||||
|
||||
if (empty($app)) {
|
||||
|
||||
// this should probably not happen
|
||||
common_log(LOG_WARNING,
|
||||
'Couldn\'t find the OAuth app for consumer key: ' .
|
||||
$this->consumer_key);
|
||||
|
||||
throw new OAuthException('No application for that consumer key.');
|
||||
}
|
||||
|
||||
// set the source attr
|
||||
|
||||
$this->oauth_source = $app->name;
|
||||
|
||||
$appUser = Oauth_application_user::staticGet('token',
|
||||
$this->access_token);
|
||||
|
||||
// XXX: Check that app->id and appUser->application_id and consumer all
|
||||
// match?
|
||||
|
||||
if (!empty($appUser)) {
|
||||
|
||||
// If access_type == 0 we have either a request token
|
||||
// or a bad / revoked access token
|
||||
|
||||
if ($appUser->access_type != 0) {
|
||||
|
||||
// Set the access level for the api call
|
||||
|
||||
$this->access = ($appUser->access_type & Oauth_application::$writeAccess)
|
||||
? self::READ_WRITE : self::READ_ONLY;
|
||||
|
||||
if (Event::handle('StartSetApiUser', array(&$user))) {
|
||||
$this->auth_user = User::staticGet('id', $appUser->profile_id);
|
||||
Event::handle('EndSetApiUser', array($user));
|
||||
}
|
||||
|
||||
$msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " .
|
||||
"application '%s' (id: %d) with %s access.";
|
||||
|
||||
common_log(LOG_INFO, sprintf($msg,
|
||||
$this->auth_user->nickname,
|
||||
$this->auth_user->id,
|
||||
$app->name,
|
||||
$app->id,
|
||||
($this->access = self::READ_WRITE) ?
|
||||
'read-write' : 'read-only'
|
||||
));
|
||||
return;
|
||||
} else {
|
||||
throw new OAuthException('Bad access token.');
|
||||
}
|
||||
} else {
|
||||
|
||||
// Also should not happen
|
||||
|
||||
throw new OAuthException('No user for that token.');
|
||||
}
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
$this->showAuthError();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this API resource require authentication?
|
||||
*
|
||||
@ -91,44 +213,54 @@ class ApiAuthAction extends ApiAction
|
||||
* @return boolean true or false
|
||||
*/
|
||||
|
||||
function checkBasicAuthUser()
|
||||
function checkBasicAuthUser($required = true)
|
||||
{
|
||||
$this->basicAuthProcessHeader();
|
||||
|
||||
$realm = common_config('site', 'name') . ' API';
|
||||
|
||||
if (!isset($this->auth_user)) {
|
||||
if (!isset($this->auth_user_nickname) && $required) {
|
||||
header('WWW-Authenticate: Basic realm="' . $realm . '"');
|
||||
|
||||
// show error if the user clicks 'cancel'
|
||||
|
||||
$this->showBasicAuthError();
|
||||
$this->showAuthError();
|
||||
exit;
|
||||
|
||||
} else {
|
||||
$nickname = $this->auth_user;
|
||||
$password = $this->auth_pw;
|
||||
$user = common_check_user($nickname, $password);
|
||||
|
||||
$user = common_check_user($this->auth_user_nickname,
|
||||
$this->auth_user_password);
|
||||
|
||||
if (Event::handle('StartSetApiUser', array(&$user))) {
|
||||
$this->auth_user = $user;
|
||||
|
||||
if (!empty($user)) {
|
||||
$this->auth_user = $user;
|
||||
}
|
||||
|
||||
Event::handle('EndSetApiUser', array($user));
|
||||
}
|
||||
|
||||
if (empty($this->auth_user)) {
|
||||
// By default, basic auth users have rw access
|
||||
|
||||
$this->access = self::READ_WRITE;
|
||||
|
||||
if (empty($this->auth_user) && $required) {
|
||||
|
||||
// basic authentication failed
|
||||
|
||||
list($proxy, $ip) = common_client_ip();
|
||||
common_log(
|
||||
LOG_WARNING,
|
||||
'Failed API auth attempt, nickname = ' .
|
||||
"$nickname, proxy = $proxy, ip = $ip."
|
||||
);
|
||||
$this->showBasicAuthError();
|
||||
|
||||
$msg = sprintf(_('Failed API auth attempt, nickname = %1$s, ' .
|
||||
'proxy = %2$s, ip = %3$s'),
|
||||
$this->auth_user_nickname,
|
||||
$proxy,
|
||||
$ip);
|
||||
common_log(LOG_WARNING, $msg);
|
||||
$this->showAuthError();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,32 +274,30 @@ class ApiAuthAction extends ApiAction
|
||||
{
|
||||
if (isset($_SERVER['AUTHORIZATION'])
|
||||
|| isset($_SERVER['HTTP_AUTHORIZATION'])
|
||||
) {
|
||||
$authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])
|
||||
? $_SERVER['HTTP_AUTHORIZATION'] : $_SERVER['AUTHORIZATION'];
|
||||
) {
|
||||
$authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])
|
||||
? $_SERVER['HTTP_AUTHORIZATION'] : $_SERVER['AUTHORIZATION'];
|
||||
}
|
||||
|
||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$this->auth_user = $_SERVER['PHP_AUTH_USER'];
|
||||
$this->auth_pw = $_SERVER['PHP_AUTH_PW'];
|
||||
$this->auth_user_nickname = $_SERVER['PHP_AUTH_USER'];
|
||||
$this->auth_user_password = $_SERVER['PHP_AUTH_PW'];
|
||||
} elseif (isset($authorization_header)
|
||||
&& strstr(substr($authorization_header, 0, 5), 'Basic')) {
|
||||
|
||||
// decode the HTTP_AUTHORIZATION header on php-cgi server self
|
||||
// Decode the HTTP_AUTHORIZATION header on php-cgi server self
|
||||
// on fcgid server the header name is AUTHORIZATION
|
||||
|
||||
$auth_hash = base64_decode(substr($authorization_header, 6));
|
||||
list($this->auth_user, $this->auth_pw) = explode(':', $auth_hash);
|
||||
list($this->auth_user_nickname,
|
||||
$this->auth_user_password) = explode(':', $auth_hash);
|
||||
|
||||
// set all to null on a empty basic auth request
|
||||
// Set all to null on a empty basic auth request
|
||||
|
||||
if ($this->auth_user == "") {
|
||||
$this->auth_user = null;
|
||||
$this->auth_pw = null;
|
||||
if (empty($this->auth_user_nickname)) {
|
||||
$this->auth_user_nickname = null;
|
||||
$this->auth_password = null;
|
||||
}
|
||||
} else {
|
||||
$this->auth_user = null;
|
||||
$this->auth_pw = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +308,7 @@ class ApiAuthAction extends ApiAction
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showBasicAuthError()
|
||||
function showAuthError()
|
||||
{
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
$msg = 'Could not authenticate you.';
|
||||
|
122
lib/apioauth.php
Normal file
122
lib/apioauth.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base action for OAuth API endpoints
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category API
|
||||
* @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 . '/lib/apioauthstore.php';
|
||||
|
||||
/**
|
||||
* Base action for API OAuth enpoints. Clean up the
|
||||
* the request, and possibly some other common things
|
||||
* here.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthAction extends Action
|
||||
{
|
||||
/**
|
||||
* Is this a read-only action?
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* Switches on request method; either shows the form or handles its input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
self::cleanRequest();
|
||||
}
|
||||
|
||||
static function cleanRequest()
|
||||
{
|
||||
// kill evil effects of magical slashing
|
||||
|
||||
if (get_magic_quotes_gpc() == 1) {
|
||||
$_POST = array_map('stripslashes', $_POST);
|
||||
$_GET = array_map('stripslashes', $_GET);
|
||||
}
|
||||
|
||||
// strip out the p param added in index.php
|
||||
|
||||
// XXX: should we strip anything else? Or alternatively
|
||||
// only allow a known list of params?
|
||||
|
||||
unset($_GET['p']);
|
||||
unset($_POST['p']);
|
||||
}
|
||||
|
||||
function getCallback($url, $params)
|
||||
{
|
||||
foreach ($params as $k => $v) {
|
||||
$url = $this->appendQueryVar($url,
|
||||
OAuthUtil::urlencode_rfc3986($k),
|
||||
OAuthUtil::urlencode_rfc3986($v));
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
function appendQueryVar($url, $k, $v) {
|
||||
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
|
||||
$url = substr($url, 0, -1);
|
||||
if (strpos($url, '?') === false) {
|
||||
return ($url . '?' . $k . '=' . $v);
|
||||
} else {
|
||||
return ($url . '&' . $k . '=' . $v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
163
lib/apioauthstore.php
Normal file
163
lib/apioauthstore.php
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once INSTALLDIR . '/lib/oauthstore.php';
|
||||
|
||||
class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
|
||||
{
|
||||
|
||||
function lookup_consumer($consumer_key)
|
||||
{
|
||||
$con = Consumer::staticGet('consumer_key', $consumer_key);
|
||||
|
||||
if (!$con) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new OAuthConsumer($con->consumer_key,
|
||||
$con->consumer_secret);
|
||||
}
|
||||
|
||||
function getAppByRequestToken($token_key)
|
||||
{
|
||||
// Look up the full req tokenx
|
||||
|
||||
$req_token = $this->lookup_token(null,
|
||||
'request',
|
||||
$token_key);
|
||||
|
||||
if (empty($req_token)) {
|
||||
common_debug("couldn't get request token from oauth datastore");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look up the full Token
|
||||
|
||||
$token = new Token();
|
||||
$token->tok = $req_token->key;
|
||||
$result = $token->find(true);
|
||||
|
||||
if (empty($result)) {
|
||||
common_debug('Couldn\'t find req token in the token table.');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look up the app
|
||||
|
||||
$app = new Oauth_application();
|
||||
$app->consumer_key = $token->consumer_key;
|
||||
$result = $app->find(true);
|
||||
|
||||
if (!empty($result)) {
|
||||
return $app;
|
||||
} else {
|
||||
common_debug("Couldn't find the app!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function new_access_token($token, $consumer)
|
||||
{
|
||||
common_debug('new_access_token("'.$token->key.'","'.$consumer->key.'")', __FILE__);
|
||||
|
||||
$rt = new Token();
|
||||
$rt->consumer_key = $consumer->key;
|
||||
$rt->tok = $token->key;
|
||||
$rt->type = 0; // request
|
||||
|
||||
$app = Oauth_application::getByConsumerKey($consumer->key);
|
||||
|
||||
if (empty($app)) {
|
||||
common_debug("empty app!");
|
||||
}
|
||||
|
||||
if ($rt->find(true) && $rt->state == 1) { // authorized
|
||||
common_debug('request token found.', __FILE__);
|
||||
|
||||
// find the associated user of the app
|
||||
|
||||
$appUser = new Oauth_application_user();
|
||||
$appUser->application_id = $app->id;
|
||||
$appUser->token = $rt->tok;
|
||||
$result = $appUser->find(true);
|
||||
|
||||
if (!empty($result)) {
|
||||
common_debug("Oath app user found.");
|
||||
} else {
|
||||
common_debug("Oauth app user not found. app id $app->id token $rt->tok");
|
||||
return null;
|
||||
}
|
||||
|
||||
// go ahead and make the access token
|
||||
|
||||
$at = new Token();
|
||||
$at->consumer_key = $consumer->key;
|
||||
$at->tok = common_good_rand(16);
|
||||
$at->secret = common_good_rand(16);
|
||||
$at->type = 1; // access
|
||||
$at->created = DB_DataObject_Cast::dateTime();
|
||||
|
||||
if (!$at->insert()) {
|
||||
$e = $at->_lastError;
|
||||
common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__);
|
||||
return null;
|
||||
} else {
|
||||
common_debug('access token "'.$at->tok.'" inserted', __FILE__);
|
||||
// burn the old one
|
||||
$orig_rt = clone($rt);
|
||||
$rt->state = 2; // used
|
||||
if (!$rt->update($orig_rt)) {
|
||||
return null;
|
||||
}
|
||||
common_debug('request token "'.$rt->tok.'" updated', __FILE__);
|
||||
|
||||
// update the token from req to access for the user
|
||||
|
||||
$orig = clone($appUser);
|
||||
$appUser->token = $at->tok;
|
||||
|
||||
// It's at this point that we change the access type
|
||||
// to whatever the application's access is. Request
|
||||
// tokens should always have an access type of 0, and
|
||||
// therefore be unuseable for making requests for
|
||||
// protected resources.
|
||||
|
||||
$appUser->access_type = $app->access_type;
|
||||
|
||||
$result = $appUser->update($orig);
|
||||
|
||||
if (empty($result)) {
|
||||
common_debug('couldn\'t update OAuth app user.');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Okay, good
|
||||
|
||||
return new OAuthToken($at->tok, $at->secret);
|
||||
}
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
338
lib/applicationeditform.php
Normal file
338
lib/applicationeditform.php
Normal file
@ -0,0 +1,338 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for editing an application
|
||||
*
|
||||
* 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 Zach Copley <zach@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') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for editing an application
|
||||
*
|
||||
* @category Form
|
||||
* @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 ApplicationEditForm extends Form
|
||||
{
|
||||
/**
|
||||
* group for user to join
|
||||
*/
|
||||
|
||||
var $application = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Action $out output channel
|
||||
* @param User_group $group group to join
|
||||
*/
|
||||
|
||||
function __construct($out=null, $application=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
if ($this->application) {
|
||||
return 'form_application_edit-' . $this->application->id;
|
||||
} else {
|
||||
return 'form_application_add';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP method used to submit the form
|
||||
*
|
||||
* For image data we need to send multipart/form-data
|
||||
* so we set that here too
|
||||
*
|
||||
* @return string the method to use for submitting
|
||||
*/
|
||||
|
||||
function method()
|
||||
{
|
||||
$this->enctype = 'multipart/form-data';
|
||||
return 'post';
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($this->application)) {
|
||||
return common_local_url('editapplication',
|
||||
array('id' => $this->application->id));
|
||||
} else {
|
||||
return common_local_url('newapplication');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, _('Edit application'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
if ($this->application) {
|
||||
$id = $this->application->id;
|
||||
$icon = $this->application->icon;
|
||||
$name = $this->application->name;
|
||||
$description = $this->application->description;
|
||||
$source_url = $this->application->source_url;
|
||||
$organization = $this->application->organization;
|
||||
$homepage = $this->application->homepage;
|
||||
$callback_url = $this->application->callback_url;
|
||||
$this->type = $this->application->type;
|
||||
$this->access_type = $this->application->access_type;
|
||||
} else {
|
||||
$id = '';
|
||||
$icon = '';
|
||||
$name = '';
|
||||
$description = '';
|
||||
$source_url = '';
|
||||
$organization = '';
|
||||
$homepage = '';
|
||||
$callback_url = '';
|
||||
$this->type = '';
|
||||
$this->access_type = '';
|
||||
}
|
||||
|
||||
$this->out->hidden('token', common_session_token());
|
||||
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->out->elementStart('li', array('id' => 'application_icon'));
|
||||
|
||||
if (!empty($icon)) {
|
||||
$this->out->element('img', array('src' => $icon));
|
||||
}
|
||||
|
||||
$this->out->element('label', array('for' => 'app_icon'),
|
||||
_('Icon'));
|
||||
$this->out->element('input', array('name' => 'app_icon',
|
||||
'type' => 'file',
|
||||
'id' => 'app_icon'));
|
||||
$this->out->element('p', 'form_guide', _('Icon for this application'));
|
||||
$this->out->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||
'type' => 'hidden',
|
||||
'id' => 'MAX_FILE_SIZE',
|
||||
'value' => ImageFile::maxFileSizeInt()));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
|
||||
$this->out->hidden('application_id', $id);
|
||||
|
||||
$this->out->input('name', _('Name'),
|
||||
($this->out->arg('name')) ? $this->out->arg('name') : $name);
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
|
||||
$maxDesc = Oauth_application::maxDesc();
|
||||
if ($maxDesc > 0) {
|
||||
$descInstr = sprintf(_('Describe your application in %d characters'),
|
||||
$maxDesc);
|
||||
} else {
|
||||
$descInstr = _('Describe your application');
|
||||
}
|
||||
$this->out->textarea('description', _('Description'),
|
||||
($this->out->arg('description')) ? $this->out->arg('description') : $description,
|
||||
$descInstr);
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('source_url', _('Source URL'),
|
||||
($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url,
|
||||
_('URL of the homepage of this application'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('organization', _('Organization'),
|
||||
($this->out->arg('organization')) ? $this->out->arg('organization') : $organization,
|
||||
_('Organization responsible for this application'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('homepage', _('Homepage'),
|
||||
($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
|
||||
_('URL for the homepage of the organization'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('callback_url', ('Callback URL'),
|
||||
($this->out->arg('callback_url')) ? $this->out->arg('callback_url') : $callback_url,
|
||||
_('URL to redirect to after authentication'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li', array('id' => 'application_types'));
|
||||
|
||||
$attrs = array('name' => 'app_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'app_type-browser',
|
||||
'class' => 'radio',
|
||||
'value' => Oauth_application::$browser);
|
||||
|
||||
// Default to Browser
|
||||
|
||||
if ($this->application->type == Oauth_application::$browser
|
||||
|| empty($this->application->type)) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'app_type-browser',
|
||||
'class' => 'radio'),
|
||||
_('Browser'));
|
||||
|
||||
$attrs = array('name' => 'app_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'app_type-dekstop',
|
||||
'class' => 'radio',
|
||||
'value' => Oauth_application::$desktop);
|
||||
|
||||
if ($this->application->type == Oauth_application::$desktop) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'app_type-desktop',
|
||||
'class' => 'radio'),
|
||||
_('Desktop'));
|
||||
$this->out->element('p', 'form_guide', _('Type of application, browser or desktop'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li', array('id' => 'default_access_types'));
|
||||
|
||||
$attrs = array('name' => 'default_access_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'default_access_type-r',
|
||||
'class' => 'radio',
|
||||
'value' => 'r');
|
||||
|
||||
// default to read-only access
|
||||
|
||||
if ($this->application->access_type & Oauth_application::$readAccess
|
||||
|| empty($this->application->access_type)) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'default_access_type-ro',
|
||||
'class' => 'radio'),
|
||||
_('Read-only'));
|
||||
|
||||
$attrs = array('name' => 'default_access_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'default_access_type-rw',
|
||||
'class' => 'radio',
|
||||
'value' => 'rw');
|
||||
|
||||
if ($this->application->access_type & Oauth_application::$readAccess
|
||||
&& $this->application->access_type & Oauth_application::$writeAccess
|
||||
) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'default_access_type-rw',
|
||||
'class' => 'radio'),
|
||||
_('Read-write'));
|
||||
$this->out->element('p', 'form_guide', _('Default access for this application: read-only, or read-write'));
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('cancel', _('Cancel'), 'submit form_action-primary',
|
||||
'cancel', _('Cancel'));
|
||||
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
|
||||
'save', _('Save'));
|
||||
}
|
||||
}
|
168
lib/applicationlist.php
Normal file
168
lib/applicationlist.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Widget to show a list of OAuth applications
|
||||
*
|
||||
* 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 Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/widget.php';
|
||||
|
||||
define('APPS_PER_PAGE', 20);
|
||||
|
||||
/**
|
||||
* Widget to show a list of OAuth applications
|
||||
*
|
||||
* @category Application
|
||||
* @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 ApplicationList extends Widget
|
||||
{
|
||||
/** Current application, application query */
|
||||
var $application = null;
|
||||
|
||||
/** Owner of this list */
|
||||
var $owner = null;
|
||||
|
||||
/** Action object using us. */
|
||||
var $action = null;
|
||||
|
||||
function __construct($application, $owner=null, $action=null, $connections = false)
|
||||
{
|
||||
parent::__construct($action);
|
||||
|
||||
$this->application = $application;
|
||||
$this->owner = $owner;
|
||||
$this->action = $action;
|
||||
$this->connections = $connections;
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->out->elementStart('ul', 'applications');
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
while ($this->application->fetch()) {
|
||||
$cnt++;
|
||||
if($cnt > APPS_PER_PAGE) {
|
||||
break;
|
||||
}
|
||||
$this->showapplication();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
function showApplication()
|
||||
{
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$this->out->elementStart('li', array('class' => 'application',
|
||||
'id' => 'oauthclient-' . $this->application->id));
|
||||
|
||||
$this->out->elementStart('span', 'vcard author');
|
||||
if (!$this->connections) {
|
||||
$this->out->elementStart('a',
|
||||
array('href' => common_local_url('showapplication',
|
||||
array('id' => $this->application->id)),
|
||||
'class' => 'url'));
|
||||
|
||||
} else {
|
||||
$this->out->elementStart('a', array('href' => $this->application->source_url,
|
||||
'class' => 'url'));
|
||||
}
|
||||
|
||||
if (!empty($this->application->icon)) {
|
||||
$this->out->element('img', array('src' => $this->application->icon,
|
||||
'class' => 'photo avatar'));
|
||||
}
|
||||
|
||||
$this->out->element('span', 'fn', $this->application->name);
|
||||
$this->out->elementEnd('a');
|
||||
$this->out->elementEnd('span');
|
||||
|
||||
$this->out->raw(' by ');
|
||||
|
||||
$this->out->element('a', array('href' => $this->application->homepage,
|
||||
'class' => 'url'),
|
||||
$this->application->organization);
|
||||
|
||||
$this->out->element('p', 'note', $this->application->description);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
if ($this->connections) {
|
||||
$appUser = Oauth_application_user::getByKeys($this->owner, $this->application);
|
||||
|
||||
if (empty($appUser)) {
|
||||
common_debug("empty appUser!");
|
||||
}
|
||||
|
||||
$this->out->elementStart('li');
|
||||
|
||||
$access = ($this->application->access_type & Oauth_application::$writeAccess)
|
||||
? 'read-write' : 'read-only';
|
||||
|
||||
$txt = 'Approved ' . common_date_string($appUser->modified) .
|
||||
" - $access access.";
|
||||
|
||||
$this->out->raw($txt);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li', 'entity_revoke');
|
||||
$this->out->elementStart('form', array('id' => 'form_revoke_app',
|
||||
'class' => 'form_revoke_app',
|
||||
'method' => 'POST',
|
||||
'action' =>
|
||||
common_local_url('oauthconnectionssettings')));
|
||||
$this->out->elementStart('fieldset');
|
||||
$this->out->hidden('id', $this->application->id);
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->submit('revoke', _('Revoke'));
|
||||
$this->out->elementEnd('fieldset');
|
||||
$this->out->elementEnd('form');
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
||||
/* Override this in subclasses. */
|
||||
|
||||
function showOwnerControls()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
//exit with 200 response, if this is checking fancy from the installer
|
||||
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
|
||||
|
||||
define('STATUSNET_VERSION', '0.9.0beta3');
|
||||
define('STATUSNET_VERSION', '0.9.0beta4');
|
||||
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
||||
|
||||
define('STATUSNET_CODENAME', 'Stand');
|
||||
|
@ -116,6 +116,11 @@ class ConnectSettingsNav extends Widget
|
||||
_('Updates by SMS'));
|
||||
}
|
||||
|
||||
$menu['oauthconnectionssettings'] = array(
|
||||
_('Connections'),
|
||||
_('Authorized connected applications')
|
||||
);
|
||||
|
||||
foreach ($menu as $menuaction => $menudesc) {
|
||||
$this->action->menuItem(common_local_url($menuaction),
|
||||
$menudesc[0],
|
||||
@ -131,4 +136,3 @@ class ConnectSettingsNav extends Widget
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,7 +56,7 @@ $default =
|
||||
'dupelimit' => 60, # default for same person saying the same thing
|
||||
'textlimit' => 140,
|
||||
'indent' => true,
|
||||
'use_x_sendfile' => false,
|
||||
'use_x_sendfile' => false
|
||||
),
|
||||
'db' =>
|
||||
array('database' => 'YOU HAVE TO SET THIS IN config.php',
|
||||
@ -69,7 +69,9 @@ $default =
|
||||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||
'quote_identifiers' => false,
|
||||
'type' => 'mysql',
|
||||
'schemacheck' => 'runtime'), // 'runtime' or 'script'
|
||||
'schemacheck' => 'runtime', // 'runtime' or 'script'
|
||||
'log_queries' => false, // true to log all DB queries
|
||||
'log_slow_queries' => 0), // if set, log queries taking over N seconds
|
||||
'syslog' =>
|
||||
array('appname' => 'statusnet', # for syslog
|
||||
'priority' => 'debug', # XXX: currently ignored
|
||||
@ -79,11 +81,13 @@ $default =
|
||||
'subsystem' => 'db', # default to database, or 'stomp'
|
||||
'stomp_server' => null,
|
||||
'queue_basename' => '/queue/statusnet/',
|
||||
'control_channel' => '/topic/statusnet-control', // broadcasts to all queue daemons
|
||||
'stomp_username' => null,
|
||||
'stomp_password' => null,
|
||||
'monitor' => null, // URL to monitor ping endpoint (work in progress)
|
||||
'softlimit' => '90%', // total size or % of memory_limit at which to restart queue threads gracefully
|
||||
'debug_memory' => false, // true to spit memory usage to log
|
||||
'inboxes' => true, // true to do inbox distribution & output queueing from in background via 'distrib' queue
|
||||
),
|
||||
'license' =>
|
||||
array('type' => 'cc', # can be 'cc', 'allrightsreserved', 'private'
|
||||
@ -117,6 +121,9 @@ $default =
|
||||
array('server' => null,
|
||||
'dir' => null,
|
||||
'path'=> null),
|
||||
'javascript' =>
|
||||
array('server' => null,
|
||||
'path'=> null),
|
||||
'throttle' =>
|
||||
array('enabled' => false, // whether to throttle edits; false by default
|
||||
'count' => 20, // number of allowed messages in timespan
|
||||
@ -209,6 +216,8 @@ $default =
|
||||
'uploads' => true,
|
||||
'filecommand' => '/usr/bin/file',
|
||||
),
|
||||
'application' =>
|
||||
array('desclimit' => null),
|
||||
'group' =>
|
||||
array('maxaliases' => 3,
|
||||
'desclimit' => null),
|
||||
@ -255,5 +264,8 @@ $default =
|
||||
'OpenID' => null),
|
||||
),
|
||||
'admin' =>
|
||||
array('panels' => array('design', 'site', 'user', 'paths')),
|
||||
array('panels' => array('design', 'site', 'user', 'paths', 'access')),
|
||||
'singleuser' =>
|
||||
array('enabled' => false,
|
||||
'nickname' => null),
|
||||
);
|
||||
|
@ -327,8 +327,8 @@ class DesignSettingsAction extends AccountSettingsAction
|
||||
{
|
||||
parent::showScripts();
|
||||
|
||||
$this->script('js/farbtastic/farbtastic.js');
|
||||
$this->script('js/userdesign.go.js');
|
||||
$this->script('farbtastic/farbtastic.js');
|
||||
$this->script('userdesign.go.js');
|
||||
|
||||
$this->autofocus('design_background-image_file');
|
||||
}
|
||||
|
@ -351,14 +351,40 @@ class HTMLOutputter extends XMLOutputter
|
||||
function script($src, $type='text/javascript')
|
||||
{
|
||||
if(Event::handle('StartScriptElement', array($this,&$src,&$type))) {
|
||||
|
||||
$url = parse_url($src);
|
||||
|
||||
if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment']))
|
||||
{
|
||||
$src = common_path($src) . '?version=' . STATUSNET_VERSION;
|
||||
$path = common_config('javascript', 'path');
|
||||
|
||||
if (empty($path)) {
|
||||
$path = common_config('site', 'path') . '/js/';
|
||||
}
|
||||
|
||||
if ($path[strlen($path)-1] != '/') {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
if ($path[0] != '/') {
|
||||
$path = '/'.$path;
|
||||
}
|
||||
|
||||
$server = common_config('javascript', 'server');
|
||||
|
||||
if (empty($server)) {
|
||||
$server = common_config('site', 'server');
|
||||
}
|
||||
|
||||
// XXX: protocol
|
||||
|
||||
$src = 'http://'.$server.$path.$src . '?version=' . STATUSNET_VERSION;
|
||||
}
|
||||
|
||||
$this->element('script', array('type' => $type,
|
||||
'src' => $src),
|
||||
' ');
|
||||
|
||||
Event::handle('EndScriptElement', array($this,$src,$type));
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ abstract class IoMaster
|
||||
protected $pollTimeouts = array();
|
||||
protected $lastPoll = array();
|
||||
|
||||
public $shutdown = false; // Did we do a graceful shutdown?
|
||||
public $respawn = true; // Should we respawn after shutdown?
|
||||
|
||||
/**
|
||||
* @param string $id process ID to use in logging/monitoring
|
||||
*/
|
||||
@ -144,7 +147,7 @@ abstract class IoMaster
|
||||
$this->logState('init');
|
||||
$this->start();
|
||||
|
||||
while (true) {
|
||||
while (!$this->shutdown) {
|
||||
$timeouts = array_values($this->pollTimeouts);
|
||||
$timeouts[] = 60; // default max timeout
|
||||
|
||||
@ -196,22 +199,31 @@ abstract class IoMaster
|
||||
$this->logState('idle');
|
||||
$this->idle();
|
||||
|
||||
$memoryLimit = $this->softMemoryLimit();
|
||||
if ($memoryLimit > 0) {
|
||||
$usage = memory_get_usage();
|
||||
if ($usage > $memoryLimit) {
|
||||
common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting.");
|
||||
break;
|
||||
} else if (common_config('queue', 'debug_memory')) {
|
||||
common_log(LOG_DEBUG, "Memory usage $usage");
|
||||
}
|
||||
}
|
||||
$this->checkMemory();
|
||||
}
|
||||
|
||||
$this->logState('shutdown');
|
||||
$this->finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check runtime memory usage, possibly triggering a graceful shutdown
|
||||
* and thread respawn if we've crossed the soft limit.
|
||||
*/
|
||||
protected function checkMemory()
|
||||
{
|
||||
$memoryLimit = $this->softMemoryLimit();
|
||||
if ($memoryLimit > 0) {
|
||||
$usage = memory_get_usage();
|
||||
if ($usage > $memoryLimit) {
|
||||
common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting.");
|
||||
$this->requestRestart();
|
||||
} else if (common_config('queue', 'debug_memory')) {
|
||||
common_log(LOG_DEBUG, "Memory usage $usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return fully-parsed soft memory limit in bytes.
|
||||
* @return intval 0 or -1 if not set
|
||||
@ -354,5 +366,24 @@ abstract class IoMaster
|
||||
$owners[] = "thread:" . $this->id;
|
||||
$this->monitor->stats($key, $owners);
|
||||
}
|
||||
|
||||
/**
|
||||
* For IoManagers to request a graceful shutdown at end of event loop.
|
||||
*/
|
||||
public function requestShutdown()
|
||||
{
|
||||
$this->shutdown = true;
|
||||
$this->respawn = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For IoManagers to request a graceful restart at end of event loop.
|
||||
*/
|
||||
public function requestRestart()
|
||||
{
|
||||
$this->shutdown = true;
|
||||
$this->respawn = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,8 @@ class PersonalGroupNav extends Widget
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur && $cur->id == $user->id) {
|
||||
if ($cur && $cur->id == $user->id &&
|
||||
!common_config('singleuser', 'enabled')) {
|
||||
|
||||
$this->out->menuItem(common_local_url('inbox', array('nickname' =>
|
||||
$nickname)),
|
||||
|
@ -100,6 +100,23 @@ abstract class QueueManager extends IoManager
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional; ping any running queue handler daemons with a notification
|
||||
* such as announcing a new site to handle or requesting clean shutdown.
|
||||
* This avoids having to restart all the daemons manually to update configs
|
||||
* and such.
|
||||
*
|
||||
* Called from scripts/queuectl.php controller utility.
|
||||
*
|
||||
* @param string $event event key
|
||||
* @param string $param optional parameter to append to key
|
||||
* @return boolean success
|
||||
*/
|
||||
public function sendControlSignal($event, $param='')
|
||||
{
|
||||
throw new Exception(get_class($this) . " does not support control signals.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an object (usually/always a Notice) into the given queue
|
||||
* for later processing. No guarantee is made on when it will be
|
||||
@ -225,7 +242,6 @@ abstract class QueueManager extends IoManager
|
||||
// XMPP output handlers...
|
||||
$this->connect('jabber', 'JabberQueueHandler');
|
||||
$this->connect('public', 'PublicQueueHandler');
|
||||
|
||||
// @fixme this should get an actual queue
|
||||
//$this->connect('confirm', 'XmppConfirmHandler');
|
||||
|
||||
|
193
lib/router.php
193
lib/router.php
@ -73,12 +73,6 @@ class Router
|
||||
|
||||
if (Event::handle('StartInitializeRouter', array(&$m))) {
|
||||
|
||||
// In the "root"
|
||||
|
||||
$m->connect('', array('action' => 'public'));
|
||||
$m->connect('rss', array('action' => 'publicrss'));
|
||||
$m->connect('featuredrss', array('action' => 'featuredrss'));
|
||||
$m->connect('favoritedrss', array('action' => 'favoritedrss'));
|
||||
$m->connect('opensearch/people', array('action' => 'opensearch',
|
||||
'type' => 'people'));
|
||||
$m->connect('opensearch/notice', array('action' => 'opensearch',
|
||||
@ -140,11 +134,23 @@ class Router
|
||||
|
||||
// settings
|
||||
|
||||
foreach (array('profile', 'avatar', 'password', 'im',
|
||||
'email', 'sms', 'userdesign', 'other') as $s) {
|
||||
foreach (array('profile', 'avatar', 'password', 'im', 'oauthconnections',
|
||||
'oauthapps', 'email', 'sms', 'userdesign', 'other') as $s) {
|
||||
$m->connect('settings/'.$s, array('action' => $s.'settings'));
|
||||
}
|
||||
|
||||
$m->connect('settings/oauthapps/show/:id',
|
||||
array('action' => 'showapplication'),
|
||||
array('id' => '[0-9]+')
|
||||
);
|
||||
$m->connect('settings/oauthapps/new',
|
||||
array('action' => 'newapplication')
|
||||
);
|
||||
$m->connect('settings/oauthapps/edit/:id',
|
||||
array('action' => 'editapplication'),
|
||||
array('id' => '[0-9]+')
|
||||
);
|
||||
|
||||
// search
|
||||
|
||||
foreach (array('group', 'people', 'notice') as $s) {
|
||||
@ -227,11 +233,6 @@ class Router
|
||||
array('action' => 'peopletag'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect('featured/', array('action' => 'featured'));
|
||||
$m->connect('featured', array('action' => 'featured'));
|
||||
$m->connect('favorited/', array('action' => 'favorited'));
|
||||
$m->connect('favorited', array('action' => 'favorited'));
|
||||
|
||||
// groups
|
||||
|
||||
$m->connect('group/new', array('action' => 'newgroup'));
|
||||
@ -622,66 +623,146 @@ class Router
|
||||
$m->connect('api/search.json', array('action' => 'twitapisearchjson'));
|
||||
$m->connect('api/trends.json', array('action' => 'twitapitrends'));
|
||||
|
||||
$m->connect('api/oauth/request_token',
|
||||
array('action' => 'apioauthrequesttoken'));
|
||||
|
||||
$m->connect('api/oauth/access_token',
|
||||
array('action' => 'apioauthaccesstoken'));
|
||||
|
||||
$m->connect('api/oauth/authorize',
|
||||
array('action' => 'apioauthauthorize'));
|
||||
|
||||
// Admin
|
||||
|
||||
$m->connect('admin/site', array('action' => 'siteadminpanel'));
|
||||
$m->connect('admin/design', array('action' => 'designadminpanel'));
|
||||
$m->connect('admin/user', array('action' => 'useradminpanel'));
|
||||
$m->connect('admin/access', array('action' => 'accessadminpanel'));
|
||||
$m->connect('admin/paths', array('action' => 'pathsadminpanel'));
|
||||
|
||||
$m->connect('getfile/:filename',
|
||||
array('action' => 'getfile'),
|
||||
array('filename' => '[A-Za-z0-9._-]+'));
|
||||
|
||||
// user stuff
|
||||
// In the "root"
|
||||
|
||||
foreach (array('subscriptions', 'subscribers',
|
||||
'nudge', 'all', 'foaf', 'xrds',
|
||||
'replies', 'inbox', 'outbox', 'microsummary') as $a) {
|
||||
$m->connect(':nickname/'.$a,
|
||||
array('action' => $a),
|
||||
if (common_config('singleuser', 'enabled')) {
|
||||
|
||||
$nickname = common_config('singleuser', 'nickname');
|
||||
|
||||
foreach (array('subscriptions', 'subscribers',
|
||||
'all', 'foaf', 'xrds',
|
||||
'replies', 'microsummary') as $a) {
|
||||
$m->connect($a,
|
||||
array('action' => $a,
|
||||
'nickname' => $nickname));
|
||||
}
|
||||
|
||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||
$m->connect($a.'/:tag',
|
||||
array('action' => $a,
|
||||
'nickname' => $nickname),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
}
|
||||
|
||||
foreach (array('rss', 'groups') as $a) {
|
||||
$m->connect($a,
|
||||
array('action' => 'user'.$a,
|
||||
'nickname' => $nickname));
|
||||
}
|
||||
|
||||
foreach (array('all', 'replies', 'favorites') as $a) {
|
||||
$m->connect($a.'/rss',
|
||||
array('action' => $a.'rss',
|
||||
'nickname' => $nickname));
|
||||
}
|
||||
|
||||
$m->connect('favorites',
|
||||
array('action' => 'showfavorites',
|
||||
'nickname' => $nickname));
|
||||
|
||||
$m->connect('avatar/:size',
|
||||
array('action' => 'avatarbynickname',
|
||||
'nickname' => $nickname),
|
||||
array('size' => '(original|96|48|24)'));
|
||||
|
||||
$m->connect('tag/:tag/rss',
|
||||
array('action' => 'userrss',
|
||||
'nickname' => $nickname),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect('tag/:tag',
|
||||
array('action' => 'showstream',
|
||||
'nickname' => $nickname),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect('',
|
||||
array('action' => 'showstream',
|
||||
'nickname' => $nickname));
|
||||
|
||||
} else {
|
||||
|
||||
$m->connect('', array('action' => 'public'));
|
||||
$m->connect('rss', array('action' => 'publicrss'));
|
||||
$m->connect('featuredrss', array('action' => 'featuredrss'));
|
||||
$m->connect('favoritedrss', array('action' => 'favoritedrss'));
|
||||
$m->connect('featured/', array('action' => 'featured'));
|
||||
$m->connect('featured', array('action' => 'featured'));
|
||||
$m->connect('favorited/', array('action' => 'favorited'));
|
||||
$m->connect('favorited', array('action' => 'favorited'));
|
||||
|
||||
foreach (array('subscriptions', 'subscribers',
|
||||
'nudge', 'all', 'foaf', 'xrds',
|
||||
'replies', 'inbox', 'outbox', 'microsummary') as $a) {
|
||||
$m->connect(':nickname/'.$a,
|
||||
array('action' => $a),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||
$m->connect(':nickname/'.$a.'/:tag',
|
||||
array('action' => $a),
|
||||
array('tag' => '[a-zA-Z0-9]+',
|
||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('rss', 'groups') as $a) {
|
||||
$m->connect(':nickname/'.$a,
|
||||
array('action' => 'user'.$a),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('all', 'replies', 'favorites') as $a) {
|
||||
$m->connect(':nickname/'.$a.'/rss',
|
||||
array('action' => $a.'rss'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
$m->connect(':nickname/favorites',
|
||||
array('action' => 'showfavorites'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||
$m->connect(':nickname/'.$a.'/:tag',
|
||||
array('action' => $a),
|
||||
array('tag' => '[a-zA-Z0-9]+',
|
||||
$m->connect(':nickname/avatar/:size',
|
||||
array('action' => 'avatarbynickname'),
|
||||
array('size' => '(original|96|48|24)',
|
||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('rss', 'groups') as $a) {
|
||||
$m->connect(':nickname/'.$a,
|
||||
array('action' => 'user'.$a),
|
||||
$m->connect(':nickname/tag/:tag/rss',
|
||||
array('action' => 'userrss'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect(':nickname/tag/:tag',
|
||||
array('action' => 'showstream'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect(':nickname',
|
||||
array('action' => 'showstream'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
foreach (array('all', 'replies', 'favorites') as $a) {
|
||||
$m->connect(':nickname/'.$a.'/rss',
|
||||
array('action' => $a.'rss'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
}
|
||||
|
||||
$m->connect(':nickname/favorites',
|
||||
array('action' => 'showfavorites'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
|
||||
$m->connect(':nickname/avatar/:size',
|
||||
array('action' => 'avatarbynickname'),
|
||||
array('size' => '(original|96|48|24)',
|
||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
|
||||
$m->connect(':nickname/tag/:tag/rss',
|
||||
array('action' => 'userrss'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect(':nickname/tag/:tag',
|
||||
array('action' => 'showstream'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
||||
array('tag' => '[a-zA-Z0-9]+'));
|
||||
|
||||
$m->connect(':nickname',
|
||||
array('action' => 'showstream'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
// user stuff
|
||||
|
||||
Event::handle('RouterInitialized', array($m));
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ abstract class SpawningDaemon extends Daemon
|
||||
{
|
||||
protected $threads=1;
|
||||
|
||||
const EXIT_OK = 0;
|
||||
const EXIT_ERR = 1;
|
||||
const EXIT_SHUTDOWN = 100;
|
||||
const EXIT_RESTART = 101;
|
||||
|
||||
function __construct($id=null, $daemonize=true, $threads=1)
|
||||
{
|
||||
parent::__construct($daemonize);
|
||||
@ -49,7 +54,7 @@ abstract class SpawningDaemon extends Daemon
|
||||
/**
|
||||
* Perform some actual work!
|
||||
*
|
||||
* @return boolean true on success, false on failure
|
||||
* @return int exit code; use self::EXIT_SHUTDOWN to request not to respawn.
|
||||
*/
|
||||
public abstract function runThread();
|
||||
|
||||
@ -84,23 +89,30 @@ abstract class SpawningDaemon extends Daemon
|
||||
while (count($children) > 0) {
|
||||
$status = null;
|
||||
$pid = pcntl_wait($status);
|
||||
if ($pid > 0) {
|
||||
if ($pid > 0 && pcntl_wifexited($status)) {
|
||||
$exitCode = pcntl_wexitstatus($status);
|
||||
|
||||
$i = array_search($pid, $children);
|
||||
if ($i === false) {
|
||||
$this->log(LOG_ERR, "Unrecognized child pid $pid exited!");
|
||||
$this->log(LOG_ERR, "Unrecognized child pid $pid exited with status $exitCode");
|
||||
continue;
|
||||
}
|
||||
unset($children[$i]);
|
||||
$this->log(LOG_INFO, "Thread $i pid $pid exited.");
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid < 0) {
|
||||
$this->log(LOG_ERROR, "Couldn't fork to respawn thread $i; aborting thread.\n");
|
||||
} else if ($pid == 0) {
|
||||
$this->initAndRunChild($i);
|
||||
if ($this->shouldRespawn($exitCode)) {
|
||||
$this->log(LOG_INFO, "Thread $i pid $pid exited with status $exitCode; respawing.");
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid < 0) {
|
||||
$this->log(LOG_ERROR, "Couldn't fork to respawn thread $i; aborting thread.\n");
|
||||
} else if ($pid == 0) {
|
||||
$this->initAndRunChild($i);
|
||||
} else {
|
||||
$this->log(LOG_INFO, "Respawned thread $i as pid $pid");
|
||||
$children[$i] = $pid;
|
||||
}
|
||||
} else {
|
||||
$this->log(LOG_INFO, "Respawned thread $i as pid $pid");
|
||||
$children[$i] = $pid;
|
||||
$this->log(LOG_INFO, "Thread $i pid $pid exited with status $exitCode; closing out thread.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,6 +120,24 @@ abstract class SpawningDaemon extends Daemon
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to respawn an exited subprocess based on its exit code.
|
||||
* Otherwise we'll respawn all exits by default.
|
||||
*
|
||||
* @param int $exitCode
|
||||
* @return boolean true to respawn
|
||||
*/
|
||||
protected function shouldRespawn($exitCode)
|
||||
{
|
||||
if ($exitCode == self::EXIT_SHUTDOWN) {
|
||||
// Thread requested a clean shutdown.
|
||||
return false;
|
||||
} else {
|
||||
// Otherwise we should always respawn!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize things for a fresh thread, call runThread(), and
|
||||
* exit at completion with appropriate return value.
|
||||
@ -116,8 +146,8 @@ abstract class SpawningDaemon extends Daemon
|
||||
{
|
||||
$this->set_id($this->get_id() . "." . $thread);
|
||||
$this->resetDb();
|
||||
$ok = $this->runThread();
|
||||
exit($ok ? 0 : 1);
|
||||
$exitCode = $this->runThread();
|
||||
exit($exitCode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,8 +38,10 @@ class StompQueueManager extends QueueManager
|
||||
var $password = null;
|
||||
var $base = null;
|
||||
var $con = null;
|
||||
protected $control;
|
||||
|
||||
protected $sites = array();
|
||||
protected $subscriptions = array();
|
||||
|
||||
protected $useTransactions = true;
|
||||
protected $transaction = null;
|
||||
@ -52,6 +54,7 @@ class StompQueueManager extends QueueManager
|
||||
$this->username = common_config('queue', 'stomp_username');
|
||||
$this->password = common_config('queue', 'stomp_password');
|
||||
$this->base = common_config('queue', 'queue_basename');
|
||||
$this->control = common_config('queue', 'control_channel');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,6 +80,36 @@ class StompQueueManager extends QueueManager
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional; ping any running queue handler daemons with a notification
|
||||
* such as announcing a new site to handle or requesting clean shutdown.
|
||||
* This avoids having to restart all the daemons manually to update configs
|
||||
* and such.
|
||||
*
|
||||
* Currently only relevant for multi-site queue managers such as Stomp.
|
||||
*
|
||||
* @param string $event event key
|
||||
* @param string $param optional parameter to append to key
|
||||
* @return boolean success
|
||||
*/
|
||||
public function sendControlSignal($event, $param='')
|
||||
{
|
||||
$message = $event;
|
||||
if ($param != '') {
|
||||
$message .= ':' . $param;
|
||||
}
|
||||
$this->_connect();
|
||||
$result = $this->con->send($this->control,
|
||||
$message,
|
||||
array ('created' => common_sql_now()));
|
||||
if ($result) {
|
||||
$this->_log(LOG_INFO, "Sent control ping to queue daemons: $message");
|
||||
return true;
|
||||
} else {
|
||||
$this->_log(LOG_ERR, "Failed sending control ping to queue daemons: $message");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the appropriate QueueHandler class for the given queue.
|
||||
@ -86,7 +119,7 @@ class StompQueueManager extends QueueManager
|
||||
*/
|
||||
function getHandler($queue)
|
||||
{
|
||||
$handlers = $this->handlers[common_config('site', 'server')];
|
||||
$handlers = $this->handlers[$this->currentSite()];
|
||||
if (isset($handlers[$queue])) {
|
||||
$class = $handlers[$queue];
|
||||
if (class_exists($class)) {
|
||||
@ -108,7 +141,7 @@ class StompQueueManager extends QueueManager
|
||||
function getQueues()
|
||||
{
|
||||
$group = $this->activeGroup();
|
||||
$site = common_config('site', 'server');
|
||||
$site = $this->currentSite();
|
||||
if (empty($this->groups[$site][$group])) {
|
||||
return array();
|
||||
} else {
|
||||
@ -126,8 +159,8 @@ class StompQueueManager extends QueueManager
|
||||
*/
|
||||
public function connect($transport, $class, $group='queuedaemon')
|
||||
{
|
||||
$this->handlers[common_config('site', 'server')][$transport] = $class;
|
||||
$this->groups[common_config('site', 'server')][$group][$transport] = $class;
|
||||
$this->handlers[$this->currentSite()][$transport] = $class;
|
||||
$this->groups[$this->currentSite()][$group][$transport] = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +178,8 @@ class StompQueueManager extends QueueManager
|
||||
|
||||
$result = $this->con->send($this->queueName($queue),
|
||||
$msg, // BODY of the message
|
||||
array ('created' => common_sql_now()));
|
||||
array ('created' => common_sql_now(),
|
||||
'persistent' => 'true'));
|
||||
|
||||
if (!$result) {
|
||||
common_log(LOG_ERR, "Error sending $rep to $queue queue");
|
||||
@ -180,7 +214,16 @@ class StompQueueManager extends QueueManager
|
||||
$ok = true;
|
||||
$frames = $this->con->readFrames();
|
||||
foreach ($frames as $frame) {
|
||||
$ok = $ok && $this->_handleItem($frame);
|
||||
$dest = $frame->headers['destination'];
|
||||
if ($dest == $this->control) {
|
||||
if (!$this->handleControlSignal($frame)) {
|
||||
// We got a control event that requests a shutdown;
|
||||
// close out and stop handling anything else!
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$ok = $ok && $this->handleItem($frame);
|
||||
}
|
||||
}
|
||||
return $ok;
|
||||
}
|
||||
@ -197,6 +240,9 @@ class StompQueueManager extends QueueManager
|
||||
public function start($master)
|
||||
{
|
||||
parent::start($master);
|
||||
$this->_connect();
|
||||
|
||||
$this->con->subscribe($this->control);
|
||||
if ($this->sites) {
|
||||
foreach ($this->sites as $server) {
|
||||
StatusNet::init($server);
|
||||
@ -221,6 +267,7 @@ class StompQueueManager extends QueueManager
|
||||
// If there are any outstanding delivered messages we haven't processed,
|
||||
// free them for another thread to take.
|
||||
$this->rollback();
|
||||
$this->con->unsubscribe($this->control);
|
||||
if ($this->sites) {
|
||||
foreach ($this->sites as $server) {
|
||||
StatusNet::init($server);
|
||||
@ -232,6 +279,15 @@ class StompQueueManager extends QueueManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get identifier of the currently active site configuration
|
||||
* @return string
|
||||
*/
|
||||
protected function currentSite()
|
||||
{
|
||||
return common_config('site', 'server'); // @fixme switch to nickname
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy open connection to Stomp queue server.
|
||||
*/
|
||||
@ -255,9 +311,11 @@ class StompQueueManager extends QueueManager
|
||||
*/
|
||||
protected function doSubscribe()
|
||||
{
|
||||
$site = $this->currentSite();
|
||||
$this->_connect();
|
||||
foreach ($this->getQueues() as $queue) {
|
||||
$rawqueue = $this->queueName($queue);
|
||||
$this->subscriptions[$site][$queue] = $rawqueue;
|
||||
$this->_log(LOG_INFO, "Subscribing to $rawqueue");
|
||||
$this->con->subscribe($rawqueue);
|
||||
}
|
||||
@ -268,9 +326,14 @@ class StompQueueManager extends QueueManager
|
||||
*/
|
||||
protected function doUnsubscribe()
|
||||
{
|
||||
$site = $this->currentSite();
|
||||
$this->_connect();
|
||||
foreach ($this->getQueues() as $queue) {
|
||||
$this->con->unsubscribe($this->queueName($queue));
|
||||
if (!empty($this->subscriptions[$site])) {
|
||||
foreach ($this->subscriptions[$site] as $queue => $rawqueue) {
|
||||
$this->_log(LOG_INFO, "Unsubscribing from $rawqueue");
|
||||
$this->con->unsubscribe($rawqueue);
|
||||
unset($this->subscriptions[$site][$queue]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,10 +349,10 @@ class StompQueueManager extends QueueManager
|
||||
* @param StompFrame $frame
|
||||
* @return bool
|
||||
*/
|
||||
protected function _handleItem($frame)
|
||||
protected function handleItem($frame)
|
||||
{
|
||||
list($site, $queue) = $this->parseDestination($frame->headers['destination']);
|
||||
if ($site != common_config('site', 'server')) {
|
||||
if ($site != $this->currentSite()) {
|
||||
$this->stats('switch');
|
||||
StatusNet::init($site);
|
||||
}
|
||||
@ -317,7 +380,7 @@ class StompQueueManager extends QueueManager
|
||||
|
||||
$handler = $this->getHandler($queue);
|
||||
if (!$handler) {
|
||||
$this->_log(LOG_ERROR, "Missing handler class; skipping $info");
|
||||
$this->_log(LOG_ERR, "Missing handler class; skipping $info");
|
||||
$this->ack($frame);
|
||||
$this->commit();
|
||||
$this->begin();
|
||||
@ -348,6 +411,77 @@ class StompQueueManager extends QueueManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a control signal broadcast.
|
||||
*
|
||||
* @param array $frame Stomp frame
|
||||
* @return bool true to continue; false to stop further processing.
|
||||
*/
|
||||
protected function handleControlSignal($frame)
|
||||
{
|
||||
$message = trim($frame->body);
|
||||
if (strpos($message, ':') !== false) {
|
||||
list($event, $param) = explode(':', $message, 2);
|
||||
} else {
|
||||
$event = $message;
|
||||
$param = '';
|
||||
}
|
||||
|
||||
$shutdown = false;
|
||||
|
||||
if ($event == 'shutdown') {
|
||||
$this->master->requestShutdown();
|
||||
$shutdown = true;
|
||||
} else if ($event == 'restart') {
|
||||
$this->master->requestRestart();
|
||||
$shutdown = true;
|
||||
} else if ($event == 'update') {
|
||||
$this->updateSiteConfig($param);
|
||||
} else {
|
||||
$this->_log(LOG_ERR, "Ignoring unrecognized control message: $message");
|
||||
}
|
||||
|
||||
$this->ack($frame);
|
||||
$this->commit();
|
||||
$this->begin();
|
||||
return $shutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set us up with queue subscriptions for a new site added at runtime,
|
||||
* triggered by a broadcast to the 'statusnet-control' topic.
|
||||
*
|
||||
* @param array $frame Stomp frame
|
||||
* @return bool true to continue; false to stop further processing.
|
||||
*/
|
||||
protected function updateSiteConfig($nickname)
|
||||
{
|
||||
if (empty($this->sites)) {
|
||||
if ($nickname == common_config('site', 'nickname')) {
|
||||
StatusNet::init(common_config('site', 'server'));
|
||||
$this->doUnsubscribe();
|
||||
$this->doSubscribe();
|
||||
} else {
|
||||
$this->_log(LOG_INFO, "Ignoring update ping for other site $nickname");
|
||||
}
|
||||
} else {
|
||||
$sn = Status_network::staticGet($nickname);
|
||||
if ($sn) {
|
||||
$server = $sn->getServerName(); // @fixme do config-by-nick
|
||||
StatusNet::init($server);
|
||||
if (empty($this->sites[$server])) {
|
||||
$this->addSite($server);
|
||||
}
|
||||
$this->_log(LOG_INFO, "(Re)subscribing to queues for site $nickname / $server");
|
||||
$this->doUnsubscribe();
|
||||
$this->doSubscribe();
|
||||
$this->stats('siteupdate');
|
||||
} else {
|
||||
$this->_log(LOG_ERR, "Ignoring ping for unrecognized new site $nickname");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the queue_basename from configuration with the
|
||||
* site server name and queue name to give eg:
|
||||
@ -360,7 +494,7 @@ class StompQueueManager extends QueueManager
|
||||
protected function queueName($queue)
|
||||
{
|
||||
return common_config('queue', 'queue_basename') .
|
||||
common_config('site', 'server') . '/' . $queue;
|
||||
$this->currentSite() . '/' . $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
204
lib/uapplugin.php
Normal file
204
lib/uapplugin.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* UAP (Universal Ad Package) plugin
|
||||
*
|
||||
* 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 Sarven Capadisli <csarven@status.net>
|
||||
* @author Evan Prodromou <evan@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') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract superclass for advertising plugins
|
||||
*
|
||||
* Plugins for showing ads should derive from this plugin.
|
||||
*
|
||||
* Outputs the following ad types (based on UAP):
|
||||
*
|
||||
* Medium Rectangle 300x250
|
||||
* Rectangle 180x150
|
||||
* Leaderboard 728x90
|
||||
* Wide Skyscraper 160x600
|
||||
*
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @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/
|
||||
*/
|
||||
|
||||
abstract class UAPPlugin extends Plugin
|
||||
{
|
||||
public $mediumRectangle = null;
|
||||
public $rectangle = null;
|
||||
public $leaderboard = null;
|
||||
public $wideSkyscraper = null;
|
||||
|
||||
/**
|
||||
* Output our dedicated stylesheet
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return boolean hook flag
|
||||
*/
|
||||
|
||||
function onEndShowStatusNetStyles($action)
|
||||
{
|
||||
// XXX: allow override by theme
|
||||
$action->cssLink('css/uap.css', 'base', 'screen, projection, tv');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a medium rectangle ad at the beginning of sidebar
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return boolean hook flag
|
||||
*/
|
||||
|
||||
function onStartShowAside($action)
|
||||
{
|
||||
if (!is_null($this->mediumRectangle)) {
|
||||
|
||||
$action->elementStart('div',
|
||||
array('id' => 'ad_medium-rectangle',
|
||||
'class' => 'ad'));
|
||||
|
||||
$this->showMediumRectangle($action);
|
||||
|
||||
$action->elementEnd('div');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a leaderboard in the header
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return boolean hook flag
|
||||
*/
|
||||
|
||||
function onEndShowHeader($action)
|
||||
{
|
||||
if (!is_null($this->leaderboard)) {
|
||||
$action->elementStart('div',
|
||||
array('id' => 'ad_leaderboard',
|
||||
'class' => 'ad'));
|
||||
$this->showLeaderboard($action);
|
||||
$action->elementEnd('div');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a rectangle before aside sections
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return boolean hook flag
|
||||
*/
|
||||
|
||||
function onStartShowSections($action)
|
||||
{
|
||||
if (!is_null($this->rectangle)) {
|
||||
$action->elementStart('div',
|
||||
array('id' => 'ad_rectangle',
|
||||
'class' => 'ad'));
|
||||
$this->showRectangle($action);
|
||||
$action->elementEnd('div');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a wide skyscraper after the aside
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return boolean hook flag
|
||||
*/
|
||||
|
||||
function onEndShowAside($action)
|
||||
{
|
||||
if (!is_null($this->wideSkyscraper)) {
|
||||
$action->elementStart('div',
|
||||
array('id' => 'ad_wide-skyscraper',
|
||||
'class' => 'ad'));
|
||||
|
||||
$this->showWideSkyscraper($action);
|
||||
|
||||
$action->elementEnd('div');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a medium rectangle ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
abstract protected function showMediumRectangle($action);
|
||||
|
||||
/**
|
||||
* Show a rectangle ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
abstract protected function showRectangle($action);
|
||||
|
||||
/**
|
||||
* Show a wide skyscraper ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
abstract protected function showWideSkyscraper($action);
|
||||
|
||||
/**
|
||||
* Show a leaderboard ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
abstract protected function showLeaderboard($action);
|
||||
}
|
160
plugins/Adsense/AdsensePlugin.php
Normal file
160
plugins/Adsense/AdsensePlugin.php
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Plugin for Google Adsense
|
||||
*
|
||||
* 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 Ads
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin to add Google Adsense to StatusNet sites
|
||||
*
|
||||
* This plugin lets you add Adsense ad units to your StatusNet site.
|
||||
*
|
||||
* We support the 4 ad sizes for the Universal Ad Platform (UAP):
|
||||
*
|
||||
* Medium Rectangle
|
||||
* (Small) Rectangle
|
||||
* Leaderboard
|
||||
* Wide Skyscraper
|
||||
*
|
||||
* They fit in different places on the default theme. Some themes
|
||||
* might interact quite poorly with this plugin.
|
||||
*
|
||||
* To enable advertising, you must sign up with Google Adsense and
|
||||
* get a client ID.
|
||||
*
|
||||
* https://www.google.com/adsense/
|
||||
*
|
||||
* You'll also need to create an Adsense for Content unit in one
|
||||
* of the four sizes described above. At the end of the process,
|
||||
* note the "google_ad_client" and "google_ad_slot" values in the
|
||||
* resultant Javascript.
|
||||
*
|
||||
* Add the plugin to config.php like so:
|
||||
*
|
||||
* addPlugin('Adsense', array('client' => 'Your client ID',
|
||||
* 'rectangle' => 'slot'));
|
||||
*
|
||||
* Here, your client ID is the value of google_ad_client and the
|
||||
* slot is the value of google_ad_slot. Note that if you create
|
||||
* a different size, you'll need to provide different arguments:
|
||||
* 'mediumRectangle', 'leaderboard', or 'wideSkyscraper'.
|
||||
*
|
||||
* If for some reason your ad server is different from the default,
|
||||
* use the 'adScript' parameter to set the full path to the ad script.
|
||||
*
|
||||
* @category Plugin
|
||||
* @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/
|
||||
*
|
||||
* @seeAlso UAPPlugin
|
||||
*/
|
||||
|
||||
class AdsensePlugin extends UAPPlugin
|
||||
{
|
||||
public $adScript = 'http://pagead2.googlesyndication.com/pagead/show_ads.js';
|
||||
public $client = null;
|
||||
|
||||
/**
|
||||
* Show a medium rectangle 'ad'
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showMediumRectangle($action)
|
||||
{
|
||||
$this->showAdsenseCode($action, 300, 250, $this->mediumRectangle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a rectangle 'ad'
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showRectangle($action)
|
||||
{
|
||||
$this->showAdsenseCode($action, 180, 150, $this->rectangle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a wide skyscraper ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showWideSkyscraper($action)
|
||||
{
|
||||
$this->showAdsenseCode($action, 160, 600, $this->wideSkyscraper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a leaderboard ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showLeaderboard($action)
|
||||
{
|
||||
$this->showAdsenseCode($action, 728, 90, $this->leaderboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the bits of JavaScript code to show Adsense
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
* @param integer $width Width of the block
|
||||
* @param integer $height Height of the block
|
||||
* @param string $slot Slot identifier
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showAdsenseCode($action, $width, $height, $slot)
|
||||
{
|
||||
$code = 'google_ad_client = "'.$this->client.'"; ';
|
||||
$code .= 'google_ad_slot = "'.$slot.'"; ';
|
||||
$code .= 'google_ad_width = '.$width.'; ';
|
||||
$code .= 'google_ad_height = '.$height.'; ';
|
||||
|
||||
$action->inlineScript($code);
|
||||
|
||||
$action->script($this->adScript);
|
||||
}
|
||||
}
|
124
plugins/BlankAd/BlankAdPlugin.php
Normal file
124
plugins/BlankAd/BlankAdPlugin.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Plugin for testing ad layout
|
||||
*
|
||||
* 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 Ads
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin for testing ad layout
|
||||
*
|
||||
* This plugin uses the UAPPlugin framework to output ad content. However,
|
||||
* its ad content is just images with one red pixel stretched to the
|
||||
* right size. It's mostly useful for debugging theme layout.
|
||||
*
|
||||
* To use this plugin, set the parameter for the ad size you want to use
|
||||
* to true (or anything non-null). For example, to make a leaderboard:
|
||||
*
|
||||
* addPlugin('BlankAd', array('leaderboard' => true));
|
||||
*
|
||||
* @category Plugin
|
||||
* @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/
|
||||
*
|
||||
* @seeAlso Location
|
||||
*/
|
||||
|
||||
class BlankAdPlugin extends UAPPlugin
|
||||
{
|
||||
/**
|
||||
* Show a medium rectangle 'ad'
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showMediumRectangle($action)
|
||||
{
|
||||
$action->element('img',
|
||||
array('width' => 300,
|
||||
'height' => 250,
|
||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
||||
'');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a rectangle 'ad'
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showRectangle($action)
|
||||
{
|
||||
$action->element('img',
|
||||
array('width' => 180,
|
||||
'height' => 150,
|
||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
||||
'');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a wide skyscraper ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showWideSkyscraper($action)
|
||||
{
|
||||
$action->element('img',
|
||||
array('width' => 160,
|
||||
'height' => 600,
|
||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
||||
'');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a leaderboard ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showLeaderboard($action)
|
||||
{
|
||||
$action->element('img',
|
||||
array('width' => 728,
|
||||
'height' => 90,
|
||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
||||
'');
|
||||
}
|
||||
}
|
BIN
plugins/BlankAd/redpixel.png
Normal file
BIN
plugins/BlankAd/redpixel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 B |
@ -89,7 +89,7 @@ class FacebookAction extends Action
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
$this->script('js/facebookapp.js');
|
||||
$this->script('facebookapp.js');
|
||||
}
|
||||
|
||||
/**
|
||||
|
165
plugins/OpenX/OpenXPlugin.php
Normal file
165
plugins/OpenX/OpenXPlugin.php
Normal file
@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Plugin for OpenX ad server
|
||||
*
|
||||
* 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 Ads
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin for OpenX Ad Server
|
||||
*
|
||||
* This plugin supports the OpenX ad server, http://www.openx.org/
|
||||
*
|
||||
* We support the 4 ad sizes for the Universal Ad Platform (UAP):
|
||||
*
|
||||
* Medium Rectangle
|
||||
* (Small) Rectangle
|
||||
* Leaderboard
|
||||
* Wide Skyscraper
|
||||
*
|
||||
* They fit in different places on the default theme. Some themes
|
||||
* might interact quite poorly with this plugin.
|
||||
*
|
||||
* To enable advertising, you will need an OpenX server. You'll need
|
||||
* to set up a "zone" for your StatusNet site that identifies a
|
||||
* kind of ad you want to place (of the above 4 sizes).
|
||||
*
|
||||
* Add the plugin to config.php like so:
|
||||
*
|
||||
* addPlugin('OpenX', array('adScript' => 'full path to script',
|
||||
* 'rectangle' => 1));
|
||||
*
|
||||
* Here, the 'adScript' parameter is the full path to the OpenX
|
||||
* ad script, like 'http://example.com/www/delivery/ajs.php'. Note
|
||||
* that we don't do any magic to swap between HTTP and HTTPS, so
|
||||
* if you want HTTPS, say so.
|
||||
*
|
||||
* The 'rectangle' parameter is the zone ID for that ad space on
|
||||
* your site. If you've configured another size, try 'mediumRectangle',
|
||||
* 'leaderboard', or 'wideSkyscraper'.
|
||||
*
|
||||
* If for some reason your ad server is different from the default,
|
||||
* use the 'adScript' parameter to set the full path to the ad script.
|
||||
*
|
||||
* @category Ads
|
||||
* @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/
|
||||
*
|
||||
* @seeAlso UAPPlugin
|
||||
*/
|
||||
|
||||
class OpenXPlugin extends UAPPlugin
|
||||
{
|
||||
public $adScript = null;
|
||||
|
||||
/**
|
||||
* Show a medium rectangle 'ad'
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showMediumRectangle($action)
|
||||
{
|
||||
$this->showAd($action, $this->mediumRectangle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a rectangle 'ad'
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showRectangle($action)
|
||||
{
|
||||
$this->showAd($action, $this->rectangle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a wide skyscraper ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showWideSkyscraper($action)
|
||||
{
|
||||
$this->showAd($action, $this->wideSkyscraper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a leaderboard ad
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showLeaderboard($action)
|
||||
{
|
||||
$this->showAd($action, $this->leaderboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an ad using OpenX
|
||||
*
|
||||
* @param Action $action Action being shown
|
||||
* @param integer $zone Zone to show
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected function showAd($action, $zone)
|
||||
{
|
||||
$scr = <<<ENDOFSCRIPT
|
||||
var m3_u = '%s';
|
||||
var m3_r = Math.floor(Math.random()*99999999999);
|
||||
if (!document.MAX_used) document.MAX_used = ',';
|
||||
document.write ("<scr"+"ipt type='text/javascript' src='"+m3_u);
|
||||
document.write ("?zoneid=%d");
|
||||
document.write ('&cb=' + m3_r);
|
||||
if (document.MAX_used != ',') document.write ("&exclude=" + document.MAX_used);
|
||||
document.write (document.charset ? '&charset='+document.charset : (document.characterSet ? '&charset='+document.characterSet : ''));
|
||||
document.write ("&loc=" + escape(window.location));
|
||||
if (document.referrer) document.write ("&referer=" + escape(document.referrer));
|
||||
if (document.context) document.write ("&context=" + escape(document.context));
|
||||
if (document.mmm_fo) document.write ("&mmm_fo=1");
|
||||
document.write ("'><\/scr"+"ipt>");
|
||||
ENDOFSCRIPT;
|
||||
|
||||
$action->inlineScript(sprintf($scr, $this->adScript, $zone));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -46,8 +46,9 @@ class PoweredByStatusNetPlugin extends Plugin
|
||||
function onEndAddressData($action)
|
||||
{
|
||||
$action->elementStart('span', 'poweredby');
|
||||
$action->text(_('powered by'));
|
||||
$action->element('a', array('href' => 'http://status.net/'), 'StatusNet');
|
||||
$action->raw(sprintf(_m('powered by %s'),
|
||||
sprintf('<a href="http://status.net/">%s</a>',
|
||||
_m('StatusNet'))));
|
||||
$action->elementEnd('span');
|
||||
|
||||
return true;
|
||||
|
32
plugins/PoweredByStatusNet/locale/PoweredByStatusNet.po
Normal file
32
plugins/PoweredByStatusNet/locale/PoweredByStatusNet.po
Normal file
@ -0,0 +1,32 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-01-22 15:03-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: PoweredByStatusNetPlugin.php:49
|
||||
#, php-format
|
||||
msgid "powered by %s"
|
||||
msgstr ""
|
||||
|
||||
#: PoweredByStatusNetPlugin.php:51
|
||||
msgid "StatusNet"
|
||||
msgstr ""
|
||||
|
||||
#: PoweredByStatusNetPlugin.php:64
|
||||
msgid ""
|
||||
"Outputs powered by <a href=\"http://status.net/\">StatusNet</a> after site "
|
||||
"name."
|
||||
msgstr ""
|
@ -79,6 +79,21 @@ class PubSubHubBubPlugin extends Plugin
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin should be active; may be mass-enabled.
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
function enabled()
|
||||
{
|
||||
if (common_config('site', 'private')) {
|
||||
// PuSH relies on public feeds
|
||||
return false;
|
||||
}
|
||||
// @fixme check for being on a private network?
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks the StartApiAtom event
|
||||
*
|
||||
@ -92,8 +107,9 @@ class PubSubHubBubPlugin extends Plugin
|
||||
|
||||
function onStartApiAtom($action)
|
||||
{
|
||||
$action->element('link', array('rel' => 'hub', 'href' => $this->hub), null);
|
||||
|
||||
if ($this->enabled()) {
|
||||
$action->element('link', array('rel' => 'hub', 'href' => $this->hub), null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -110,9 +126,11 @@ class PubSubHubBubPlugin extends Plugin
|
||||
|
||||
function onStartApiRss($action)
|
||||
{
|
||||
$action->element('atom:link', array('rel' => 'hub',
|
||||
'href' => $this->hub),
|
||||
null);
|
||||
if ($this->enabled()) {
|
||||
$action->element('atom:link', array('rel' => 'hub',
|
||||
'href' => $this->hub),
|
||||
null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -130,6 +148,9 @@ class PubSubHubBubPlugin extends Plugin
|
||||
|
||||
function onHandleQueuedNotice($notice)
|
||||
{
|
||||
if (!$this->enabled()) {
|
||||
return false;
|
||||
}
|
||||
$publisher = new Publisher($this->hub);
|
||||
|
||||
$feeds = array();
|
||||
@ -211,13 +232,20 @@ class PubSubHubBubPlugin extends Plugin
|
||||
'format' => 'atom'));
|
||||
}
|
||||
}
|
||||
$feeds = array_unique($feeds);
|
||||
|
||||
foreach (array_unique($feeds) as $feed) {
|
||||
if (!$publisher->publish_update($feed)) {
|
||||
common_log_line(LOG_WARNING,
|
||||
$feed.' was not published to hub at '.
|
||||
$this->hub.':'.$publisher->last_response());
|
||||
}
|
||||
ob_start();
|
||||
$ok = $publisher->publish_update($feeds);
|
||||
$push_last_response = ob_get_clean();
|
||||
|
||||
if (!$ok) {
|
||||
common_log(LOG_WARNING,
|
||||
'Failure publishing ' . count($feeds) . ' feeds to hub at '.
|
||||
$this->hub.': '.$push_last_response);
|
||||
} else {
|
||||
common_log(LOG_INFO,
|
||||
'Published ' . count($feeds) . ' feeds to hub at '.
|
||||
$this->hub.': '.$push_last_response);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -236,16 +264,21 @@ class PubSubHubBubPlugin extends Plugin
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
{
|
||||
$about = _m('The PubSubHubBub plugin pushes RSS/Atom updates '.
|
||||
'to a <a href = "'.
|
||||
'http://pubsubhubbub.googlecode.com/'.
|
||||
'">PubSubHubBub</a> hub.');
|
||||
if (!$this->enabled()) {
|
||||
$about = '<span class="disabled" style="color:gray">' . $about . '</span> ' .
|
||||
_m('(inactive on private site)');
|
||||
}
|
||||
$versions[] = array('name' => 'PubSubHubBub',
|
||||
'version' => STATUSNET_VERSION,
|
||||
'author' => 'Craig Andrews',
|
||||
'homepage' =>
|
||||
'http://status.net/wiki/Plugin:PubSubHubBub',
|
||||
'rawdescription' =>
|
||||
_m('The PubSubHubBub plugin pushes RSS/Atom updates '.
|
||||
'to a <a href = "'.
|
||||
'http://pubsubhubbub.googlecode.com/'.
|
||||
'">PubSubHubBub</a> hub.'));
|
||||
$about);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ class RealtimePlugin extends Plugin
|
||||
$scripts = $this->_getScripts();
|
||||
|
||||
foreach ($scripts as $script) {
|
||||
$action->script($script);
|
||||
$action->script(common_path($script));
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
@ -18,7 +18,8 @@ display:none;
|
||||
}
|
||||
|
||||
.realtime-popup #form_notice label[for=notice_data-attach],
|
||||
.realtime-popup #form_notice #notice_data-attach {
|
||||
.realtime-popup #form_notice #notice_data-attach,
|
||||
.realtime-popup #form_notice label[for=notice_data-geo] {
|
||||
top:0;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @copyright 2009-2010 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
@ -41,6 +42,7 @@ define('TWITTERBRIDGEPLUGIN_VERSION', '0.9');
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
* @link http://twitter.com/
|
||||
@ -72,6 +74,27 @@ class TwitterBridgePlugin extends Plugin
|
||||
$m->connect('twitter/authorization',
|
||||
array('action' => 'twitterauthorization'));
|
||||
$m->connect('settings/twitter', array('action' => 'twittersettings'));
|
||||
$m->connect('main/twitterlogin', array('action' => 'twitterlogin'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a login tab for 'Sign in with Twitter'
|
||||
*
|
||||
* @param Action &action the current action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function onEndLoginGroupNav(&$action)
|
||||
{
|
||||
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(common_local_url('twitterlogin'),
|
||||
_('Twitter'),
|
||||
_('Login or register using Twitter'),
|
||||
'twitterlogin' === $action_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -108,6 +131,7 @@ class TwitterBridgePlugin extends Plugin
|
||||
switch ($cls) {
|
||||
case 'TwittersettingsAction':
|
||||
case 'TwitterauthorizationAction':
|
||||
case 'TwitterloginAction':
|
||||
include_once INSTALLDIR . '/plugins/TwitterBridge/' .
|
||||
strtolower(mb_substr($cls, 0, -6)) . '.php';
|
||||
return false;
|
||||
|
@ -19,10 +19,11 @@
|
||||
* 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 TwitterauthorizationAction
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copely <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @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/
|
||||
*/
|
||||
@ -41,15 +42,21 @@ require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
|
||||
* (Foreign_link) between the StatusNet user and Twitter user and stores the
|
||||
* access token and secret in the link.
|
||||
*
|
||||
* @category Twitter
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
*/
|
||||
class TwitterauthorizationAction extends Action
|
||||
{
|
||||
var $twuid = null;
|
||||
var $tw_fields = null;
|
||||
var $access_token = null;
|
||||
var $signin = null;
|
||||
|
||||
/**
|
||||
* Initialize class members. Looks for 'oauth_token' parameter.
|
||||
*
|
||||
@ -61,6 +68,7 @@ class TwitterauthorizationAction extends Action
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->signin = $this->boolean('signin');
|
||||
$this->oauth_token = $this->arg('oauth_token');
|
||||
|
||||
return true;
|
||||
@ -77,28 +85,61 @@ class TwitterauthorizationAction extends Action
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_m('Not logged in.'), 403);
|
||||
if (common_logged_in()) {
|
||||
$user = common_current_user();
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
// If there's already a foreign link record, it means we already
|
||||
// have an access token, and this is unecessary. So go back.
|
||||
|
||||
if (isset($flink)) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
// If there's already a foreign link record, it means we already
|
||||
// have an access token, and this is unecessary. So go back.
|
||||
// User was not logged in to StatusNet before
|
||||
|
||||
if (isset($flink)) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
$this->twuid = $this->trimmed('twuid');
|
||||
|
||||
// $this->oauth_token is only populated once Twitter authorizes our
|
||||
// request token. If it's empty we're at the beginning of the auth
|
||||
// process
|
||||
$this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'),
|
||||
'fullname' => $this->trimmed('tw_fields_fullname'));
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
$this->authorizeRequestToken();
|
||||
$this->access_token = new OAuthToken($this->trimmed('access_token_key'), $this->trimmed('access_token_secret'));
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->arg('create')) {
|
||||
if (!$this->boolean('license')) {
|
||||
$this->showForm(_('You can\'t register if you don\'t agree to the license.'),
|
||||
$this->trimmed('newname'));
|
||||
return;
|
||||
}
|
||||
$this->createNewUser();
|
||||
} else if ($this->arg('connect')) {
|
||||
$this->connectNewUser();
|
||||
} else {
|
||||
common_debug('Twitter Connect Plugin - ' .
|
||||
print_r($this->args, true));
|
||||
$this->showForm(_('Something weird happened.'),
|
||||
$this->trimmed('newname'));
|
||||
}
|
||||
} else {
|
||||
$this->saveAccessToken();
|
||||
// $this->oauth_token is only populated once Twitter authorizes our
|
||||
// request token. If it's empty we're at the beginning of the auth
|
||||
// process
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
$this->authorizeRequestToken();
|
||||
} else {
|
||||
$this->saveAccessToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +164,7 @@ class TwitterauthorizationAction extends Action
|
||||
$_SESSION['twitter_request_token'] = $req_tok->key;
|
||||
$_SESSION['twitter_request_token_secret'] = $req_tok->secret;
|
||||
|
||||
$auth_link = $client->getAuthorizeLink($req_tok);
|
||||
$auth_link = $client->getAuthorizeLink($req_tok, $this->signin);
|
||||
|
||||
} catch (OAuthClientException $e) {
|
||||
$msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
|
||||
@ -150,6 +191,8 @@ class TwitterauthorizationAction extends Action
|
||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
$twitter_user = null;
|
||||
|
||||
try {
|
||||
|
||||
$client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
|
||||
@ -165,40 +208,54 @@ class TwitterauthorizationAction extends Action
|
||||
$twitter_user = $client->verifyCredentials();
|
||||
|
||||
} catch (OAuthClientException $e) {
|
||||
$msg = sprintf('OAuth client cURL error - code: %1$s, msg: %2$s',
|
||||
$msg = sprintf('OAuth client error - code: %1$s, msg: %2$s',
|
||||
$e->getCode(), $e->getMessage());
|
||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
// Save the access token and Twitter user info
|
||||
if (common_logged_in()) {
|
||||
|
||||
$this->saveForeignLink($atok, $twitter_user);
|
||||
// Save the access token and Twitter user info
|
||||
|
||||
$user = common_current_user();
|
||||
$this->saveForeignLink($user->id, $twitter_user->id, $atok);
|
||||
save_twitter_user($twitter_user->id, $twitter_user->name);
|
||||
|
||||
} else {
|
||||
|
||||
$this->twuid = $twitter_user->id;
|
||||
$this->tw_fields = array("screen_name" => $twitter_user->screen_name,
|
||||
"name" => $twitter_user->name);
|
||||
$this->access_token = $atok;
|
||||
$this->tryLogin();
|
||||
}
|
||||
|
||||
// Clean up the the mess we made in the session
|
||||
|
||||
unset($_SESSION['twitter_request_token']);
|
||||
unset($_SESSION['twitter_request_token_secret']);
|
||||
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
if (common_logged_in()) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a Foreign_link between Twitter user and local user,
|
||||
* which includes the access token and secret.
|
||||
*
|
||||
* @param OAuthToken $access_token the access token to save
|
||||
* @param mixed $twitter_user twitter API user object
|
||||
* @param int $user_id StatusNet user ID
|
||||
* @param int $twuid Twitter user ID
|
||||
* @param OAuthToken $token the access token to save
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function saveForeignLink($access_token, $twitter_user)
|
||||
function saveForeignLink($user_id, $twuid, $access_token)
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$flink = new Foreign_link();
|
||||
|
||||
$flink->user_id = $user->id;
|
||||
$flink->foreign_id = $twitter_user->id;
|
||||
$flink->user_id = $user_id;
|
||||
$flink->foreign_id = $twuid;
|
||||
$flink->service = TWITTER_SERVICE;
|
||||
|
||||
$creds = TwitterOAuthClient::packToken($access_token);
|
||||
@ -214,10 +271,325 @@ class TwitterauthorizationAction extends Action
|
||||
|
||||
if (empty($flink_id)) {
|
||||
common_log_db_error($flink, 'INSERT', __FILE__);
|
||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||
$this->serverError(_('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
save_twitter_user($twitter_user->id, $twitter_user->screen_name);
|
||||
return $flink_id;
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->error) {
|
||||
$this->element('div', array('class' => 'error'), $this->error);
|
||||
} else {
|
||||
$this->element('div', 'instructions',
|
||||
sprintf(_('This is the first time you\'ve logged into %s so we must connect your Twitter account to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
|
||||
}
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Twitter Account Setup');
|
||||
}
|
||||
|
||||
function showForm($error=null, $username=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->username = $username;
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showPage()
|
||||
{
|
||||
parent::showPage();
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if (!empty($this->message_text)) {
|
||||
$this->element('p', null, $this->message);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_twitter_connect',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('twitterauthorization')));
|
||||
$this->elementStart('fieldset', array('id' => 'settings_twitter_connect_options'));
|
||||
$this->element('legend', null, _('Connection options'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->element('input', array('type' => 'checkbox',
|
||||
'id' => 'license',
|
||||
'class' => 'checkbox',
|
||||
'name' => 'license',
|
||||
'value' => 'true'));
|
||||
$this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
|
||||
$this->text(_('My text and files are available under '));
|
||||
$this->element('a', array('href' => common_config('license', 'url')),
|
||||
common_config('license', 'title'));
|
||||
$this->text(_(' except this private data: password, email address, IM address, phone number.'));
|
||||
$this->elementEnd('label');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->hidden('access_token_key', $this->access_token->key);
|
||||
$this->hidden('access_token_secret', $this->access_token->secret);
|
||||
$this->hidden('twuid', $this->twuid);
|
||||
$this->hidden('tw_fields_screen_name', $this->tw_fields['screen_name']);
|
||||
$this->hidden('tw_fields_name', $this->tw_fields['name']);
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->element('legend', null,
|
||||
_('Create new account'));
|
||||
$this->element('p', null,
|
||||
_('Create a new user with this nickname.'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('newname', _('New nickname'),
|
||||
($this->username) ? $this->username : '',
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('create', _('Create'));
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null,
|
||||
_('Connect existing account'));
|
||||
$this->element('p', null,
|
||||
_('If you already have an account, login with your username and password to connect it to your Twitter account.'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Existing nickname'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('password', _('Password'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('connect', _('Connect'));
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
function message($msg)
|
||||
{
|
||||
$this->message_text = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function createNewUser()
|
||||
{
|
||||
if (common_config('site', 'closed')) {
|
||||
$this->clientError(_('Registration not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$invite = null;
|
||||
|
||||
if (common_config('site', 'inviteonly')) {
|
||||
$code = $_SESSION['invitecode'];
|
||||
if (empty($code)) {
|
||||
$this->clientError(_('Registration not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$invite = Invitation::staticGet($code);
|
||||
|
||||
if (empty($invite)) {
|
||||
$this->clientError(_('Not a valid invitation code.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$nickname = $this->trimmed('newname');
|
||||
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => NICKNAME_FMT))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::allowed_nickname($nickname)) {
|
||||
$this->showForm(_('Nickname not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (User::staticGet('nickname', $nickname)) {
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$fullname = trim($this->tw_fields['name']);
|
||||
|
||||
$args = array('nickname' => $nickname, 'fullname' => $fullname);
|
||||
|
||||
if (!empty($invite)) {
|
||||
$args['code'] = $invite->code;
|
||||
}
|
||||
|
||||
$user = User::register($args);
|
||||
|
||||
$result = $this->saveForeignLink($user->id,
|
||||
$this->twuid,
|
||||
$this->access_token);
|
||||
|
||||
save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
|
||||
|
||||
if (!$result) {
|
||||
$this->serverError(_('Error connecting user to Twitter.'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_set_user($user);
|
||||
common_real_login(true);
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Registered new user $user->id from Twitter user $this->twuid");
|
||||
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
|
||||
function connectNewUser()
|
||||
{
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$password = $this->trimmed('password');
|
||||
|
||||
if (!common_check_user($nickname, $password)) {
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
|
||||
if (!empty($user)) {
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Legit user to connect to Twitter: $nickname");
|
||||
}
|
||||
|
||||
$result = $this->saveForeignLink($user->id,
|
||||
$this->twuid,
|
||||
$this->access_token);
|
||||
|
||||
save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
|
||||
|
||||
if (!$result) {
|
||||
$this->serverError(_('Error connecting user to Twitter.'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Connected Twitter user $this->twuid to local user $user->id");
|
||||
|
||||
common_set_user($user);
|
||||
common_real_login(true);
|
||||
|
||||
$this->goHome($user->nickname);
|
||||
}
|
||||
|
||||
function connectUser()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$result = $this->flinkUser($user->id, $this->twuid);
|
||||
|
||||
if (empty($result)) {
|
||||
$this->serverError(_('Error connecting user to Twitter.'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Connected Twitter user $this->twuid to local user $user->id");
|
||||
|
||||
// Return to Twitter connection settings tab
|
||||
common_redirect(common_local_url('twittersettings'), 303);
|
||||
}
|
||||
|
||||
function tryLogin()
|
||||
{
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Trying login for Twitter user $this->twuid.");
|
||||
|
||||
$flink = Foreign_link::getByForeignID($this->twuid,
|
||||
TWITTER_SERVICE);
|
||||
|
||||
if (!empty($flink)) {
|
||||
$user = $flink->getUser();
|
||||
|
||||
if (!empty($user)) {
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Logged in Twitter user $flink->foreign_id as user $user->id ($user->nickname)");
|
||||
|
||||
common_set_user($user);
|
||||
common_real_login(true);
|
||||
$this->goHome($user->nickname);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"No flink found for twuid: $this->twuid - new user");
|
||||
|
||||
$this->showForm(null, $this->bestNewNickname());
|
||||
}
|
||||
}
|
||||
|
||||
function goHome($nickname)
|
||||
{
|
||||
$url = common_get_returnto();
|
||||
if ($url) {
|
||||
// We don't have to return to it again
|
||||
common_set_returnto(null);
|
||||
} else {
|
||||
$url = common_local_url('all',
|
||||
array('nickname' =>
|
||||
$nickname));
|
||||
}
|
||||
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
function bestNewNickname()
|
||||
{
|
||||
if (!empty($this->tw_fields['name'])) {
|
||||
$nickname = $this->nicknamize($this->tw_fields['name']);
|
||||
if ($this->isNewNickname($nickname)) {
|
||||
return $nickname;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Given a string, try to make it work as a nickname
|
||||
|
||||
function nicknamize($str)
|
||||
{
|
||||
$str = preg_replace('/\W/', '', $str);
|
||||
$str = str_replace(array('-', '_'), '', $str);
|
||||
return strtolower($str);
|
||||
}
|
||||
|
||||
function isNewNickname($str)
|
||||
{
|
||||
if (!Validate::string($str, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => NICKNAME_FMT))) {
|
||||
return false;
|
||||
}
|
||||
if (!User::allowed_nickname($str)) {
|
||||
return false;
|
||||
}
|
||||
if (User::staticGet('nickname', $str)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
97
plugins/TwitterBridge/twitterlogin.php
Normal file
97
plugins/TwitterBridge/twitterlogin.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* 'Sign in with Twitter' login page
|
||||
*
|
||||
* 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 Login
|
||||
* @package StatusNet
|
||||
* @author Julien Chaumond <chaumond@gmail.com>
|
||||
* @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') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
|
||||
|
||||
/**
|
||||
* Page for logging in with Twitter
|
||||
*
|
||||
* @category Login
|
||||
* @package StatusNet
|
||||
* @author Julien Chaumond <chaumond@gmail.com>
|
||||
* @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/
|
||||
*
|
||||
* @see SettingsAction
|
||||
*/
|
||||
|
||||
class TwitterloginAction extends Action
|
||||
{
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (common_is_real_login()) {
|
||||
$this->clientError(_('Already logged in.'));
|
||||
}
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Twitter Login');
|
||||
}
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Login with your Twitter account');
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
$instr = $this->getInstructions();
|
||||
$output = common_markup_to_html($instr);
|
||||
$this->elementStart('div', 'instructions');
|
||||
$this->raw($output);
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('a', array('href' => common_local_url('twitterauthorization',
|
||||
null,
|
||||
array('signin' => true))));
|
||||
$this->element('img', array('src' => common_path('plugins/TwitterBridge/Sign-in-with-Twitter-lighter.png'),
|
||||
'alt' => 'Sign in with Twitter'));
|
||||
$this->elementEnd('a');
|
||||
}
|
||||
|
||||
function showLocalNav()
|
||||
{
|
||||
$nav = new LoginGroupNav($this);
|
||||
$nav->show();
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ class TwitterOAuthClient extends OAuthClient
|
||||
{
|
||||
public static $requestTokenURL = 'https://twitter.com/oauth/request_token';
|
||||
public static $authorizeURL = 'https://twitter.com/oauth/authorize';
|
||||
public static $signinUrl = 'https://twitter.com/oauth/authenticate';
|
||||
public static $accessTokenURL = 'https://twitter.com/oauth/access_token';
|
||||
|
||||
/**
|
||||
@ -97,9 +98,11 @@ class TwitterOAuthClient extends OAuthClient
|
||||
*
|
||||
* @return the link
|
||||
*/
|
||||
function getAuthorizeLink($request_token)
|
||||
function getAuthorizeLink($request_token, $signin = false)
|
||||
{
|
||||
return parent::getAuthorizeLink(self::$authorizeURL,
|
||||
$url = ($signin) ? self::$signinUrl : self::$authorizeURL;
|
||||
|
||||
return parent::getAuthorizeLink($url,
|
||||
$request_token,
|
||||
common_local_url('twitterauthorization'));
|
||||
}
|
||||
|
@ -121,8 +121,35 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
$this->elementEnd('p');
|
||||
$this->element('p', 'form_note',
|
||||
_m('Connected Twitter account'));
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->submit('remove', _m('Remove'));
|
||||
$this->elementStart('fieldset');
|
||||
|
||||
$this->element('legend', null, _m('Disconnect my account from Twitter'));
|
||||
|
||||
if (!$user->password) {
|
||||
|
||||
$this->elementStart('p', array('class' => 'form_guide'));
|
||||
$this->text(_m('Disconnecting your Twitter ' .
|
||||
'could make it impossible to log in! Please '));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('passwordsettings')),
|
||||
_m('set a password'));
|
||||
|
||||
$this->text(_m(' first.'));
|
||||
$this->elementEnd('p');
|
||||
} else {
|
||||
|
||||
$note = _m('Keep your %1$s account but disconnect from Twitter. ' .
|
||||
'You can use your %1$s password to log in.');
|
||||
|
||||
$site = common_config('site', 'name');
|
||||
|
||||
$this->element('p', 'instructions',
|
||||
sprintf($note, $site));
|
||||
|
||||
$this->submit('disconnect', _m('Disconnect'));
|
||||
}
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
@ -205,7 +232,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
if ($this->arg('save')) {
|
||||
$this->savePreferences();
|
||||
} else if ($this->arg('remove')) {
|
||||
} else if ($this->arg('disconnect')) {
|
||||
$this->removeTwitterAccount();
|
||||
} else {
|
||||
$this->showForm(_m('Unexpected form submission.'));
|
||||
@ -231,7 +258,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
return;
|
||||
}
|
||||
|
||||
$this->showForm(_m('Twitter account removed.'), true);
|
||||
$this->showForm(_m('Twitter account disconnected.'), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,10 +45,12 @@ function read_input_line($prompt)
|
||||
if (CONSOLE_INTERACTIVE) {
|
||||
if (CONSOLE_READLINE) {
|
||||
$line = readline($prompt);
|
||||
readline_add_history($line);
|
||||
if (defined('CONSOLE_HISTORY')) {
|
||||
// Save often; it's easy to hit fatal errors.
|
||||
readline_write_history(CONSOLE_HISTORY);
|
||||
if (trim($line) != '') {
|
||||
readline_add_history($line);
|
||||
if (defined('CONSOLE_HISTORY')) {
|
||||
// Save often; it's easy to hit fatal errors.
|
||||
readline_write_history(CONSOLE_HISTORY);
|
||||
}
|
||||
}
|
||||
return $line;
|
||||
} else {
|
||||
|
85
scripts/queuectl.php
Executable file
85
scripts/queuectl.php
Executable file
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env php
|
||||
<?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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends control signals to running queue daemons.
|
||||
*
|
||||
* @author Brion Vibber <brion@status.net>
|
||||
* @package QueueHandler
|
||||
*/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||
|
||||
$shortoptions = 'ur';
|
||||
$longoptions = array('update', 'restart', 'stop');
|
||||
|
||||
$helptext = <<<END_OF_QUEUECTL_HELP
|
||||
Send broadcast events to control any running queue handlers.
|
||||
(Currently for Stomp queues only.)
|
||||
|
||||
Events relating to current site (as selected with -s etc)
|
||||
-u --update Announce new site or updated configuration. Running
|
||||
daemons will start subscribing to any new queues needed
|
||||
for this site.
|
||||
|
||||
Global events:
|
||||
-r --restart Graceful restart of all threads
|
||||
--stop Graceful shutdown of all threads
|
||||
|
||||
END_OF_QUEUECTL_HELP;
|
||||
|
||||
require_once INSTALLDIR.'/scripts/commandline.inc';
|
||||
|
||||
function doSendControl($message, $event, $param='')
|
||||
{
|
||||
print $message;
|
||||
$qm = QueueManager::get();
|
||||
if ($qm->sendControlSignal($event, $param)) {
|
||||
print " sent.\n";
|
||||
} else {
|
||||
print " FAILED.\n";
|
||||
}
|
||||
}
|
||||
|
||||
$actions = 0;
|
||||
|
||||
if (have_option('u') || have_option('--update')) {
|
||||
$nickname = common_config('site', 'nickname');
|
||||
doSendControl("Sending site update signal to queue daemons for $nickname",
|
||||
"update", $nickname);
|
||||
$actions++;
|
||||
}
|
||||
|
||||
if (have_option('r') || have_option('--restart')) {
|
||||
doSendControl("Sending graceful restart signal to queue daemons...",
|
||||
"restart");
|
||||
$actions++;
|
||||
}
|
||||
|
||||
if (have_option('--stop')) {
|
||||
doSendControl("Sending graceful shutdown signal to queue daemons...",
|
||||
"shutdown");
|
||||
$actions++;
|
||||
}
|
||||
|
||||
if (!$actions) {
|
||||
show_help();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||
|
||||
$shortoptions = 'fi:at:';
|
||||
$longoptions = array('id=', 'foreground', 'all', 'threads=', 'skip-xmpp', 'xmpp-only');
|
||||
$longoptions = array('id=', 'foreground', 'all', 'threads=');
|
||||
|
||||
/**
|
||||
* Attempts to get a count of the processors available on the current system
|
||||
@ -115,7 +115,7 @@ class QueueDaemon extends SpawningDaemon
|
||||
|
||||
$this->log(LOG_INFO, 'terminating normally');
|
||||
|
||||
return true;
|
||||
return $master->respawn ? self::EXIT_RESTART : self::EXIT_SHUTDOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,13 +163,6 @@ if (!$threads) {
|
||||
$daemonize = !(have_option('f') || have_option('--foreground'));
|
||||
$all = have_option('a') || have_option('--all');
|
||||
|
||||
if (have_option('--skip-xmpp')) {
|
||||
define('XMPP_EMERGENCY_FLAG', true);
|
||||
}
|
||||
if (have_option('--xmpp-only')) {
|
||||
define('XMPP_ONLY_FLAG', true);
|
||||
}
|
||||
|
||||
$daemon = new QueueDaemon($id, $daemonize, $threads, $all);
|
||||
$daemon->runOnce();
|
||||
|
||||
|
82
scripts/sendemail.php
Executable file
82
scripts/sendemail.php
Executable file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, 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/>.
|
||||
*/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||
|
||||
$shortoptions = 'i:n:';
|
||||
$longoptions = array('id=', 'nickname=', 'subject=');
|
||||
|
||||
$helptext = <<<END_OF_USEREMAIL_HELP
|
||||
sendemail.php [options] < <message body>
|
||||
Sends given email text to user.
|
||||
|
||||
-i --id id of the user to query
|
||||
-n --nickname nickname of the user to query
|
||||
--subject mail subject line (required)
|
||||
|
||||
END_OF_USEREMAIL_HELP;
|
||||
|
||||
require_once INSTALLDIR.'/scripts/commandline.inc';
|
||||
|
||||
if (have_option('i', 'id')) {
|
||||
$id = get_option_value('i', 'id');
|
||||
$user = User::staticGet('id', $id);
|
||||
if (empty($user)) {
|
||||
print "Can't find user with ID $id\n";
|
||||
exit(1);
|
||||
}
|
||||
} else if (have_option('n', 'nickname')) {
|
||||
$nickname = get_option_value('n', 'nickname');
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
if (empty($user)) {
|
||||
print "Can't find user with nickname '$nickname'\n";
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
print "You must provide a user by --id or --nickname\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($user->email)) {
|
||||
// @fixme unconfirmed address?
|
||||
print "No email registered for user '$user->nickname'\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!have_option('subject')) {
|
||||
echo "You must provide a subject line for the mail in --subject='...' param.\n";
|
||||
exit(1);
|
||||
}
|
||||
$subject = get_option_value('subject');
|
||||
|
||||
if (posix_isatty(STDIN)) {
|
||||
print "You must provide message input on stdin!\n";
|
||||
exit(1);
|
||||
}
|
||||
$body = file_get_contents('php://stdin');
|
||||
|
||||
print "Sending to $user->email...";
|
||||
if (mail_to_user($user, $subject, $body)) {
|
||||
print " done\n";
|
||||
} else {
|
||||
print " failed.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
@ -11,4 +11,8 @@ export AVATARBASE=/var/www/avatar.example.net
|
||||
export BACKGROUNDBASE=/var/www/background.example.net
|
||||
export FILEBASE=/var/www/file.example.net
|
||||
export PWDGEN="pwgen 20"
|
||||
|
||||
export PHPBASE=/var/www/statusnet
|
||||
export WILDCARD=example.net
|
||||
export MAILTEMPLATE=/etc/statusnet/newsite-mail.txt
|
||||
export MAILSUBJECT="Your new StatusNet site"
|
||||
export POSTINSTALL=/etc/statusnet/morestuff.sh
|
||||
|
@ -2,9 +2,23 @@
|
||||
|
||||
source /etc/statusnet/setup.cfg
|
||||
|
||||
export nickname=$1
|
||||
export sitename=$2
|
||||
# setup_status_net.sh mysite 'My Site' '1user' 'owner@example.com' 'Firsty McLastname'
|
||||
|
||||
export nickname="$1"
|
||||
export sitename="$2"
|
||||
export tags="$3"
|
||||
export email="$4"
|
||||
export fullname="$5"
|
||||
|
||||
# Fixme: if this is changed later we need to update profile URLs
|
||||
# for the created user.
|
||||
export server="$nickname.$WILDCARD"
|
||||
|
||||
# End-user info
|
||||
export userpass=`$PWDGEN`
|
||||
export roles="administrator moderator owner"
|
||||
|
||||
# DB info
|
||||
export password=`$PWDGEN`
|
||||
export database=$nickname$DBBASE
|
||||
export username=$nickname$USERBASE
|
||||
@ -21,8 +35,8 @@ mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS
|
||||
|
||||
GRANT ALL ON $database.* TO '$username'@'localhost' IDENTIFIED BY '$password';
|
||||
GRANT ALL ON $database.* TO '$username'@'%' IDENTIFIED BY '$password';
|
||||
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created)
|
||||
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now());
|
||||
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created, tags)
|
||||
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now(), '$tags');
|
||||
|
||||
ENDOFCOMMANDS
|
||||
|
||||
@ -30,3 +44,39 @@ for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
|
||||
mkdir $top/$nickname
|
||||
chmod a+w $top/$nickname
|
||||
done
|
||||
|
||||
php $PHPBASE/scripts/registeruser.php \
|
||||
-s"$server" \
|
||||
-n"$nickname" \
|
||||
-f"$fullname" \
|
||||
-w"$userpass" \
|
||||
-e"$email"
|
||||
|
||||
for role in $roles
|
||||
do
|
||||
php $PHPBASE/scripts/userrole.php \
|
||||
-s"$server" \
|
||||
-n"$nickname" \
|
||||
-r"$role"
|
||||
done
|
||||
|
||||
if [ -f "$MAILTEMPLATE" ]
|
||||
then
|
||||
# fixme how safe is this? are sitenames sanitized?
|
||||
cat $MAILTEMPLATE | \
|
||||
sed "s/\$nickname/$nickname/" | \
|
||||
sed "s/\$sitename/$sitename/" | \
|
||||
sed "s/\$userpass/$userpass/" | \
|
||||
php $PHPBASE/scripts/sendemail.php \
|
||||
-s"$server" \
|
||||
-n"$nickname" \
|
||||
--subject="$MAILSUBJECT"
|
||||
else
|
||||
echo "No mail template, not sending email."
|
||||
fi
|
||||
|
||||
if [ -f "$POSTINSTALL" ]
|
||||
then
|
||||
echo "Running $POSTINSTALL ..."
|
||||
source "$POSTINSTALL"
|
||||
fi
|
||||
|
@ -56,7 +56,7 @@ class XMPPDaemon extends SpawningDaemon
|
||||
|
||||
common_log(LOG_INFO, 'terminating normally');
|
||||
|
||||
return true;
|
||||
return $master->respawn ? self::EXIT_RESTART : self::EXIT_SHUTDOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
22
tests/oauth/README
Normal file
22
tests/oauth/README
Normal file
@ -0,0 +1,22 @@
|
||||
Some very rough test scripts for hitting up the OAuth endpoints.
|
||||
|
||||
Note: this works best if you register an OAuth application, leaving
|
||||
the callback URL blank.
|
||||
|
||||
Put your instance info and consumer key and secret in oauth.ini
|
||||
|
||||
Example usage:
|
||||
--------------
|
||||
|
||||
php getrequesttoken.php
|
||||
|
||||
Gets a request token, token secret and a url to authorize it. Once
|
||||
you authorize the request token you can exchange it for an access token...
|
||||
|
||||
php exchangetokens.php --oauth_token=b9a79548a88c1aa9a5bea73103c6d41d --token_secret=4a47d9337fc0202a14ab552e17a3b657
|
||||
|
||||
Once you have your access token, go ahead and try a protected API
|
||||
resource:
|
||||
|
||||
php verifycreds.php --oauth_token=cf2de7665f0dda0a82c2dc39b01be7f9 --token_secret=4524c3b712200138e1a4cff2e9ca83d8
|
||||
|
105
tests/oauth/exchangetokens.php
Executable file
105
tests/oauth/exchangetokens.php
Executable file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, 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/>.
|
||||
*/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||
|
||||
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||
|
||||
$ini = parse_ini_file("oauth.ini");
|
||||
|
||||
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||
|
||||
$at_endpoint = $ini['apiroot'] . $ini['access_token_url'];
|
||||
|
||||
$shortoptions = 't:s:';
|
||||
$longoptions = array('oauth_token=', 'token_secret=');
|
||||
|
||||
$helptext = <<<END_OF_ETOKENS_HELP
|
||||
exchangetokens.php [options]
|
||||
Exchange an authorized OAuth request token for an access token
|
||||
|
||||
-t --oauth_token authorized request token
|
||||
-s --token_secret authorized request token secret
|
||||
|
||||
END_OF_ETOKENS_HELP;
|
||||
|
||||
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||
|
||||
$token = null;
|
||||
$token_secret = null;
|
||||
|
||||
if (have_option('t', 'oauth_token')) {
|
||||
$token = get_option_value('oauth_token');
|
||||
}
|
||||
|
||||
if (have_option('s', 'token_secret')) {
|
||||
$token_secret = get_option_value('s', 'token_secret');
|
||||
}
|
||||
|
||||
if (empty($token)) {
|
||||
print "Please specify a request token.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($token_secret)) {
|
||||
print "Please specify a request token secret.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$rt = new OAuthToken($token, $token_secret);
|
||||
common_debug("Exchange request token = " . var_export($rt, true));
|
||||
|
||||
$parsed = parse_url($at_endpoint);
|
||||
$params = array();
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, $rt, "GET", $at_endpoint, $params);
|
||||
$req_req->sign_request($hmac_method, $test_consumer, $rt);
|
||||
|
||||
$r = httpRequest($req_req->to_url());
|
||||
|
||||
common_debug("Exchange request token = " . var_export($rt, true));
|
||||
common_debug("Exchange tokens URL: " . $req_req->to_url());
|
||||
|
||||
$body = $r->getBody();
|
||||
|
||||
$token_stuff = array();
|
||||
parse_str($body, $token_stuff);
|
||||
|
||||
print 'Access token : ' . $token_stuff['oauth_token'] . "\n";
|
||||
print 'Access token secret : ' . $token_stuff['oauth_token_secret'] . "\n";
|
||||
|
||||
function httpRequest($url)
|
||||
{
|
||||
$request = HTTPClient::start();
|
||||
|
||||
$request->setConfig(array(
|
||||
'follow_redirects' => true,
|
||||
'connect_timeout' => 120,
|
||||
'timeout' => 120,
|
||||
'ssl_verify_peer' => false,
|
||||
'ssl_verify_host' => false
|
||||
));
|
||||
|
||||
return $request->get($url);
|
||||
}
|
||||
|
71
tests/oauth/getrequesttoken.php
Executable file
71
tests/oauth/getrequesttoken.php
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, 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/>.
|
||||
*/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||
|
||||
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||
|
||||
$ini = parse_ini_file("oauth.ini");
|
||||
|
||||
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||
|
||||
$rt_endpoint = $ini['apiroot'] . $ini['request_token_url'];
|
||||
|
||||
$parsed = parse_url($rt_endpoint);
|
||||
$params = array();
|
||||
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, NULL, "GET", $rt_endpoint, $params);
|
||||
$req_req->sign_request($hmac_method, $test_consumer, NULL);
|
||||
|
||||
$r = httpRequest($req_req->to_url());
|
||||
|
||||
$body = $r->getBody();
|
||||
|
||||
$token_stuff = array();
|
||||
parse_str($body, $token_stuff);
|
||||
|
||||
$authurl = $ini['apiroot'] . $ini['authorize_url'] . '?oauth_token=' . $token_stuff['oauth_token'];
|
||||
|
||||
print 'Request token : ' . $token_stuff['oauth_token'] . "\n";
|
||||
print 'Request token secret : ' . $token_stuff['oauth_token_secret'] . "\n";
|
||||
print "Authorize URL : $authurl\n";
|
||||
|
||||
//var_dump($req_req);
|
||||
|
||||
function httpRequest($url)
|
||||
{
|
||||
$request = HTTPClient::start();
|
||||
|
||||
$request->setConfig(array(
|
||||
'follow_redirects' => true,
|
||||
'connect_timeout' => 120,
|
||||
'timeout' => 120,
|
||||
'ssl_verify_peer' => false,
|
||||
'ssl_verify_host' => false
|
||||
));
|
||||
|
||||
return $request->get($url);
|
||||
}
|
||||
|
10
tests/oauth/oauth.ini
Normal file
10
tests/oauth/oauth.ini
Normal file
@ -0,0 +1,10 @@
|
||||
; Setup OAuth info here
|
||||
apiroot = "http://YOURSTATUSNET/api"
|
||||
|
||||
request_token_url = "/oauth/request_token"
|
||||
authorize_url = "/oauth/authorize"
|
||||
access_token_url = "/oauth/access_token"
|
||||
|
||||
consumer_key = "b748968e9bea81a53f3a3c15aa0c686f"
|
||||
consumer_secret = "5434e18cce05d9e53cdd48029a62fa41"
|
||||
|
115
tests/oauth/statusupdate.php
Normal file
115
tests/oauth/statusupdate.php
Normal file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - a 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/>.
|
||||
**/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||
|
||||
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||
|
||||
$shortoptions = 'o:s:u:';
|
||||
$longoptions = array('oauth_token=', 'token_secret=', 'update=');
|
||||
|
||||
$helptext = <<<END_OF_VERIFY_HELP
|
||||
statusupdate.php [options]
|
||||
Update your status using OAuth
|
||||
|
||||
-o --oauth_token access token
|
||||
-s --token_secret access token secret
|
||||
-u --update status update
|
||||
|
||||
|
||||
END_OF_VERIFY_HELP;
|
||||
|
||||
$token = null;
|
||||
$token_secret = null;
|
||||
$update = null;
|
||||
|
||||
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||
|
||||
if (have_option('o', 'oauth_token')) {
|
||||
$token = get_option_value('oauth_token');
|
||||
}
|
||||
|
||||
if (have_option('s', 'token_secret')) {
|
||||
$token_secret = get_option_value('s', 'token_secret');
|
||||
}
|
||||
|
||||
if (have_option('u', 'update')) {
|
||||
$update = get_option_value('u', 'update');
|
||||
}
|
||||
|
||||
if (empty($token)) {
|
||||
print "Please specify an access token.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($token_secret)) {
|
||||
print "Please specify an access token secret.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($update)) {
|
||||
print "You forgot to update your status!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$ini = parse_ini_file("oauth.ini");
|
||||
|
||||
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||
|
||||
$endpoint = $ini['apiroot'] . '/statuses/update.xml';
|
||||
|
||||
print "$endpoint\n";
|
||||
|
||||
$at = new OAuthToken($token, $token_secret);
|
||||
|
||||
$parsed = parse_url($endpoint);
|
||||
$params = array();
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$params['status'] = $update;
|
||||
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, $at, 'POST', $endpoint, $params);
|
||||
$req_req->sign_request($hmac_method, $test_consumer, $at);
|
||||
|
||||
$r = httpRequest($req_req->to_url());
|
||||
|
||||
$body = $r->getBody();
|
||||
|
||||
print "$body\n";
|
||||
|
||||
//print $req_req->to_url() . "\n\n";
|
||||
|
||||
function httpRequest($url)
|
||||
{
|
||||
$request = HTTPClient::start();
|
||||
|
||||
$request->setConfig(array(
|
||||
'follow_redirects' => true,
|
||||
'connect_timeout' => 120,
|
||||
'timeout' => 120,
|
||||
'ssl_verify_peer' => false,
|
||||
'ssl_verify_host' => false
|
||||
));
|
||||
|
||||
return $request->post($url);
|
||||
}
|
||||
|
101
tests/oauth/verifycreds.php
Executable file
101
tests/oauth/verifycreds.php
Executable file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, 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/>.
|
||||
*/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
|
||||
|
||||
require_once INSTALLDIR . '/extlib/OAuth.php';
|
||||
|
||||
$shortoptions = 'o:s:';
|
||||
$longoptions = array('oauth_token=', 'token_secret=');
|
||||
|
||||
$helptext = <<<END_OF_VERIFY_HELP
|
||||
verifycreds.php [options]
|
||||
Use an access token to verify credentials thru the api
|
||||
|
||||
-o --oauth_token access token
|
||||
-s --token_secret access token secret
|
||||
|
||||
END_OF_VERIFY_HELP;
|
||||
|
||||
$token = null;
|
||||
$token_secret = null;
|
||||
|
||||
require_once INSTALLDIR . '/scripts/commandline.inc';
|
||||
|
||||
if (have_option('o', 'oauth_token')) {
|
||||
$token = get_option_value('oauth_token');
|
||||
}
|
||||
|
||||
if (have_option('s', 'token_secret')) {
|
||||
$token_secret = get_option_value('s', 'token_secret');
|
||||
}
|
||||
|
||||
if (empty($token)) {
|
||||
print "Please specify an access token.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($token_secret)) {
|
||||
print "Please specify an access token secret.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$ini = parse_ini_file("oauth.ini");
|
||||
|
||||
$test_consumer = new OAuthConsumer($ini['consumer_key'], $ini['consumer_secret']);
|
||||
|
||||
$endpoint = $ini['apiroot'] . '/account/verify_credentials.xml';
|
||||
|
||||
print "$endpoint\n";
|
||||
|
||||
$at = new OAuthToken($token, $token_secret);
|
||||
|
||||
$parsed = parse_url($endpoint);
|
||||
$params = array();
|
||||
parse_str($parsed['query'], $params);
|
||||
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$req_req = OAuthRequest::from_consumer_and_token($test_consumer, $at, "GET", $endpoint, $params);
|
||||
$req_req->sign_request($hmac_method, $test_consumer, $at);
|
||||
|
||||
$r = httpRequest($req_req->to_url());
|
||||
|
||||
$body = $r->getBody();
|
||||
|
||||
print "$body\n";
|
||||
|
||||
//print $req_req->to_url() . "\n\n";
|
||||
|
||||
function httpRequest($url)
|
||||
{
|
||||
$request = HTTPClient::start();
|
||||
|
||||
$request->setConfig(array(
|
||||
'follow_redirects' => true,
|
||||
'connect_timeout' => 120,
|
||||
'timeout' => 120,
|
||||
'ssl_verify_peer' => false,
|
||||
'ssl_verify_host' => false
|
||||
));
|
||||
|
||||
return $request->get($url);
|
||||
}
|
||||
|
@ -177,7 +177,8 @@ font-weight:bold;
|
||||
#form_password_recover legend,
|
||||
#form_password_change legend,
|
||||
.form_entity_block legend,
|
||||
#form_filter_bytag legend {
|
||||
#form_filter_bytag legend,
|
||||
#apioauthauthorize_allowdeny {
|
||||
display:none;
|
||||
}
|
||||
|
||||
@ -895,9 +896,63 @@ font-weight:normal;
|
||||
margin-right:11px;
|
||||
}
|
||||
|
||||
/*applications*/
|
||||
.applications {
|
||||
margin-bottom:18px;
|
||||
float:left;
|
||||
width:100%;
|
||||
}
|
||||
.applications li {
|
||||
list-style-type:none;
|
||||
}
|
||||
.application img,
|
||||
#showapplication .entity_profile img,
|
||||
.form_data #application_icon img,
|
||||
#apioauthauthorize .form_data img {
|
||||
max-width:96px;
|
||||
max-height:96px;
|
||||
}
|
||||
#apioauthauthorize .form_data img {
|
||||
margin-right:18px;
|
||||
float:left;
|
||||
}
|
||||
#showapplication .entity_profile {
|
||||
width:68%;
|
||||
}
|
||||
#showapplication .entity_profile .entity_fn {
|
||||
margin-left:0;
|
||||
}
|
||||
#showapplication .entity_profile .entity_fn .fn:before,
|
||||
#showapplication .entity_profile .entity_fn .fn:after {
|
||||
content:'';
|
||||
}
|
||||
#showapplication .entity_data {
|
||||
clear:both;
|
||||
margin-bottom:18px;
|
||||
}
|
||||
#showapplication .entity_data h2 {
|
||||
display:none;
|
||||
}
|
||||
#showapplication .entity_data dl {
|
||||
margin-bottom:18px;
|
||||
}
|
||||
#showapplication .entity_data dt {
|
||||
font-weight:bold;
|
||||
}
|
||||
#showapplication .entity_data dd {
|
||||
margin-left:1.795%;
|
||||
font-family:monospace;
|
||||
font-size:1.3em;
|
||||
}
|
||||
.form_data #application_types label.radio,
|
||||
.form_data #default_access_types label.radio {
|
||||
width:14.5%;
|
||||
}
|
||||
|
||||
/* NOTICE */
|
||||
.notice,
|
||||
.profile {
|
||||
.profile,
|
||||
.application {
|
||||
position:relative;
|
||||
padding-top:11px;
|
||||
padding-bottom:11px;
|
||||
@ -989,7 +1044,12 @@ margin-left:0;
|
||||
margin-left:110px;
|
||||
}
|
||||
#shownotice .notice .entry-title {
|
||||
margin-left:110px;
|
||||
font-size:2.2em;
|
||||
min-height:123px;
|
||||
}
|
||||
#shownotice .notice div.entry-content {
|
||||
margin-left:0;
|
||||
}
|
||||
|
||||
.notice p.entry-content {
|
||||
|
54
theme/base/css/uap.css
Normal file
54
theme/base/css/uap.css
Normal file
@ -0,0 +1,54 @@
|
||||
/** Universal Ad Package styles:
|
||||
* Medium Rectangle 300x250
|
||||
* Rectangle 180x150
|
||||
* Leaderboard 728x90
|
||||
* Wide Skyscraper 160x600
|
||||
*
|
||||
* @package StatusNet
|
||||
* @author Sarven Capadisli <csarven@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/
|
||||
*/
|
||||
|
||||
|
||||
.ad {
|
||||
border:1px solid #CCC;
|
||||
float:left;
|
||||
}
|
||||
|
||||
#ad_medium-rectangle {
|
||||
width:300px;
|
||||
height:250px;
|
||||
|
||||
margin-left:1.35%;
|
||||
margin-bottom:18px;
|
||||
}
|
||||
|
||||
#ad_rectangle {
|
||||
width:180px;
|
||||
height:150px;
|
||||
|
||||
float:none;
|
||||
clear:both;
|
||||
margin:0 auto;
|
||||
margin-bottom:29px;
|
||||
}
|
||||
|
||||
#ad_leaderboard {
|
||||
width:728px;
|
||||
height:90px;
|
||||
|
||||
margin:0 auto 18px;
|
||||
float:none;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
#ad_wide-skyscraper {
|
||||
width:160px;
|
||||
height:600px;
|
||||
|
||||
float:right;
|
||||
margin-top:18px;
|
||||
margin-right:8.25%;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user