summaryrefslogtreecommitdiff
path: root/actions
diff options
context:
space:
mode:
Diffstat (limited to 'actions')
-rw-r--r--actions/apiaccountverifycredentials.php14
-rw-r--r--actions/apioauthaccesstoken.php94
-rw-r--r--actions/apioauthauthorize.php376
-rw-r--r--actions/apioauthrequesttoken.php99
-rw-r--r--actions/apistatusesupdate.php5
-rw-r--r--actions/designadminpanel.php2
-rw-r--r--actions/doc.php152
-rw-r--r--actions/editapplication.php264
-rw-r--r--actions/emailsettings.php2
-rw-r--r--actions/inbox.php4
-rw-r--r--actions/newapplication.php277
-rw-r--r--actions/oauthappssettings.php166
-rw-r--r--actions/oauthconnectionssettings.php212
-rw-r--r--actions/outbox.php4
-rw-r--r--actions/replies.php2
-rw-r--r--actions/showapplication.php328
-rw-r--r--actions/showfavorites.php4
-rw-r--r--actions/showgroup.php4
-rw-r--r--actions/showstream.php2
-rw-r--r--actions/tag.php6
-rw-r--r--actions/usergroups.php4
21 files changed, 1968 insertions, 53 deletions
diff --git a/actions/apiaccountverifycredentials.php b/actions/apiaccountverifycredentials.php
index 08b201dbf..1095d5162 100644
--- a/actions/apiaccountverifycredentials.php
+++ b/actions/apiaccountverifycredentials.php
@@ -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;
+ }
+
}
diff --git a/actions/apioauthaccesstoken.php b/actions/apioauthaccesstoken.php
new file mode 100644
index 000000000..085ef6f0b
--- /dev/null
+++ b/actions/apioauthaccesstoken.php
@@ -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_WARN, '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";
+ }
+}
+
diff --git a/actions/apioauthauthorize.php b/actions/apioauthauthorize.php
new file mode 100644
index 000000000..fa074c4e7
--- /dev/null
+++ b/actions/apioauthauthorize.php
@@ -0,0 +1,376 @@
+<?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>%s</strong> by <strong>%s</strong> would like " .
+ "the ability to <strong>%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()
+ {
+ }
+
+}
diff --git a/actions/apioauthrequesttoken.php b/actions/apioauthrequesttoken.php
new file mode 100644
index 000000000..467640b9a
--- /dev/null
+++ b/actions/apioauthrequesttoken.php
@@ -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_WARN, 'API OAuthException - ' . $e->getMessage());
+ header('HTTP/1.1 401 Unauthorized');
+ header('Content-Type: text/html; charset=utf-8');
+ print $e->getMessage() . "\n";
+ }
+ }
+
+}
diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php
index 9d831b9db..31c9b20ce 100644
--- a/actions/apistatusesupdate.php
+++ b/actions/apistatusesupdate.php
@@ -85,6 +85,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$this->lat = $this->trimmed('lat');
$this->lon = $this->trimmed('long');
+ // try to set the source attr from OAuth app
+ if (empty($this->source)) {
+ $this->source = $this->oauth_source;
+ }
+
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
$this->source = 'api';
}
diff --git a/actions/designadminpanel.php b/actions/designadminpanel.php
index f862aff0e..72ad6ade2 100644
--- a/actions/designadminpanel.php
+++ b/actions/designadminpanel.php
@@ -289,7 +289,7 @@ class DesignadminpanelAction extends AdminPanelAction
function showStylesheets()
{
parent::showStylesheets();
- $this->cssLink('css/farbtastic.css','base','screen, projection, tv');
+ $this->cssLink('js/farbtastic/farbtastic.css',null,'screen, projection, tv');
}
/**
diff --git a/actions/doc.php b/actions/doc.php
index 836f039d3..25d363472 100644
--- a/actions/doc.php
+++ b/actions/doc.php
@@ -45,11 +45,23 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/
class DocAction extends Action
{
- var $filename;
- var $title;
+ var $output = null;
+ var $filename = null;
+ var $title = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->title = $this->trimmed('title');
+ $this->output = null;
+
+ $this->loadDoc();
+ return true;
+ }
/**
- * Class handler.
+ * Handle a request
*
* @param array $args array of arguments
*
@@ -58,51 +70,51 @@ class DocAction extends Action
function handle($args)
{
parent::handle($args);
-
- $this->title = $this->trimmed('title');
- $this->output = null;
-
- if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
-
- $this->filename = INSTALLDIR.'/doc-src/'.$this->title;
- if (!file_exists($this->filename)) {
- $this->clientError(_('No such document.'));
- return;
- }
-
- $c = file_get_contents($this->filename);
- $this->output = common_markup_to_html($c);
-
- Event::handle('EndLoadDoc', array($this->title, &$this->output));
- }
-
$this->showPage();
}
- // overrrided to add entry-title class
- function showPageTitle() {
+ /**
+ * Page title
+ *
+ * Gives the page title of the document. Override default for hAtom entry.
+ *
+ * @return void
+ */
+
+ function showPageTitle()
+ {
$this->element('h1', array('class' => 'entry-title'), $this->title());
}
- // overrided to add hentry, and content-inner classes
+ /**
+ * Block for content.
+ *
+ * Overrides default from Action to wrap everything in an hAtom entry.
+ *
+ * @return void.
+ */
+
function showContentBlock()
- {
- $this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
- $this->showPageTitle();
- $this->showPageNoticeBlock();
- $this->elementStart('div', array('id' => 'content_inner',
- 'class' => 'entry-content'));
- // show the actual content (forms, lists, whatever)
- $this->showContent();
- $this->elementEnd('div');
- $this->elementEnd('div');
- }
+ {
+ $this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
+ $this->showPageTitle();
+ $this->showPageNoticeBlock();
+ $this->elementStart('div', array('id' => 'content_inner',
+ 'class' => 'entry-content'));
+ // show the actual content (forms, lists, whatever)
+ $this->showContent();
+ $this->elementEnd('div');
+ $this->elementEnd('div');
+ }
/**
* Display content.
*
- * @return nothing
+ * Shows the content of the document.
+ *
+ * @return void
*/
+
function showContent()
{
$this->raw($this->output);
@@ -111,6 +123,8 @@ class DocAction extends Action
/**
* Page title.
*
+ * Uses the title of the document.
+ *
* @return page title
*/
function title()
@@ -118,8 +132,74 @@ class DocAction extends Action
return ucfirst($this->title);
}
+ /**
+ * These pages are read-only.
+ *
+ * @param array $args unused.
+ *
+ * @return boolean read-only flag (false)
+ */
+
function isReadOnly($args)
{
return true;
}
+
+ function loadDoc()
+ {
+ if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
+
+ $this->filename = $this->getFilename();
+
+ if (empty($this->filename)) {
+ throw new ClientException(sprintf(_('No such document "%s"'), $this->title), 404);
+ }
+
+ $c = file_get_contents($this->filename);
+
+ $this->output = common_markup_to_html($c);
+
+ Event::handle('EndLoadDoc', array($this->title, &$this->output));
+ }
+ }
+
+ function getFilename()
+ {
+ if (file_exists(INSTALLDIR.'/local/doc-src/'.$this->title)) {
+ $localDef = INSTALLDIR.'/local/doc-src/'.$this->title;
+ }
+
+ $local = glob(INSTALLDIR.'/local/doc-src/'.$this->title.'.*');
+
+ if (count($local) || isset($localDef)) {
+ return $this->negotiateLanguage($local, $localDef);
+ }
+
+ if (file_exists(INSTALLDIR.'/doc-src/'.$this->title)) {
+ $distDef = INSTALLDIR.'/doc-src/'.$this->title;
+ }
+
+ $dist = glob(INSTALLDIR.'/doc-src/'.$this->title.'.*');
+
+ if (count($dist) || isset($distDef)) {
+ return $this->negotiateLanguage($dist, $distDef);
+ }
+
+ return null;
+ }
+
+ function negotiateLanguage($filenames, $defaultFilename=null)
+ {
+ // XXX: do this better
+
+ $langcode = common_language();
+
+ foreach ($filenames as $filename) {
+ if (preg_match('/\.'.$langcode.'$/', $filename)) {
+ return $filename;
+ }
+ }
+
+ return $defaultFilename;
+ }
}
diff --git a/actions/editapplication.php b/actions/editapplication.php
new file mode 100644
index 000000000..9cc3e3cea
--- /dev/null
+++ b/actions/editapplication.php
@@ -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);
+ }
+
+}
+
diff --git a/actions/emailsettings.php b/actions/emailsettings.php
index bfef2970d..08608348c 100644
--- a/actions/emailsettings.php
+++ b/actions/emailsettings.php
@@ -130,7 +130,7 @@ class EmailsettingsAction extends AccountSettingsAction
if (common_config('emailpost', 'enabled') && $user->email) {
$this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
- $this->element('legend',_('Incoming email'));
+ $this->element('legend', null, _('Incoming email'));
if ($user->incomingemail) {
$this->elementStart('p');
$this->element('span', 'address', $user->incomingemail);
diff --git a/actions/inbox.php b/actions/inbox.php
index f605cc9e8..8330f753f 100644
--- a/actions/inbox.php
+++ b/actions/inbox.php
@@ -56,10 +56,10 @@ class InboxAction extends MailboxAction
function title()
{
if ($this->page > 1) {
- return sprintf(_("Inbox for %1$s - page %2$d"), $this->user->nickname,
+ return sprintf(_('Inbox for %1$s - page %2$d'), $this->user->nickname,
$this->page);
} else {
- return sprintf(_("Inbox for %s"), $this->user->nickname);
+ return sprintf(_('Inbox for %s'), $this->user->nickname);
}
}
diff --git a/actions/newapplication.php b/actions/newapplication.php
new file mode 100644
index 000000000..c499fe7c7
--- /dev/null
+++ b/actions/newapplication.php
@@ -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);
+
+ }
+
+}
+
diff --git a/actions/oauthappssettings.php b/actions/oauthappssettings.php
new file mode 100644
index 000000000..6c0670b17
--- /dev/null
+++ b/actions/oauthappssettings.php
@@ -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;
+ }
+
+ }
+
+}
diff --git a/actions/oauthconnectionssettings.php b/actions/oauthconnectionssettings.php
new file mode 100644
index 000000000..b17729b82
--- /dev/null
+++ b/actions/oauthconnectionssettings.php
@@ -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');
+ }
+
+}
diff --git a/actions/outbox.php b/actions/outbox.php
index de30de018..b81d4b9d0 100644
--- a/actions/outbox.php
+++ b/actions/outbox.php
@@ -55,10 +55,10 @@ class OutboxAction extends MailboxAction
function title()
{
if ($this->page > 1) {
- return sprintf(_("Outbox for %1$s - page %2$d"),
+ return sprintf(_('Outbox for %1$s - page %2$d'),
$this->user->nickname, $page);
} else {
- return sprintf(_("Outbox for %s"), $this->user->nickname);
+ return sprintf(_('Outbox for %s'), $this->user->nickname);
}
}
diff --git a/actions/replies.php b/actions/replies.php
index 2e50f1c3c..164c328db 100644
--- a/actions/replies.php
+++ b/actions/replies.php
@@ -124,7 +124,7 @@ class RepliesAction extends OwnerDesignAction
if ($this->page == 1) {
return sprintf(_("Replies to %s"), $this->user->nickname);
} else {
- return sprintf(_("Replies to %1$s, page %2$d"),
+ return sprintf(_('Replies to %1$s, page %2$d'),
$this->user->nickname,
$this->page);
}
diff --git a/actions/showapplication.php b/actions/showapplication.php
new file mode 100644
index 000000000..049206375
--- /dev/null
+++ b/actions/showapplication.php
@@ -0,0 +1,328 @@
+<?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();
+ }
+
+}
+
diff --git a/actions/showfavorites.php b/actions/showfavorites.php
index 6023f0156..f2d082293 100644
--- a/actions/showfavorites.php
+++ b/actions/showfavorites.php
@@ -74,9 +74,9 @@ class ShowfavoritesAction extends OwnerDesignAction
function title()
{
if ($this->page == 1) {
- return sprintf(_("%s's favorite notices"), $this->user->nickname);
+ return sprintf(_('%s\'s favorite notices'), $this->user->nickname);
} else {
- return sprintf(_("%1$s's favorite notices, page %2$d"),
+ return sprintf(_('%1$s\'s favorite notices, page %2$d'),
$this->user->nickname,
$this->page);
}
diff --git a/actions/showgroup.php b/actions/showgroup.php
index 06ae572e8..8042a4951 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -79,9 +79,9 @@ class ShowgroupAction extends GroupDesignAction
}
if ($this->page == 1) {
- return sprintf(_("%s group"), $base);
+ return sprintf(_('%s group'), $base);
} else {
- return sprintf(_("%1$s group, page %2$d"),
+ return sprintf(_('%1$s group, page %2$d'),
$base,
$this->page);
}
diff --git a/actions/showstream.php b/actions/showstream.php
index 75e10858d..90ff67073 100644
--- a/actions/showstream.php
+++ b/actions/showstream.php
@@ -76,7 +76,7 @@ class ShowstreamAction extends ProfileAction
if ($this->page == 1) {
return $base;
} else {
- return sprintf(_("%1$s, page %2$d"),
+ return sprintf(_('%1$s, page %2$d'),
$base,
$this->page);
}
diff --git a/actions/tag.php b/actions/tag.php
index 12857236e..e91df6ea9 100644
--- a/actions/tag.php
+++ b/actions/tag.php
@@ -63,9 +63,9 @@ class TagAction extends Action
function title()
{
if ($this->page == 1) {
- return sprintf(_("Notices tagged with %s"), $this->tag);
+ return sprintf(_('Notices tagged with %s'), $this->tag);
} else {
- return sprintf(_("Notices tagged with %1$s, page %2$d"),
+ return sprintf(_('Notices tagged with %1$s, page %2$d'),
$this->tag,
$this->page);
}
@@ -85,7 +85,7 @@ class TagAction extends Action
array('tag' => $this->tag)),
sprintf(_('Notice feed for tag %s (RSS 1.0)'),
$this->tag)),
- new Feed(Feed::RSS2,
+ new Feed(Feed::RSS2,
common_local_url('ApiTimelineTag',
array('format' => 'rss',
'tag' => $this->tag)),
diff --git a/actions/usergroups.php b/actions/usergroups.php
index 504226143..97faabae6 100644
--- a/actions/usergroups.php
+++ b/actions/usergroups.php
@@ -59,9 +59,9 @@ class UsergroupsAction extends OwnerDesignAction
function title()
{
if ($this->page == 1) {
- return sprintf(_("%s groups"), $this->user->nickname);
+ return sprintf(_('%s groups'), $this->user->nickname);
} else {
- return sprintf(_("%1$s groups, page %2$d"),
+ return sprintf(_('%1$s groups, page %2$d'),
$this->user->nickname,
$this->page);
}