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>
|
EndAddressData: At the end of <address>
|
||||||
- $action: the current action
|
- $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
|
StartLoginGroupNav: Before showing the login and register navigation menu
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
|
46
README
46
README
@ -2,8 +2,8 @@
|
|||||||
README
|
README
|
||||||
------
|
------
|
||||||
|
|
||||||
StatusNet 0.9.0 ("Stand") Beta 3
|
StatusNet 0.9.0 ("Stand") Beta 4
|
||||||
20 Jan 2010
|
27 Jan 2010
|
||||||
|
|
||||||
This is the README file for StatusNet (formerly Laconica), the Open
|
This is the README file for StatusNet (formerly Laconica), the Open
|
||||||
Source microblogging platform. It includes installation instructions,
|
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
|
needs as a parameter the install path; if you run it from the
|
||||||
StatusNet dir, "." should suffice.
|
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
|
* xmppdaemon.php - listens for new XMPP messages from users and stores
|
||||||
them as notices in the database.
|
them as notices in the database; also pulls queued XMPP output from
|
||||||
* jabberqueuehandler.php - sends queued notices in the database to
|
queuedaemon.php to push out to clients.
|
||||||
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.
|
|
||||||
|
|
||||||
Note that these queue daemons are pretty raw, and need your care. In
|
These two daemons will automatically restart in most cases of failure
|
||||||
particular, they leak memory, and you may want to restart them on a
|
including memory leaks (if a memory_limit is set), but may still die
|
||||||
regular (daily or so) basis with a cron job. Also, if they lose
|
or behave oddly if they lose connections to the XMPP or queue servers.
|
||||||
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',
|
It may be a good idea to use a daemon-monitoring service, like 'monit',
|
||||||
to check their status and keep them running.
|
to check their status and keep them running.
|
||||||
|
|
||||||
All the daemons write their process IDs (pids) to /var/run/ by
|
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
|
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"
|
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
|
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
|
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.
|
compile the ".po" files into ".mo" files, however.
|
||||||
|
|
||||||
Contributions of translation information to StatusNet are very easy:
|
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
|
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.
|
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
|
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
|
should enable it only after you've convinced yourself that
|
||||||
it is safe. Default is 'false'.
|
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
|
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'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -108,5 +108,20 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
|||||||
$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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether this API resource requires auth. Overloaded to look
|
* Determines whether this API resource requires auth. Overloaded to look
|
||||||
* return true in case source_id and source_screen_name are both empty
|
* 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 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 Mike Cochrane <mikec@mikenz.geek.nz>
|
||||||
* @author Robin Millette <robin@millette.info>
|
* @author Robin Millette <robin@millette.info>
|
||||||
* @author Zach Copley <zach@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
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
@ -79,12 +79,16 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
$this->user = $this->auth_user;
|
|
||||||
$this->status = $this->trimmed('status');
|
$this->status = $this->trimmed('status');
|
||||||
$this->source = $this->trimmed('source');
|
$this->source = $this->trimmed('source');
|
||||||
$this->lat = $this->trimmed('lat');
|
$this->lat = $this->trimmed('lat');
|
||||||
$this->lon = $this->trimmed('long');
|
$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)) {
|
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
|
||||||
$this->source = 'api';
|
$this->source = 'api';
|
||||||
}
|
}
|
||||||
@ -140,7 +144,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->user)) {
|
if (empty($this->auth_user)) {
|
||||||
$this->clientError(_('No such user.'), 404, $this->format);
|
$this->clientError(_('No such user.'), 404, $this->format);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -167,7 +171,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
// Check for commands
|
// Check for commands
|
||||||
|
|
||||||
$inter = new CommandInterpreter();
|
$inter = new CommandInterpreter();
|
||||||
$cmd = $inter->handle_command($this->user, $status_shortened);
|
$cmd = $inter->handle_command($this->auth_user, $status_shortened);
|
||||||
|
|
||||||
if ($cmd) {
|
if ($cmd) {
|
||||||
|
|
||||||
@ -179,7 +183,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
// And, it returns your last status whether the cmd was successful
|
// And, it returns your last status whether the cmd was successful
|
||||||
// or not!
|
// or not!
|
||||||
|
|
||||||
$this->notice = $this->user->getCurrentNotice();
|
$this->notice = $this->auth_user->getCurrentNotice();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -206,7 +210,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
$upload = null;
|
$upload = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$upload = MediaFile::fromUpload('media', $this->user);
|
$upload = MediaFile::fromUpload('media', $this->auth_user);
|
||||||
} catch (ClientException $ce) {
|
} catch (ClientException $ce) {
|
||||||
$this->clientError($ce->getMessage());
|
$this->clientError($ce->getMessage());
|
||||||
return;
|
return;
|
||||||
@ -229,19 +233,19 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
|
|
||||||
$options = array('reply_to' => $reply_to);
|
$options = array('reply_to' => $reply_to);
|
||||||
|
|
||||||
if ($this->user->shareLocation()) {
|
if ($this->auth_user->shareLocation()) {
|
||||||
|
|
||||||
$locOptions = Notice::locationOptions($this->lat,
|
$locOptions = Notice::locationOptions($this->lat,
|
||||||
$this->lon,
|
$this->lon,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
$this->user->getProfile());
|
$this->auth_user->getProfile());
|
||||||
|
|
||||||
$options = array_merge($options, $locOptions);
|
$options = array_merge($options, $locOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->notice =
|
$this->notice =
|
||||||
Notice::saveNew($this->user->id,
|
Notice::saveNew($this->auth_user->id,
|
||||||
$content,
|
$content,
|
||||||
$this->source,
|
$this->source,
|
||||||
$options);
|
$options);
|
||||||
@ -250,7 +254,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||||||
$upload->attachToNotice($this->notice);
|
$upload->attachToNotice($this->notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showNotice();
|
$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();
|
parent::showScripts();
|
||||||
|
|
||||||
if ($this->mode == 'crop') {
|
if ($this->mode == 'crop') {
|
||||||
$this->script('js/jcrop/jquery.Jcrop.min.js');
|
$this->script('jcrop/jquery.Jcrop.min.js');
|
||||||
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
$this->script('jcrop/jquery.Jcrop.go.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->autofocus('avatarfile');
|
$this->autofocus('avatarfile');
|
||||||
|
@ -302,8 +302,8 @@ class DesignadminpanelAction extends AdminPanelAction
|
|||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
|
||||||
$this->script('js/farbtastic/farbtastic.js');
|
$this->script('farbtastic/farbtastic.js');
|
||||||
$this->script('js/userdesign.go.js');
|
$this->script('userdesign.go.js');
|
||||||
|
|
||||||
$this->autofocus('design_background-image_file');
|
$this->autofocus('design_background-image_file');
|
||||||
}
|
}
|
||||||
|
130
actions/doc.php
130
actions/doc.php
@ -45,11 +45,23 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
*/
|
*/
|
||||||
class DocAction extends Action
|
class DocAction extends Action
|
||||||
{
|
{
|
||||||
var $filename;
|
var $output = null;
|
||||||
var $title;
|
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
|
* @param array $args array of arguments
|
||||||
*
|
*
|
||||||
@ -58,33 +70,30 @@ class DocAction extends Action
|
|||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::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();
|
$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());
|
$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()
|
function showContentBlock()
|
||||||
{
|
{
|
||||||
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
|
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
|
||||||
@ -101,8 +110,11 @@ class DocAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Display content.
|
* Display content.
|
||||||
*
|
*
|
||||||
* @return nothing
|
* Shows the content of the document.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$this->raw($this->output);
|
$this->raw($this->output);
|
||||||
@ -111,6 +123,8 @@ class DocAction extends Action
|
|||||||
/**
|
/**
|
||||||
* Page title.
|
* Page title.
|
||||||
*
|
*
|
||||||
|
* Uses the title of the document.
|
||||||
|
*
|
||||||
* @return page title
|
* @return page title
|
||||||
*/
|
*/
|
||||||
function title()
|
function title()
|
||||||
@ -118,8 +132,74 @@ class DocAction extends Action
|
|||||||
return ucfirst($this->title);
|
return ucfirst($this->title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These pages are read-only.
|
||||||
|
*
|
||||||
|
* @param array $args unused.
|
||||||
|
*
|
||||||
|
* @return boolean read-only flag (false)
|
||||||
|
*/
|
||||||
|
|
||||||
function isReadOnly($args)
|
function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return true;
|
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();
|
parent::showScripts();
|
||||||
|
|
||||||
if ($this->mode == 'crop') {
|
if ($this->mode == 'crop') {
|
||||||
$this->script('js/jcrop/jquery.Jcrop.min.js');
|
$this->script('jcrop/jquery.Jcrop.min.js');
|
||||||
$this->script('js/jcrop/jquery.Jcrop.go.js');
|
$this->script('jcrop/jquery.Jcrop.go.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->autofocus('avatarfile');
|
$this->autofocus('avatarfile');
|
||||||
|
@ -56,10 +56,10 @@ class InboxAction extends MailboxAction
|
|||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page > 1) {
|
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);
|
$this->page);
|
||||||
} else {
|
} 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()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page > 1) {
|
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);
|
$this->user->nickname, $page);
|
||||||
} else {
|
} 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 Evan Prodromou <evan@status.net>
|
||||||
* @author Zach Copley <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
* @author Sarven Capadisli <csarven@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
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
@ -98,6 +98,11 @@ class PathsadminpanelAction extends AdminPanelAction
|
|||||||
'background' => array('server', 'dir', 'path')
|
'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();
|
$values = array();
|
||||||
|
|
||||||
foreach ($settings as $section => $parts) {
|
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);
|
$this->validate($values);
|
||||||
|
|
||||||
// assert(all values are valid);
|
// assert(all values are valid);
|
||||||
@ -120,6 +131,12 @@ class PathsadminpanelAction extends AdminPanelAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($booleans as $section => $parts) {
|
||||||
|
foreach ($parts as $setting) {
|
||||||
|
Config::save($section, $setting, $values[$section][$setting]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$config->query('COMMIT');
|
$config->query('COMMIT');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -217,6 +234,10 @@ class PathsAdminPanelForm extends AdminForm
|
|||||||
$this->out->element('legend', null, _('Site'), 'site');
|
$this->out->element('legend', null, _('Site'), 'site');
|
||||||
$this->out->elementStart('ul', 'form_data');
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
|
||||||
|
$this->li();
|
||||||
|
$this->input('server', _('Server'), _('Site\'s server hostname.'));
|
||||||
|
$this->unli();
|
||||||
|
|
||||||
$this->li();
|
$this->li();
|
||||||
$this->input('path', _('Path'), _('Site path'));
|
$this->input('path', _('Path'), _('Site path'));
|
||||||
$this->unli();
|
$this->unli();
|
||||||
@ -225,6 +246,12 @@ class PathsAdminPanelForm extends AdminForm
|
|||||||
$this->input('locale_path', _('Path to locales'), _('Directory path to locales'), 'site');
|
$this->input('locale_path', _('Path to locales'), _('Directory path to locales'), 'site');
|
||||||
$this->unli();
|
$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('ul');
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ class RepliesAction extends OwnerDesignAction
|
|||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("Replies to %s"), $this->user->nickname);
|
return sprintf(_("Replies to %s"), $this->user->nickname);
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("Replies to %1$s, page %2$d"),
|
return sprintf(_('Replies to %1$s, page %2$d'),
|
||||||
$this->user->nickname,
|
$this->user->nickname,
|
||||||
$this->page);
|
$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()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("%s's favorite notices"), $this->user->nickname);
|
return sprintf(_('%s\'s favorite notices'), $this->user->nickname);
|
||||||
} else {
|
} 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->user->nickname,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
|
@ -79,9 +79,9 @@ class ShowgroupAction extends GroupDesignAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("%s group"), $base);
|
return sprintf(_('%s group'), $base);
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("%1$s group, page %2$d"),
|
return sprintf(_('%1$s group, page %2$d'),
|
||||||
$base,
|
$base,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ class ShowstreamAction extends ProfileAction
|
|||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return $base;
|
return $base;
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("%1$s, page %2$d"),
|
return sprintf(_('%1$s, page %2$d'),
|
||||||
$base,
|
$base,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @author Zach Copley <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
* @author Sarven Capadisli <csarven@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
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
@ -95,8 +95,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
|||||||
'site', 'textlimit', 'dupelimit'),
|
'site', 'textlimit', 'dupelimit'),
|
||||||
'snapshot' => array('run', 'reporturl', 'frequency'));
|
'snapshot' => array('run', 'reporturl', 'frequency'));
|
||||||
|
|
||||||
static $booleans = array('site' => array('private', 'inviteonly', 'closed', 'fancy'));
|
|
||||||
|
|
||||||
$values = array();
|
$values = array();
|
||||||
|
|
||||||
foreach ($settings as $section => $parts) {
|
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 throws an exception on validation errors
|
||||||
|
|
||||||
$this->validate($values);
|
$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');
|
$config->query('COMMIT');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -299,44 +285,6 @@ class SiteAdminPanelForm extends AdminForm
|
|||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_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->elementStart('fieldset', array('id' => 'settings_admin_snapshots'));
|
||||||
$this->out->element('legend', null, _('Snapshots'));
|
$this->out->element('legend', null, _('Snapshots'));
|
||||||
$this->out->elementStart('ul', 'form_data');
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
@ -63,9 +63,9 @@ class TagAction extends Action
|
|||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("Notices tagged with %s"), $this->tag);
|
return sprintf(_('Notices tagged with %s'), $this->tag);
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("Notices tagged with %1$s, page %2$d"),
|
return sprintf(_('Notices tagged with %1$s, page %2$d'),
|
||||||
$this->tag,
|
$this->tag,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,9 @@ class UsergroupsAction extends OwnerDesignAction
|
|||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("%s groups"), $this->user->nickname);
|
return sprintf(_('%s groups'), $this->user->nickname);
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("%1$s groups, page %2$d"),
|
return sprintf(_('%1$s groups, page %2$d'),
|
||||||
$this->user->nickname,
|
$this->user->nickname,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,10 @@ class Consumer extends Memcached_DataObject
|
|||||||
|
|
||||||
public $__table = 'consumer'; // table name
|
public $__table = 'consumer'; // table name
|
||||||
public $consumer_key; // varchar(255) primary_key not_null
|
public $consumer_key; // varchar(255) primary_key not_null
|
||||||
|
public $consumer_secret; // varchar(255) not_null
|
||||||
public $seed; // char(32) not_null
|
public $seed; // char(32) not_null
|
||||||
public $created; // datetime() not_null
|
public $created; // datetime not_null
|
||||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||||
|
|
||||||
/* Static get */
|
/* Static get */
|
||||||
function staticGet($k,$v=null)
|
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 */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###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
|
// Clear this out so we don't accidentally break global
|
||||||
// state in *this* process.
|
// state in *this* process.
|
||||||
$this->_DB_resultid = null;
|
$this->_DB_resultid = null;
|
||||||
|
|
||||||
// We don't have any local DBO refs, so clear these out.
|
// We don't have any local DBO refs, so clear these out.
|
||||||
$this->_link_loaded = false;
|
$this->_link_loaded = false;
|
||||||
}
|
}
|
||||||
@ -91,9 +90,7 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
unset($i);
|
unset($i);
|
||||||
}
|
}
|
||||||
$i = Memcached_DataObject::getcached($cls, $k, $v);
|
$i = Memcached_DataObject::getcached($cls, $k, $v);
|
||||||
if ($i) {
|
if ($i === false) { // false == cache miss
|
||||||
return $i;
|
|
||||||
} else {
|
|
||||||
$i = DB_DataObject::factory($cls);
|
$i = DB_DataObject::factory($cls);
|
||||||
if (empty($i)) {
|
if (empty($i)) {
|
||||||
$i = false;
|
$i = false;
|
||||||
@ -101,22 +98,34 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
}
|
}
|
||||||
$result = $i->get($k, $v);
|
$result = $i->get($k, $v);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
// Hit!
|
||||||
$i->encache();
|
$i->encache();
|
||||||
return $i;
|
|
||||||
} else {
|
} 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;
|
$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);
|
$i = Memcached_DataObject::multicache($cls, $kv);
|
||||||
if ($i) {
|
if ($i !== false) { // false == cache miss
|
||||||
return $i;
|
return $i;
|
||||||
} else {
|
} else {
|
||||||
$i = new $cls();
|
$i = DB_DataObject::factory($cls);
|
||||||
|
if (empty($i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
foreach ($kv as $k => $v) {
|
foreach ($kv as $k => $v) {
|
||||||
$i->$k = $v;
|
$i->$k = $v;
|
||||||
}
|
}
|
||||||
@ -124,6 +133,11 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
$i->encache();
|
$i->encache();
|
||||||
} else {
|
} else {
|
||||||
$i = null;
|
$i = null;
|
||||||
|
$c = self::memcache();
|
||||||
|
if (!empty($c)) {
|
||||||
|
$ck = self::multicacheKey($cls, $kv);
|
||||||
|
$c->set($ck, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $i;
|
return $i;
|
||||||
}
|
}
|
||||||
@ -132,6 +146,9 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
function insert()
|
function insert()
|
||||||
{
|
{
|
||||||
$result = parent::insert();
|
$result = parent::insert();
|
||||||
|
if ($result) {
|
||||||
|
$this->encache(); // in case of cached negative lookups
|
||||||
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,6 +203,17 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
|
|
||||||
function keyTypes()
|
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;
|
global $_DB_DATAOBJECT;
|
||||||
if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
|
if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
|
||||||
$this->databaseStructure();
|
$this->databaseStructure();
|
||||||
@ -197,6 +225,7 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
function encache()
|
function encache()
|
||||||
{
|
{
|
||||||
$c = $this->memcache();
|
$c = $this->memcache();
|
||||||
|
|
||||||
if (!$c) {
|
if (!$c) {
|
||||||
return false;
|
return false;
|
||||||
} else if ($this->tableName() == 'user' && is_object($this->id)) {
|
} else if ($this->tableName() == 'user' && is_object($this->id)) {
|
||||||
@ -206,62 +235,84 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
str_replace("\n", " ", $e->getTraceAsString()));
|
str_replace("\n", " ", $e->getTraceAsString()));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
$pkey = array();
|
$keys = $this->_allCacheKeys();
|
||||||
$pval = array();
|
|
||||||
$types = $this->keyTypes();
|
foreach ($keys as $key) {
|
||||||
ksort($types);
|
$c->set($key, $this);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function decache()
|
function decache()
|
||||||
{
|
{
|
||||||
$c = $this->memcache();
|
$c = $this->memcache();
|
||||||
|
|
||||||
if (!$c) {
|
if (!$c) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
$pkey = array();
|
|
||||||
$pval = array();
|
$keys = $this->_allCacheKeys();
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$c->delete($key, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _allCacheKeys()
|
||||||
|
{
|
||||||
|
$ckeys = array();
|
||||||
|
|
||||||
$types = $this->keyTypes();
|
$types = $this->keyTypes();
|
||||||
ksort($types);
|
ksort($types);
|
||||||
|
|
||||||
|
$pkey = array();
|
||||||
|
$pval = array();
|
||||||
|
|
||||||
foreach ($types as $key => $type) {
|
foreach ($types as $key => $type) {
|
||||||
if ($type == 'K') {
|
|
||||||
|
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;
|
$pkey[] = $key;
|
||||||
$pval[] = $this->$key;
|
$pval[] = $this->$key;
|
||||||
} else {
|
} else {
|
||||||
$c->delete($this->cacheKey($this->tableName(), $key, $this->$key));
|
throw new Exception("Unknown key type $key => $type for " . $this->tableName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# should work for both compound and scalar pkeys
|
|
||||||
# XXX: comma works for now but may not be safe separator for future keys
|
assert(count($pkey) > 0);
|
||||||
|
|
||||||
|
// XXX: should work for both compound and scalar pkeys
|
||||||
$pvals = implode(',', $pval);
|
$pvals = implode(',', $pval);
|
||||||
$pkeys = implode(',', $pkey);
|
$pkeys = implode(',', $pkey);
|
||||||
$c->delete($this->cacheKey($this->tableName(), $pkeys, $pvals));
|
|
||||||
}
|
$ckeys[] = $this->cacheKey($this->tableName(), $pkeys, $pvals);
|
||||||
|
|
||||||
|
return $ckeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
function multicache($cls, $kv)
|
function multicache($cls, $kv)
|
||||||
{
|
{
|
||||||
ksort($kv);
|
ksort($kv);
|
||||||
$c = Memcached_DataObject::memcache();
|
$c = self::memcache();
|
||||||
if (!$c) {
|
if (!$c) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
return $c->get(self::multicacheKey($cls, $kv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function multicacheKey($cls, $kv)
|
||||||
|
{
|
||||||
|
ksort($kv);
|
||||||
$pkeys = implode(',', array_keys($kv));
|
$pkeys = implode(',', array_keys($kv));
|
||||||
$pvals = implode(',', array_values($kv));
|
$pvals = implode(',', array_values($kv));
|
||||||
return $c->get(Memcached_DataObject::cacheKey($cls, $pkeys, $pvals));
|
return self::cacheKey($cls, $pkeys, $pvals);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSearchEngine($table)
|
function getSearchEngine($table)
|
||||||
@ -298,7 +349,8 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
$key_part = common_keyize($cls).':'.md5($qry);
|
$key_part = common_keyize($cls).':'.md5($qry);
|
||||||
$ckey = common_cache_key($key_part);
|
$ckey = common_cache_key($key_part);
|
||||||
$stored = $c->get($ckey);
|
$stored = $c->get($ckey);
|
||||||
if ($stored) {
|
|
||||||
|
if ($stored !== false) {
|
||||||
return new ArrayWrapper($stored);
|
return new ArrayWrapper($stored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,6 +365,39 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
return new ArrayWrapper($cached);
|
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
|
// We overload so that 'SET NAMES "utf8"' is called for
|
||||||
// each connection
|
// each connection
|
||||||
|
|
||||||
|
@ -326,9 +326,13 @@ class Notice extends Memcached_DataObject
|
|||||||
# XXX: someone clever could prepend instead of clearing the cache
|
# XXX: someone clever could prepend instead of clearing the cache
|
||||||
$notice->blowOnInsert();
|
$notice->blowOnInsert();
|
||||||
|
|
||||||
|
if (common_config('queue', 'inboxes')) {
|
||||||
$qm = QueueManager::get();
|
$qm = QueueManager::get();
|
||||||
|
|
||||||
$qm->enqueue($notice, 'distrib');
|
$qm->enqueue($notice, 'distrib');
|
||||||
|
} else {
|
||||||
|
$handler = new DistribQueueHandler();
|
||||||
|
$handler->handle($notice);
|
||||||
|
}
|
||||||
|
|
||||||
return $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;
|
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()
|
function subscriptionCount()
|
||||||
{
|
{
|
||||||
$c = common_memcache();
|
$c = common_memcache();
|
||||||
|
@ -39,9 +39,19 @@ class Status_network extends DB_DataObject
|
|||||||
public $logo; // varchar(255)
|
public $logo; // varchar(255)
|
||||||
public $created; // datetime() not_null
|
public $created; // datetime() not_null
|
||||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||||
|
public $tags; // text
|
||||||
|
|
||||||
/* Static get */
|
/* 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 */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###END_AUTOCODE
|
||||||
@ -245,4 +255,23 @@ class Status_network extends DB_DataObject
|
|||||||
return $this->nickname . '.' . self::$wildcard;
|
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 $secret; // char(32) not_null
|
||||||
public $type; // tinyint(1) not_null
|
public $type; // tinyint(1) not_null
|
||||||
public $state; // tinyint(1)
|
public $state; // tinyint(1)
|
||||||
|
public $verifier; // varchar(255)
|
||||||
|
public $verified_callback; // varchar(255)
|
||||||
public $created; // datetime() not_null
|
public $created; // datetime() not_null
|
||||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ code = K
|
|||||||
|
|
||||||
[consumer]
|
[consumer]
|
||||||
consumer_key = 130
|
consumer_key = 130
|
||||||
|
consumer_secret = 130
|
||||||
seed = 130
|
seed = 130
|
||||||
created = 142
|
created = 142
|
||||||
modified = 384
|
modified = 384
|
||||||
@ -348,6 +349,37 @@ created = 142
|
|||||||
tag = K
|
tag = K
|
||||||
notice_id = 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]
|
[profile]
|
||||||
id = 129
|
id = 129
|
||||||
nickname = 130
|
nickname = 130
|
||||||
@ -484,6 +516,8 @@ tok = 130
|
|||||||
secret = 130
|
secret = 130
|
||||||
type = 145
|
type = 145
|
||||||
state = 17
|
state = 17
|
||||||
|
verifier = 2
|
||||||
|
verified_callback = 2
|
||||||
created = 142
|
created = 142
|
||||||
modified = 384
|
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',
|
theme varchar(255) comment 'theme name',
|
||||||
logo varchar(255) comment 'site logo',
|
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',
|
created datetime not null comment 'date this record was created',
|
||||||
modified timestamp comment 'date this record was modified'
|
modified timestamp comment 'date this record was modified'
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ create table fave (
|
|||||||
|
|
||||||
create table consumer (
|
create table consumer (
|
||||||
consumer_key varchar(255) primary key comment 'unique identifier, root URL',
|
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',
|
seed char(32) not null comment 'seed for new tokens by this consumer',
|
||||||
|
|
||||||
created datetime not null comment 'date this record was created',
|
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',
|
secret char(32) not null comment 'secret value',
|
||||||
type tinyint not null default 0 comment 'request or access',
|
type tinyint not null default 0 comment 'request or access',
|
||||||
state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
|
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',
|
created datetime not null comment 'date this record was created',
|
||||||
modified timestamp comment 'date this record was modified',
|
modified timestamp comment 'date this record was modified',
|
||||||
@ -207,6 +210,33 @@ create table nonce (
|
|||||||
constraint primary key (consumer_key, ts, nonce)
|
constraint primary key (consumer_key, ts, nonce)
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) 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 */
|
/* These are used by JanRain OpenID library */
|
||||||
|
|
||||||
create table oid_associations (
|
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
|
// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API
|
||||||
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) (function(){
|
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){
|
||||||
|
|
||||||
// -- BEGIN GEARS_INIT
|
// -- BEGIN GEARS_INIT
|
||||||
(function() {
|
(function() {
|
||||||
@ -23,8 +23,7 @@ if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim )
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Safari
|
// Safari
|
||||||
if ((typeof navigator.mimeTypes != 'undefined')
|
if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
|
||||||
&& navigator.mimeTypes["application/x-googlegears"]) {
|
|
||||||
factory = document.createElement("object");
|
factory = document.createElement("object");
|
||||||
factory.style.display = "none";
|
factory.style.display = "none";
|
||||||
factory.width = 0;
|
factory.width = 0;
|
||||||
@ -64,8 +63,8 @@ var GearsGeoLocation = (function() {
|
|||||||
return function(position) {
|
return function(position) {
|
||||||
callback(position);
|
callback(position);
|
||||||
self.lastPosition = position;
|
self.lastPosition = position;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
// -- PUBLIC
|
// -- PUBLIC
|
||||||
return {
|
return {
|
||||||
@ -96,9 +95,123 @@ var GearsGeoLocation = (function() {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// If you have Gears installed use that
|
var AjaxGeoLocation = (function() {
|
||||||
if (window.google && google.gears) {
|
// -- PRIVATE
|
||||||
navigator.geolocation = GearsGeoLocation();
|
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('StartShowScripts', array($this))) {
|
||||||
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
if (Event::handle('StartShowJQueryScripts', array($this))) {
|
||||||
$this->script('js/jquery.min.js');
|
$this->script('jquery.min.js');
|
||||||
$this->script('js/jquery.form.js');
|
$this->script('jquery.form.js');
|
||||||
$this->script('js/jquery.cookie.js');
|
$this->script('jquery.cookie.js');
|
||||||
$this->script('js/json2.js');
|
$this->script('json2.js');
|
||||||
$this->script('js/jquery.joverlay.min.js');
|
$this->script('jquery.joverlay.min.js');
|
||||||
Event::handle('EndShowJQueryScripts', array($this));
|
Event::handle('EndShowJQueryScripts', array($this));
|
||||||
}
|
}
|
||||||
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
||||||
Event::handle('StartShowLaconicaScripts', array($this))) {
|
Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||||
$this->script('js/xbImportNode.js');
|
$this->script('xbImportNode.js');
|
||||||
$this->script('js/util.js');
|
$this->script('util.js');
|
||||||
$this->script('js/geometa.js');
|
$this->script('geometa.js');
|
||||||
// Frame-busting code to avoid clickjacking attacks.
|
// Frame-busting code to avoid clickjacking attacks.
|
||||||
$this->element('script', array('type' => 'text/javascript'),
|
$this->element('script', array('type' => 'text/javascript'),
|
||||||
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
'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->elementStart('div', array('id' => 'header'));
|
||||||
$this->showLogo();
|
$this->showLogo();
|
||||||
$this->showPrimaryNav();
|
$this->showPrimaryNav();
|
||||||
|
if (Event::handle('StartShowSiteNotice', array($this))) {
|
||||||
$this->showSiteNotice();
|
$this->showSiteNotice();
|
||||||
|
|
||||||
|
Event::handle('EndShowSiteNotice', array($this));
|
||||||
|
}
|
||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$this->showNoticeForm();
|
$this->showNoticeForm();
|
||||||
} else {
|
} else {
|
||||||
@ -388,8 +392,14 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
$this->elementStart('address', array('id' => 'site_contact',
|
$this->elementStart('address', array('id' => 'site_contact',
|
||||||
'class' => 'vcard'));
|
'class' => 'vcard'));
|
||||||
if (Event::handle('StartAddressData', array($this))) {
|
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',
|
$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'))) {
|
if (common_config('site', 'logo') || file_exists(Theme::file('logo.png'))) {
|
||||||
$this->element('img', array('class' => 'logo photo',
|
$this->element('img', array('class' => 'logo photo',
|
||||||
'src' => (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'),
|
'src' => (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'),
|
||||||
|
@ -319,7 +319,12 @@ class AdminPanelNav extends Widget
|
|||||||
|
|
||||||
if ($this->canAdmin('user')) {
|
if ($this->canAdmin('user')) {
|
||||||
$this->out->menuItem(common_local_url('useradminpanel'), _('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('access')) {
|
||||||
|
$this->out->menuItem(common_local_url('accessadminpanel'), _('Access'),
|
||||||
|
_('Access configuration'), $action_name == 'accessadminpanel', 'nav_design_admin_panel');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->canAdmin('paths')) {
|
if ($this->canAdmin('paths')) {
|
||||||
|
@ -53,6 +53,9 @@ if (!defined('STATUSNET')) {
|
|||||||
|
|
||||||
class ApiAction extends Action
|
class ApiAction extends Action
|
||||||
{
|
{
|
||||||
|
const READ_ONLY = 1;
|
||||||
|
const READ_WRITE = 2;
|
||||||
|
|
||||||
var $format = null;
|
var $format = null;
|
||||||
var $user = null;
|
var $user = null;
|
||||||
var $auth_user = null;
|
var $auth_user = null;
|
||||||
@ -62,6 +65,8 @@ class ApiAction extends Action
|
|||||||
var $since_id = null;
|
var $since_id = null;
|
||||||
var $since = null;
|
var $since = null;
|
||||||
|
|
||||||
|
var $access = self::READ_ONLY; // read (default) or read-write
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialization.
|
* Initialization.
|
||||||
*
|
*
|
||||||
|
186
lib/apiauth.php
186
lib/apiauth.php
@ -29,7 +29,7 @@
|
|||||||
* @author mEDI <medi@milaro.net>
|
* @author mEDI <medi@milaro.net>
|
||||||
* @author Sarven Capadisli <csarven@status.net>
|
* @author Sarven Capadisli <csarven@status.net>
|
||||||
* @author Zach Copley <zach@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
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
@ -39,6 +39,7 @@ if (!defined('STATUSNET')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR . '/lib/api.php';
|
require_once INSTALLDIR . '/lib/api.php';
|
||||||
|
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions extending this class will require auth
|
* Actions extending this class will require auth
|
||||||
@ -52,6 +53,10 @@ require_once INSTALLDIR . '/lib/api.php';
|
|||||||
|
|
||||||
class ApiAuthAction extends ApiAction
|
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
|
* Take arguments for running, and output basic auth header if needed
|
||||||
@ -66,13 +71,130 @@ class ApiAuthAction extends ApiAction
|
|||||||
{
|
{
|
||||||
parent::prepare($args);
|
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()) {
|
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;
|
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?
|
* Does this API resource require authentication?
|
||||||
*
|
*
|
||||||
@ -91,44 +213,54 @@ class ApiAuthAction extends ApiAction
|
|||||||
* @return boolean true or false
|
* @return boolean true or false
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function checkBasicAuthUser()
|
function checkBasicAuthUser($required = true)
|
||||||
{
|
{
|
||||||
$this->basicAuthProcessHeader();
|
$this->basicAuthProcessHeader();
|
||||||
|
|
||||||
$realm = common_config('site', 'name') . ' API';
|
$realm = common_config('site', 'name') . ' API';
|
||||||
|
|
||||||
if (!isset($this->auth_user)) {
|
if (!isset($this->auth_user_nickname) && $required) {
|
||||||
header('WWW-Authenticate: Basic realm="' . $realm . '"');
|
header('WWW-Authenticate: Basic realm="' . $realm . '"');
|
||||||
|
|
||||||
// show error if the user clicks 'cancel'
|
// show error if the user clicks 'cancel'
|
||||||
|
|
||||||
$this->showBasicAuthError();
|
$this->showAuthError();
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$nickname = $this->auth_user;
|
|
||||||
$password = $this->auth_pw;
|
$user = common_check_user($this->auth_user_nickname,
|
||||||
$user = common_check_user($nickname, $password);
|
$this->auth_user_password);
|
||||||
|
|
||||||
if (Event::handle('StartSetApiUser', array(&$user))) {
|
if (Event::handle('StartSetApiUser', array(&$user))) {
|
||||||
|
|
||||||
|
if (!empty($user)) {
|
||||||
$this->auth_user = $user;
|
$this->auth_user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
Event::handle('EndSetApiUser', array($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
|
// basic authentication failed
|
||||||
|
|
||||||
list($proxy, $ip) = common_client_ip();
|
list($proxy, $ip) = common_client_ip();
|
||||||
common_log(
|
|
||||||
LOG_WARNING,
|
$msg = sprintf(_('Failed API auth attempt, nickname = %1$s, ' .
|
||||||
'Failed API auth attempt, nickname = ' .
|
'proxy = %2$s, ip = %3$s'),
|
||||||
"$nickname, proxy = $proxy, ip = $ip."
|
$this->auth_user_nickname,
|
||||||
);
|
$proxy,
|
||||||
$this->showBasicAuthError();
|
$ip);
|
||||||
|
common_log(LOG_WARNING, $msg);
|
||||||
|
$this->showAuthError();
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,26 +280,24 @@ class ApiAuthAction extends ApiAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
if (isset($_SERVER['PHP_AUTH_USER'])) {
|
||||||
$this->auth_user = $_SERVER['PHP_AUTH_USER'];
|
$this->auth_user_nickname = $_SERVER['PHP_AUTH_USER'];
|
||||||
$this->auth_pw = $_SERVER['PHP_AUTH_PW'];
|
$this->auth_user_password = $_SERVER['PHP_AUTH_PW'];
|
||||||
} elseif (isset($authorization_header)
|
} elseif (isset($authorization_header)
|
||||||
&& strstr(substr($authorization_header, 0, 5), 'Basic')) {
|
&& 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
|
// on fcgid server the header name is AUTHORIZATION
|
||||||
|
|
||||||
$auth_hash = base64_decode(substr($authorization_header, 6));
|
$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 == "") {
|
if (empty($this->auth_user_nickname)) {
|
||||||
$this->auth_user = null;
|
$this->auth_user_nickname = null;
|
||||||
$this->auth_pw = null;
|
$this->auth_password = null;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$this->auth_user = null;
|
|
||||||
$this->auth_pw = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +308,7 @@ class ApiAuthAction extends ApiAction
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function showBasicAuthError()
|
function showAuthError()
|
||||||
{
|
{
|
||||||
header('HTTP/1.1 401 Unauthorized');
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
$msg = 'Could not authenticate you.';
|
$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
|
//exit with 200 response, if this is checking fancy from the installer
|
||||||
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
|
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('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
||||||
|
|
||||||
define('STATUSNET_CODENAME', 'Stand');
|
define('STATUSNET_CODENAME', 'Stand');
|
||||||
|
@ -116,6 +116,11 @@ class ConnectSettingsNav extends Widget
|
|||||||
_('Updates by SMS'));
|
_('Updates by SMS'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$menu['oauthconnectionssettings'] = array(
|
||||||
|
_('Connections'),
|
||||||
|
_('Authorized connected applications')
|
||||||
|
);
|
||||||
|
|
||||||
foreach ($menu as $menuaction => $menudesc) {
|
foreach ($menu as $menuaction => $menudesc) {
|
||||||
$this->action->menuItem(common_local_url($menuaction),
|
$this->action->menuItem(common_local_url($menuaction),
|
||||||
$menudesc[0],
|
$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
|
'dupelimit' => 60, # default for same person saying the same thing
|
||||||
'textlimit' => 140,
|
'textlimit' => 140,
|
||||||
'indent' => true,
|
'indent' => true,
|
||||||
'use_x_sendfile' => false,
|
'use_x_sendfile' => false
|
||||||
),
|
),
|
||||||
'db' =>
|
'db' =>
|
||||||
array('database' => 'YOU HAVE TO SET THIS IN config.php',
|
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
|
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||||
'quote_identifiers' => false,
|
'quote_identifiers' => false,
|
||||||
'type' => 'mysql',
|
'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' =>
|
'syslog' =>
|
||||||
array('appname' => 'statusnet', # for syslog
|
array('appname' => 'statusnet', # for syslog
|
||||||
'priority' => 'debug', # XXX: currently ignored
|
'priority' => 'debug', # XXX: currently ignored
|
||||||
@ -79,11 +81,13 @@ $default =
|
|||||||
'subsystem' => 'db', # default to database, or 'stomp'
|
'subsystem' => 'db', # default to database, or 'stomp'
|
||||||
'stomp_server' => null,
|
'stomp_server' => null,
|
||||||
'queue_basename' => '/queue/statusnet/',
|
'queue_basename' => '/queue/statusnet/',
|
||||||
|
'control_channel' => '/topic/statusnet-control', // broadcasts to all queue daemons
|
||||||
'stomp_username' => null,
|
'stomp_username' => null,
|
||||||
'stomp_password' => null,
|
'stomp_password' => null,
|
||||||
'monitor' => null, // URL to monitor ping endpoint (work in progress)
|
'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
|
'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
|
'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' =>
|
'license' =>
|
||||||
array('type' => 'cc', # can be 'cc', 'allrightsreserved', 'private'
|
array('type' => 'cc', # can be 'cc', 'allrightsreserved', 'private'
|
||||||
@ -117,6 +121,9 @@ $default =
|
|||||||
array('server' => null,
|
array('server' => null,
|
||||||
'dir' => null,
|
'dir' => null,
|
||||||
'path'=> null),
|
'path'=> null),
|
||||||
|
'javascript' =>
|
||||||
|
array('server' => null,
|
||||||
|
'path'=> null),
|
||||||
'throttle' =>
|
'throttle' =>
|
||||||
array('enabled' => false, // whether to throttle edits; false by default
|
array('enabled' => false, // whether to throttle edits; false by default
|
||||||
'count' => 20, // number of allowed messages in timespan
|
'count' => 20, // number of allowed messages in timespan
|
||||||
@ -209,6 +216,8 @@ $default =
|
|||||||
'uploads' => true,
|
'uploads' => true,
|
||||||
'filecommand' => '/usr/bin/file',
|
'filecommand' => '/usr/bin/file',
|
||||||
),
|
),
|
||||||
|
'application' =>
|
||||||
|
array('desclimit' => null),
|
||||||
'group' =>
|
'group' =>
|
||||||
array('maxaliases' => 3,
|
array('maxaliases' => 3,
|
||||||
'desclimit' => null),
|
'desclimit' => null),
|
||||||
@ -255,5 +264,8 @@ $default =
|
|||||||
'OpenID' => null),
|
'OpenID' => null),
|
||||||
),
|
),
|
||||||
'admin' =>
|
'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();
|
parent::showScripts();
|
||||||
|
|
||||||
$this->script('js/farbtastic/farbtastic.js');
|
$this->script('farbtastic/farbtastic.js');
|
||||||
$this->script('js/userdesign.go.js');
|
$this->script('userdesign.go.js');
|
||||||
|
|
||||||
$this->autofocus('design_background-image_file');
|
$this->autofocus('design_background-image_file');
|
||||||
}
|
}
|
||||||
|
@ -351,14 +351,40 @@ class HTMLOutputter extends XMLOutputter
|
|||||||
function script($src, $type='text/javascript')
|
function script($src, $type='text/javascript')
|
||||||
{
|
{
|
||||||
if(Event::handle('StartScriptElement', array($this,&$src,&$type))) {
|
if(Event::handle('StartScriptElement', array($this,&$src,&$type))) {
|
||||||
|
|
||||||
$url = parse_url($src);
|
$url = parse_url($src);
|
||||||
|
|
||||||
if( empty($url['scheme']) && empty($url['host']) && empty($url['query']) && empty($url['fragment']))
|
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,
|
$this->element('script', array('type' => $type,
|
||||||
'src' => $src),
|
'src' => $src),
|
||||||
' ');
|
' ');
|
||||||
|
|
||||||
Event::handle('EndScriptElement', array($this,$src,$type));
|
Event::handle('EndScriptElement', array($this,$src,$type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,9 @@ abstract class IoMaster
|
|||||||
protected $pollTimeouts = array();
|
protected $pollTimeouts = array();
|
||||||
protected $lastPoll = 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
|
* @param string $id process ID to use in logging/monitoring
|
||||||
*/
|
*/
|
||||||
@ -144,7 +147,7 @@ abstract class IoMaster
|
|||||||
$this->logState('init');
|
$this->logState('init');
|
||||||
$this->start();
|
$this->start();
|
||||||
|
|
||||||
while (true) {
|
while (!$this->shutdown) {
|
||||||
$timeouts = array_values($this->pollTimeouts);
|
$timeouts = array_values($this->pollTimeouts);
|
||||||
$timeouts[] = 60; // default max timeout
|
$timeouts[] = 60; // default max timeout
|
||||||
|
|
||||||
@ -196,22 +199,31 @@ abstract class IoMaster
|
|||||||
$this->logState('idle');
|
$this->logState('idle');
|
||||||
$this->idle();
|
$this->idle();
|
||||||
|
|
||||||
|
$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();
|
$memoryLimit = $this->softMemoryLimit();
|
||||||
if ($memoryLimit > 0) {
|
if ($memoryLimit > 0) {
|
||||||
$usage = memory_get_usage();
|
$usage = memory_get_usage();
|
||||||
if ($usage > $memoryLimit) {
|
if ($usage > $memoryLimit) {
|
||||||
common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting.");
|
common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting.");
|
||||||
break;
|
$this->requestRestart();
|
||||||
} else if (common_config('queue', 'debug_memory')) {
|
} else if (common_config('queue', 'debug_memory')) {
|
||||||
common_log(LOG_DEBUG, "Memory usage $usage");
|
common_log(LOG_DEBUG, "Memory usage $usage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logState('shutdown');
|
|
||||||
$this->finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return fully-parsed soft memory limit in bytes.
|
* Return fully-parsed soft memory limit in bytes.
|
||||||
* @return intval 0 or -1 if not set
|
* @return intval 0 or -1 if not set
|
||||||
@ -354,5 +366,24 @@ abstract class IoMaster
|
|||||||
$owners[] = "thread:" . $this->id;
|
$owners[] = "thread:" . $this->id;
|
||||||
$this->monitor->stats($key, $owners);
|
$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();
|
$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' =>
|
$this->out->menuItem(common_local_url('inbox', array('nickname' =>
|
||||||
$nickname)),
|
$nickname)),
|
||||||
|
@ -100,6 +100,23 @@ abstract class QueueManager extends IoManager
|
|||||||
$this->initialize();
|
$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
|
* Store an object (usually/always a Notice) into the given queue
|
||||||
* for later processing. No guarantee is made on when it will be
|
* for later processing. No guarantee is made on when it will be
|
||||||
@ -225,7 +242,6 @@ abstract class QueueManager extends IoManager
|
|||||||
// XMPP output handlers...
|
// XMPP output handlers...
|
||||||
$this->connect('jabber', 'JabberQueueHandler');
|
$this->connect('jabber', 'JabberQueueHandler');
|
||||||
$this->connect('public', 'PublicQueueHandler');
|
$this->connect('public', 'PublicQueueHandler');
|
||||||
|
|
||||||
// @fixme this should get an actual queue
|
// @fixme this should get an actual queue
|
||||||
//$this->connect('confirm', 'XmppConfirmHandler');
|
//$this->connect('confirm', 'XmppConfirmHandler');
|
||||||
|
|
||||||
|
109
lib/router.php
109
lib/router.php
@ -73,12 +73,6 @@ class Router
|
|||||||
|
|
||||||
if (Event::handle('StartInitializeRouter', array(&$m))) {
|
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',
|
$m->connect('opensearch/people', array('action' => 'opensearch',
|
||||||
'type' => 'people'));
|
'type' => 'people'));
|
||||||
$m->connect('opensearch/notice', array('action' => 'opensearch',
|
$m->connect('opensearch/notice', array('action' => 'opensearch',
|
||||||
@ -140,11 +134,23 @@ class Router
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
|
|
||||||
foreach (array('profile', 'avatar', 'password', 'im',
|
foreach (array('profile', 'avatar', 'password', 'im', 'oauthconnections',
|
||||||
'email', 'sms', 'userdesign', 'other') as $s) {
|
'oauthapps', 'email', 'sms', 'userdesign', 'other') as $s) {
|
||||||
$m->connect('settings/'.$s, array('action' => $s.'settings'));
|
$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
|
// search
|
||||||
|
|
||||||
foreach (array('group', 'people', 'notice') as $s) {
|
foreach (array('group', 'people', 'notice') as $s) {
|
||||||
@ -227,11 +233,6 @@ class Router
|
|||||||
array('action' => 'peopletag'),
|
array('action' => 'peopletag'),
|
||||||
array('tag' => '[a-zA-Z0-9]+'));
|
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
|
// groups
|
||||||
|
|
||||||
$m->connect('group/new', array('action' => 'newgroup'));
|
$m->connect('group/new', array('action' => 'newgroup'));
|
||||||
@ -622,16 +623,93 @@ class Router
|
|||||||
$m->connect('api/search.json', array('action' => 'twitapisearchjson'));
|
$m->connect('api/search.json', array('action' => 'twitapisearchjson'));
|
||||||
$m->connect('api/trends.json', array('action' => 'twitapitrends'));
|
$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/site', array('action' => 'siteadminpanel'));
|
||||||
$m->connect('admin/design', array('action' => 'designadminpanel'));
|
$m->connect('admin/design', array('action' => 'designadminpanel'));
|
||||||
$m->connect('admin/user', array('action' => 'useradminpanel'));
|
$m->connect('admin/user', array('action' => 'useradminpanel'));
|
||||||
|
$m->connect('admin/access', array('action' => 'accessadminpanel'));
|
||||||
$m->connect('admin/paths', array('action' => 'pathsadminpanel'));
|
$m->connect('admin/paths', array('action' => 'pathsadminpanel'));
|
||||||
|
|
||||||
$m->connect('getfile/:filename',
|
$m->connect('getfile/:filename',
|
||||||
array('action' => 'getfile'),
|
array('action' => 'getfile'),
|
||||||
array('filename' => '[A-Za-z0-9._-]+'));
|
array('filename' => '[A-Za-z0-9._-]+'));
|
||||||
|
|
||||||
// user stuff
|
// In the "root"
|
||||||
|
|
||||||
|
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',
|
foreach (array('subscriptions', 'subscribers',
|
||||||
'nudge', 'all', 'foaf', 'xrds',
|
'nudge', 'all', 'foaf', 'xrds',
|
||||||
@ -682,6 +760,9 @@ class Router
|
|||||||
$m->connect(':nickname',
|
$m->connect(':nickname',
|
||||||
array('action' => 'showstream'),
|
array('action' => 'showstream'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// user stuff
|
||||||
|
|
||||||
Event::handle('RouterInitialized', array($m));
|
Event::handle('RouterInitialized', array($m));
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,11 @@ abstract class SpawningDaemon extends Daemon
|
|||||||
{
|
{
|
||||||
protected $threads=1;
|
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)
|
function __construct($id=null, $daemonize=true, $threads=1)
|
||||||
{
|
{
|
||||||
parent::__construct($daemonize);
|
parent::__construct($daemonize);
|
||||||
@ -49,7 +54,7 @@ abstract class SpawningDaemon extends Daemon
|
|||||||
/**
|
/**
|
||||||
* Perform some actual work!
|
* 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();
|
public abstract function runThread();
|
||||||
|
|
||||||
@ -84,14 +89,18 @@ abstract class SpawningDaemon extends Daemon
|
|||||||
while (count($children) > 0) {
|
while (count($children) > 0) {
|
||||||
$status = null;
|
$status = null;
|
||||||
$pid = pcntl_wait($status);
|
$pid = pcntl_wait($status);
|
||||||
if ($pid > 0) {
|
if ($pid > 0 && pcntl_wifexited($status)) {
|
||||||
|
$exitCode = pcntl_wexitstatus($status);
|
||||||
|
|
||||||
$i = array_search($pid, $children);
|
$i = array_search($pid, $children);
|
||||||
if ($i === false) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
unset($children[$i]);
|
unset($children[$i]);
|
||||||
$this->log(LOG_INFO, "Thread $i pid $pid exited.");
|
|
||||||
|
if ($this->shouldRespawn($exitCode)) {
|
||||||
|
$this->log(LOG_INFO, "Thread $i pid $pid exited with status $exitCode; respawing.");
|
||||||
|
|
||||||
$pid = pcntl_fork();
|
$pid = pcntl_fork();
|
||||||
if ($pid < 0) {
|
if ($pid < 0) {
|
||||||
@ -102,12 +111,33 @@ abstract class SpawningDaemon extends Daemon
|
|||||||
$this->log(LOG_INFO, "Respawned thread $i as pid $pid");
|
$this->log(LOG_INFO, "Respawned thread $i as pid $pid");
|
||||||
$children[$i] = $pid;
|
$children[$i] = $pid;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$this->log(LOG_INFO, "Thread $i pid $pid exited with status $exitCode; closing out thread.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->log(LOG_INFO, "All child processes complete.");
|
$this->log(LOG_INFO, "All child processes complete.");
|
||||||
return true;
|
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
|
* Initialize things for a fresh thread, call runThread(), and
|
||||||
* exit at completion with appropriate return value.
|
* exit at completion with appropriate return value.
|
||||||
@ -116,8 +146,8 @@ abstract class SpawningDaemon extends Daemon
|
|||||||
{
|
{
|
||||||
$this->set_id($this->get_id() . "." . $thread);
|
$this->set_id($this->get_id() . "." . $thread);
|
||||||
$this->resetDb();
|
$this->resetDb();
|
||||||
$ok = $this->runThread();
|
$exitCode = $this->runThread();
|
||||||
exit($ok ? 0 : 1);
|
exit($exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,8 +38,10 @@ class StompQueueManager extends QueueManager
|
|||||||
var $password = null;
|
var $password = null;
|
||||||
var $base = null;
|
var $base = null;
|
||||||
var $con = null;
|
var $con = null;
|
||||||
|
protected $control;
|
||||||
|
|
||||||
protected $sites = array();
|
protected $sites = array();
|
||||||
|
protected $subscriptions = array();
|
||||||
|
|
||||||
protected $useTransactions = true;
|
protected $useTransactions = true;
|
||||||
protected $transaction = null;
|
protected $transaction = null;
|
||||||
@ -52,6 +54,7 @@ class StompQueueManager extends QueueManager
|
|||||||
$this->username = common_config('queue', 'stomp_username');
|
$this->username = common_config('queue', 'stomp_username');
|
||||||
$this->password = common_config('queue', 'stomp_password');
|
$this->password = common_config('queue', 'stomp_password');
|
||||||
$this->base = common_config('queue', 'queue_basename');
|
$this->base = common_config('queue', 'queue_basename');
|
||||||
|
$this->control = common_config('queue', 'control_channel');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,6 +80,36 @@ class StompQueueManager extends QueueManager
|
|||||||
$this->initialize();
|
$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.
|
* Instantiate the appropriate QueueHandler class for the given queue.
|
||||||
@ -86,7 +119,7 @@ class StompQueueManager extends QueueManager
|
|||||||
*/
|
*/
|
||||||
function getHandler($queue)
|
function getHandler($queue)
|
||||||
{
|
{
|
||||||
$handlers = $this->handlers[common_config('site', 'server')];
|
$handlers = $this->handlers[$this->currentSite()];
|
||||||
if (isset($handlers[$queue])) {
|
if (isset($handlers[$queue])) {
|
||||||
$class = $handlers[$queue];
|
$class = $handlers[$queue];
|
||||||
if (class_exists($class)) {
|
if (class_exists($class)) {
|
||||||
@ -108,7 +141,7 @@ class StompQueueManager extends QueueManager
|
|||||||
function getQueues()
|
function getQueues()
|
||||||
{
|
{
|
||||||
$group = $this->activeGroup();
|
$group = $this->activeGroup();
|
||||||
$site = common_config('site', 'server');
|
$site = $this->currentSite();
|
||||||
if (empty($this->groups[$site][$group])) {
|
if (empty($this->groups[$site][$group])) {
|
||||||
return array();
|
return array();
|
||||||
} else {
|
} else {
|
||||||
@ -126,8 +159,8 @@ class StompQueueManager extends QueueManager
|
|||||||
*/
|
*/
|
||||||
public function connect($transport, $class, $group='queuedaemon')
|
public function connect($transport, $class, $group='queuedaemon')
|
||||||
{
|
{
|
||||||
$this->handlers[common_config('site', 'server')][$transport] = $class;
|
$this->handlers[$this->currentSite()][$transport] = $class;
|
||||||
$this->groups[common_config('site', 'server')][$group][$transport] = $class;
|
$this->groups[$this->currentSite()][$group][$transport] = $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,7 +178,8 @@ class StompQueueManager extends QueueManager
|
|||||||
|
|
||||||
$result = $this->con->send($this->queueName($queue),
|
$result = $this->con->send($this->queueName($queue),
|
||||||
$msg, // BODY of the message
|
$msg, // BODY of the message
|
||||||
array ('created' => common_sql_now()));
|
array ('created' => common_sql_now(),
|
||||||
|
'persistent' => 'true'));
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
common_log(LOG_ERR, "Error sending $rep to $queue queue");
|
common_log(LOG_ERR, "Error sending $rep to $queue queue");
|
||||||
@ -180,7 +214,16 @@ class StompQueueManager extends QueueManager
|
|||||||
$ok = true;
|
$ok = true;
|
||||||
$frames = $this->con->readFrames();
|
$frames = $this->con->readFrames();
|
||||||
foreach ($frames as $frame) {
|
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;
|
return $ok;
|
||||||
}
|
}
|
||||||
@ -197,6 +240,9 @@ class StompQueueManager extends QueueManager
|
|||||||
public function start($master)
|
public function start($master)
|
||||||
{
|
{
|
||||||
parent::start($master);
|
parent::start($master);
|
||||||
|
$this->_connect();
|
||||||
|
|
||||||
|
$this->con->subscribe($this->control);
|
||||||
if ($this->sites) {
|
if ($this->sites) {
|
||||||
foreach ($this->sites as $server) {
|
foreach ($this->sites as $server) {
|
||||||
StatusNet::init($server);
|
StatusNet::init($server);
|
||||||
@ -221,6 +267,7 @@ class StompQueueManager extends QueueManager
|
|||||||
// If there are any outstanding delivered messages we haven't processed,
|
// If there are any outstanding delivered messages we haven't processed,
|
||||||
// free them for another thread to take.
|
// free them for another thread to take.
|
||||||
$this->rollback();
|
$this->rollback();
|
||||||
|
$this->con->unsubscribe($this->control);
|
||||||
if ($this->sites) {
|
if ($this->sites) {
|
||||||
foreach ($this->sites as $server) {
|
foreach ($this->sites as $server) {
|
||||||
StatusNet::init($server);
|
StatusNet::init($server);
|
||||||
@ -232,6 +279,15 @@ class StompQueueManager extends QueueManager
|
|||||||
return true;
|
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.
|
* Lazy open connection to Stomp queue server.
|
||||||
*/
|
*/
|
||||||
@ -255,9 +311,11 @@ class StompQueueManager extends QueueManager
|
|||||||
*/
|
*/
|
||||||
protected function doSubscribe()
|
protected function doSubscribe()
|
||||||
{
|
{
|
||||||
|
$site = $this->currentSite();
|
||||||
$this->_connect();
|
$this->_connect();
|
||||||
foreach ($this->getQueues() as $queue) {
|
foreach ($this->getQueues() as $queue) {
|
||||||
$rawqueue = $this->queueName($queue);
|
$rawqueue = $this->queueName($queue);
|
||||||
|
$this->subscriptions[$site][$queue] = $rawqueue;
|
||||||
$this->_log(LOG_INFO, "Subscribing to $rawqueue");
|
$this->_log(LOG_INFO, "Subscribing to $rawqueue");
|
||||||
$this->con->subscribe($rawqueue);
|
$this->con->subscribe($rawqueue);
|
||||||
}
|
}
|
||||||
@ -268,9 +326,14 @@ class StompQueueManager extends QueueManager
|
|||||||
*/
|
*/
|
||||||
protected function doUnsubscribe()
|
protected function doUnsubscribe()
|
||||||
{
|
{
|
||||||
|
$site = $this->currentSite();
|
||||||
$this->_connect();
|
$this->_connect();
|
||||||
foreach ($this->getQueues() as $queue) {
|
if (!empty($this->subscriptions[$site])) {
|
||||||
$this->con->unsubscribe($this->queueName($queue));
|
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
|
* @param StompFrame $frame
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function _handleItem($frame)
|
protected function handleItem($frame)
|
||||||
{
|
{
|
||||||
list($site, $queue) = $this->parseDestination($frame->headers['destination']);
|
list($site, $queue) = $this->parseDestination($frame->headers['destination']);
|
||||||
if ($site != common_config('site', 'server')) {
|
if ($site != $this->currentSite()) {
|
||||||
$this->stats('switch');
|
$this->stats('switch');
|
||||||
StatusNet::init($site);
|
StatusNet::init($site);
|
||||||
}
|
}
|
||||||
@ -317,7 +380,7 @@ class StompQueueManager extends QueueManager
|
|||||||
|
|
||||||
$handler = $this->getHandler($queue);
|
$handler = $this->getHandler($queue);
|
||||||
if (!$handler) {
|
if (!$handler) {
|
||||||
$this->_log(LOG_ERROR, "Missing handler class; skipping $info");
|
$this->_log(LOG_ERR, "Missing handler class; skipping $info");
|
||||||
$this->ack($frame);
|
$this->ack($frame);
|
||||||
$this->commit();
|
$this->commit();
|
||||||
$this->begin();
|
$this->begin();
|
||||||
@ -348,6 +411,77 @@ class StompQueueManager extends QueueManager
|
|||||||
return true;
|
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
|
* Combines the queue_basename from configuration with the
|
||||||
* site server name and queue name to give eg:
|
* site server name and queue name to give eg:
|
||||||
@ -360,7 +494,7 @@ class StompQueueManager extends QueueManager
|
|||||||
protected function queueName($queue)
|
protected function queueName($queue)
|
||||||
{
|
{
|
||||||
return common_config('queue', 'queue_basename') .
|
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()
|
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)
|
function onEndAddressData($action)
|
||||||
{
|
{
|
||||||
$action->elementStart('span', 'poweredby');
|
$action->elementStart('span', 'poweredby');
|
||||||
$action->text(_('powered by'));
|
$action->raw(sprintf(_m('powered by %s'),
|
||||||
$action->element('a', array('href' => 'http://status.net/'), 'StatusNet');
|
sprintf('<a href="http://status.net/">%s</a>',
|
||||||
|
_m('StatusNet'))));
|
||||||
$action->elementEnd('span');
|
$action->elementEnd('span');
|
||||||
|
|
||||||
return true;
|
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();
|
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
|
* Hooks the StartApiAtom event
|
||||||
*
|
*
|
||||||
@ -92,8 +107,9 @@ class PubSubHubBubPlugin extends Plugin
|
|||||||
|
|
||||||
function onStartApiAtom($action)
|
function onStartApiAtom($action)
|
||||||
{
|
{
|
||||||
|
if ($this->enabled()) {
|
||||||
$action->element('link', array('rel' => 'hub', 'href' => $this->hub), null);
|
$action->element('link', array('rel' => 'hub', 'href' => $this->hub), null);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,9 +126,11 @@ class PubSubHubBubPlugin extends Plugin
|
|||||||
|
|
||||||
function onStartApiRss($action)
|
function onStartApiRss($action)
|
||||||
{
|
{
|
||||||
|
if ($this->enabled()) {
|
||||||
$action->element('atom:link', array('rel' => 'hub',
|
$action->element('atom:link', array('rel' => 'hub',
|
||||||
'href' => $this->hub),
|
'href' => $this->hub),
|
||||||
null);
|
null);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +148,9 @@ class PubSubHubBubPlugin extends Plugin
|
|||||||
|
|
||||||
function onHandleQueuedNotice($notice)
|
function onHandleQueuedNotice($notice)
|
||||||
{
|
{
|
||||||
|
if (!$this->enabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$publisher = new Publisher($this->hub);
|
$publisher = new Publisher($this->hub);
|
||||||
|
|
||||||
$feeds = array();
|
$feeds = array();
|
||||||
@ -211,13 +232,20 @@ class PubSubHubBubPlugin extends Plugin
|
|||||||
'format' => 'atom'));
|
'format' => 'atom'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$feeds = array_unique($feeds);
|
||||||
|
|
||||||
foreach (array_unique($feeds) as $feed) {
|
ob_start();
|
||||||
if (!$publisher->publish_update($feed)) {
|
$ok = $publisher->publish_update($feeds);
|
||||||
common_log_line(LOG_WARNING,
|
$push_last_response = ob_get_clean();
|
||||||
$feed.' was not published to hub at '.
|
|
||||||
$this->hub.':'.$publisher->last_response());
|
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;
|
return true;
|
||||||
@ -236,16 +264,21 @@ class PubSubHubBubPlugin extends Plugin
|
|||||||
|
|
||||||
function onPluginVersion(&$versions)
|
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',
|
$versions[] = array('name' => 'PubSubHubBub',
|
||||||
'version' => STATUSNET_VERSION,
|
'version' => STATUSNET_VERSION,
|
||||||
'author' => 'Craig Andrews',
|
'author' => 'Craig Andrews',
|
||||||
'homepage' =>
|
'homepage' =>
|
||||||
'http://status.net/wiki/Plugin:PubSubHubBub',
|
'http://status.net/wiki/Plugin:PubSubHubBub',
|
||||||
'rawdescription' =>
|
'rawdescription' =>
|
||||||
_m('The PubSubHubBub plugin pushes RSS/Atom updates '.
|
$about);
|
||||||
'to a <a href = "'.
|
|
||||||
'http://pubsubhubbub.googlecode.com/'.
|
|
||||||
'">PubSubHubBub</a> hub.'));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ class RealtimePlugin extends Plugin
|
|||||||
$scripts = $this->_getScripts();
|
$scripts = $this->_getScripts();
|
||||||
|
|
||||||
foreach ($scripts as $script) {
|
foreach ($scripts as $script) {
|
||||||
$action->script($script);
|
$action->script(common_path($script));
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
@ -18,7 +18,8 @@ display:none;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.realtime-popup #form_notice label[for=notice_data-attach],
|
.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;
|
top:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Zach Copley <zach@status.net>
|
* @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
|
* @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://laconi.ca/
|
||||||
*/
|
*/
|
||||||
@ -41,6 +42,7 @@ define('TWITTERBRIDGEPLUGIN_VERSION', '0.9');
|
|||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Zach Copley <zach@status.net>
|
* @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
|
* @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://laconi.ca/
|
||||||
* @link http://twitter.com/
|
* @link http://twitter.com/
|
||||||
@ -72,6 +74,27 @@ class TwitterBridgePlugin extends Plugin
|
|||||||
$m->connect('twitter/authorization',
|
$m->connect('twitter/authorization',
|
||||||
array('action' => 'twitterauthorization'));
|
array('action' => 'twitterauthorization'));
|
||||||
$m->connect('settings/twitter', array('action' => 'twittersettings'));
|
$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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -108,6 +131,7 @@ class TwitterBridgePlugin extends Plugin
|
|||||||
switch ($cls) {
|
switch ($cls) {
|
||||||
case 'TwittersettingsAction':
|
case 'TwittersettingsAction':
|
||||||
case 'TwitterauthorizationAction':
|
case 'TwitterauthorizationAction':
|
||||||
|
case 'TwitterloginAction':
|
||||||
include_once INSTALLDIR . '/plugins/TwitterBridge/' .
|
include_once INSTALLDIR . '/plugins/TwitterBridge/' .
|
||||||
strtolower(mb_substr($cls, 0, -6)) . '.php';
|
strtolower(mb_substr($cls, 0, -6)) . '.php';
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* @category TwitterauthorizationAction
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Zach Copely <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
* @copyright 2009 StatusNet, Inc.
|
* @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
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @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
|
* (Foreign_link) between the StatusNet user and Twitter user and stores the
|
||||||
* access token and secret in the link.
|
* access token and secret in the link.
|
||||||
*
|
*
|
||||||
* @category Twitter
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Zach Copley <zach@status.net>
|
* @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
|
* @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://laconi.ca/
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class TwitterauthorizationAction extends Action
|
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.
|
* Initialize class members. Looks for 'oauth_token' parameter.
|
||||||
*
|
*
|
||||||
@ -61,6 +68,7 @@ class TwitterauthorizationAction extends Action
|
|||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$this->signin = $this->boolean('signin');
|
||||||
$this->oauth_token = $this->arg('oauth_token');
|
$this->oauth_token = $this->arg('oauth_token');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -77,10 +85,7 @@ class TwitterauthorizationAction extends Action
|
|||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
|
||||||
if (!common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$this->clientError(_m('Not logged in.'), 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||||
|
|
||||||
@ -90,7 +95,42 @@ class TwitterauthorizationAction extends Action
|
|||||||
if (isset($flink)) {
|
if (isset($flink)) {
|
||||||
common_redirect(common_local_url('twittersettings'));
|
common_redirect(common_local_url('twittersettings'));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
|
||||||
|
// User was not logged in to StatusNet before
|
||||||
|
|
||||||
|
$this->twuid = $this->trimmed('twuid');
|
||||||
|
|
||||||
|
$this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'),
|
||||||
|
'fullname' => $this->trimmed('tw_fields_fullname'));
|
||||||
|
|
||||||
|
$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->oauth_token is only populated once Twitter authorizes our
|
// $this->oauth_token is only populated once Twitter authorizes our
|
||||||
// request token. If it's empty we're at the beginning of the auth
|
// request token. If it's empty we're at the beginning of the auth
|
||||||
// process
|
// process
|
||||||
@ -101,6 +141,7 @@ class TwitterauthorizationAction extends Action
|
|||||||
$this->saveAccessToken();
|
$this->saveAccessToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asks Twitter for a request token, and then redirects to Twitter
|
* Asks Twitter for a request token, and then redirects to Twitter
|
||||||
@ -123,7 +164,7 @@ class TwitterauthorizationAction extends Action
|
|||||||
$_SESSION['twitter_request_token'] = $req_tok->key;
|
$_SESSION['twitter_request_token'] = $req_tok->key;
|
||||||
$_SESSION['twitter_request_token_secret'] = $req_tok->secret;
|
$_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) {
|
} catch (OAuthClientException $e) {
|
||||||
$msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
|
$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.'));
|
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$twitter_user = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
$client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
|
$client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
|
||||||
@ -165,40 +208,54 @@ class TwitterauthorizationAction extends Action
|
|||||||
$twitter_user = $client->verifyCredentials();
|
$twitter_user = $client->verifyCredentials();
|
||||||
|
|
||||||
} catch (OAuthClientException $e) {
|
} 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());
|
$e->getCode(), $e->getMessage());
|
||||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
|
|
||||||
// Save the access token and Twitter user info
|
// Save the access token and Twitter user info
|
||||||
|
|
||||||
$this->saveForeignLink($atok, $twitter_user);
|
$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
|
// Clean up the the mess we made in the session
|
||||||
|
|
||||||
unset($_SESSION['twitter_request_token']);
|
unset($_SESSION['twitter_request_token']);
|
||||||
unset($_SESSION['twitter_request_token_secret']);
|
unset($_SESSION['twitter_request_token_secret']);
|
||||||
|
|
||||||
|
if (common_logged_in()) {
|
||||||
common_redirect(common_local_url('twittersettings'));
|
common_redirect(common_local_url('twittersettings'));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a Foreign_link between Twitter user and local user,
|
* Saves a Foreign_link between Twitter user and local user,
|
||||||
* which includes the access token and secret.
|
* which includes the access token and secret.
|
||||||
*
|
*
|
||||||
* @param OAuthToken $access_token the access token to save
|
* @param int $user_id StatusNet user ID
|
||||||
* @param mixed $twitter_user twitter API user object
|
* @param int $twuid Twitter user ID
|
||||||
|
* @param OAuthToken $token the access token to save
|
||||||
*
|
*
|
||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
function saveForeignLink($access_token, $twitter_user)
|
function saveForeignLink($user_id, $twuid, $access_token)
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$flink = new Foreign_link();
|
$flink = new Foreign_link();
|
||||||
|
|
||||||
$flink->user_id = $user->id;
|
$flink->user_id = $user_id;
|
||||||
$flink->foreign_id = $twitter_user->id;
|
$flink->foreign_id = $twuid;
|
||||||
$flink->service = TWITTER_SERVICE;
|
$flink->service = TWITTER_SERVICE;
|
||||||
|
|
||||||
$creds = TwitterOAuthClient::packToken($access_token);
|
$creds = TwitterOAuthClient::packToken($access_token);
|
||||||
@ -214,10 +271,325 @@ class TwitterauthorizationAction extends Action
|
|||||||
|
|
||||||
if (empty($flink_id)) {
|
if (empty($flink_id)) {
|
||||||
common_log_db_error($flink, 'INSERT', __FILE__);
|
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 $requestTokenURL = 'https://twitter.com/oauth/request_token';
|
||||||
public static $authorizeURL = 'https://twitter.com/oauth/authorize';
|
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';
|
public static $accessTokenURL = 'https://twitter.com/oauth/access_token';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,9 +98,11 @@ class TwitterOAuthClient extends OAuthClient
|
|||||||
*
|
*
|
||||||
* @return the link
|
* @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,
|
$request_token,
|
||||||
common_local_url('twitterauthorization'));
|
common_local_url('twitterauthorization'));
|
||||||
}
|
}
|
||||||
|
@ -121,8 +121,35 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
$this->elementEnd('p');
|
$this->elementEnd('p');
|
||||||
$this->element('p', 'form_note',
|
$this->element('p', 'form_note',
|
||||||
_m('Connected Twitter account'));
|
_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');
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
@ -205,7 +232,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
if ($this->arg('save')) {
|
if ($this->arg('save')) {
|
||||||
$this->savePreferences();
|
$this->savePreferences();
|
||||||
} else if ($this->arg('remove')) {
|
} else if ($this->arg('disconnect')) {
|
||||||
$this->removeTwitterAccount();
|
$this->removeTwitterAccount();
|
||||||
} else {
|
} else {
|
||||||
$this->showForm(_m('Unexpected form submission.'));
|
$this->showForm(_m('Unexpected form submission.'));
|
||||||
@ -231,7 +258,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showForm(_m('Twitter account removed.'), true);
|
$this->showForm(_m('Twitter account disconnected.'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,11 +45,13 @@ function read_input_line($prompt)
|
|||||||
if (CONSOLE_INTERACTIVE) {
|
if (CONSOLE_INTERACTIVE) {
|
||||||
if (CONSOLE_READLINE) {
|
if (CONSOLE_READLINE) {
|
||||||
$line = readline($prompt);
|
$line = readline($prompt);
|
||||||
|
if (trim($line) != '') {
|
||||||
readline_add_history($line);
|
readline_add_history($line);
|
||||||
if (defined('CONSOLE_HISTORY')) {
|
if (defined('CONSOLE_HISTORY')) {
|
||||||
// Save often; it's easy to hit fatal errors.
|
// Save often; it's easy to hit fatal errors.
|
||||||
readline_write_history(CONSOLE_HISTORY);
|
readline_write_history(CONSOLE_HISTORY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $line;
|
return $line;
|
||||||
} else {
|
} else {
|
||||||
return readline_emulation($prompt);
|
return readline_emulation($prompt);
|
||||||
|
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__) . '/..'));
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
|
|
||||||
$shortoptions = 'fi:at:';
|
$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
|
* 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');
|
$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'));
|
$daemonize = !(have_option('f') || have_option('--foreground'));
|
||||||
$all = have_option('a') || have_option('--all');
|
$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 = new QueueDaemon($id, $daemonize, $threads, $all);
|
||||||
$daemon->runOnce();
|
$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 BACKGROUNDBASE=/var/www/background.example.net
|
||||||
export FILEBASE=/var/www/file.example.net
|
export FILEBASE=/var/www/file.example.net
|
||||||
export PWDGEN="pwgen 20"
|
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
|
source /etc/statusnet/setup.cfg
|
||||||
|
|
||||||
export nickname=$1
|
# setup_status_net.sh mysite 'My Site' '1user' 'owner@example.com' 'Firsty McLastname'
|
||||||
export sitename=$2
|
|
||||||
|
|
||||||
|
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 password=`$PWDGEN`
|
||||||
export database=$nickname$DBBASE
|
export database=$nickname$DBBASE
|
||||||
export username=$nickname$USERBASE
|
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'@'localhost' IDENTIFIED BY '$password';
|
||||||
GRANT ALL ON $database.* TO '$username'@'%' IDENTIFIED BY '$password';
|
GRANT ALL ON $database.* TO '$username'@'%' IDENTIFIED BY '$password';
|
||||||
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created)
|
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created, tags)
|
||||||
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now());
|
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now(), '$tags');
|
||||||
|
|
||||||
ENDOFCOMMANDS
|
ENDOFCOMMANDS
|
||||||
|
|
||||||
@ -30,3 +44,39 @@ for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do
|
|||||||
mkdir $top/$nickname
|
mkdir $top/$nickname
|
||||||
chmod a+w $top/$nickname
|
chmod a+w $top/$nickname
|
||||||
done
|
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');
|
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_recover legend,
|
||||||
#form_password_change legend,
|
#form_password_change legend,
|
||||||
.form_entity_block legend,
|
.form_entity_block legend,
|
||||||
#form_filter_bytag legend {
|
#form_filter_bytag legend,
|
||||||
|
#apioauthauthorize_allowdeny {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,9 +896,63 @@ font-weight:normal;
|
|||||||
margin-right:11px;
|
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 */
|
||||||
.notice,
|
.notice,
|
||||||
.profile {
|
.profile,
|
||||||
|
.application {
|
||||||
position:relative;
|
position:relative;
|
||||||
padding-top:11px;
|
padding-top:11px;
|
||||||
padding-bottom:11px;
|
padding-bottom:11px;
|
||||||
@ -989,7 +1044,12 @@ margin-left:0;
|
|||||||
margin-left:110px;
|
margin-left:110px;
|
||||||
}
|
}
|
||||||
#shownotice .notice .entry-title {
|
#shownotice .notice .entry-title {
|
||||||
|
margin-left:110px;
|
||||||
font-size:2.2em;
|
font-size:2.2em;
|
||||||
|
min-height:123px;
|
||||||
|
}
|
||||||
|
#shownotice .notice div.entry-content {
|
||||||
|
margin-left:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice p.entry-content {
|
.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