Workflow for registering new OAuth apps pretty much done.

This commit is contained in:
Zach Copley 2009-11-16 16:58:49 -08:00
parent 8e0499a233
commit dad67b030f
12 changed files with 950 additions and 83 deletions

View File

@ -31,7 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1); exit(1);
} }
require_once INSTALLDIR . '/lib/connectsettingsaction.php'; require_once INSTALLDIR . '/lib/settingsaction.php';
require_once INSTALLDIR . '/lib/applicationlist.php';
/** /**
* Show a user's registered OAuth applications * Show a user's registered OAuth applications
@ -45,8 +46,23 @@ require_once INSTALLDIR . '/lib/connectsettingsaction.php';
* @see SettingsAction * @see SettingsAction
*/ */
class AppsAction extends ConnectSettingsAction class AppsAction 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 * Title of the page
* *
@ -79,6 +95,49 @@ class AppsAction extends ConnectSettingsAction
{ {
$user = common_current_user(); $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->element('a',
array('href' => common_local_url(
'newapplication',
array('nickname' => $user->nickname)
)
),
'Register a new application »');
$this->pagination(
$this->page > 1,
$cnt > APPS_PER_PAGE,
$this->page,
'apps',
array('nickname' => $user->nickname)
);
}
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');
} }
/** /**

246
actions/editapplication.php Normal file
View File

@ -0,0 +1,246 @@
<?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 $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);
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 group.
*
* @param array $args unused
*
* @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;
}
$cur = common_current_user();
if ($this->arg('cancel')) {
common_redirect(common_local_url('showapplication',
array(
'nickname' => $cur->nickname,
'id' => $this->app->id)
), 303);
} elseif ($this->arg('save')) {
$this->trySave();
} else {
$this->clientError(_('Unexpected form submission.'));
}
} else {
$this->showForm();
}
}
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('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 (empty($callback_url)) {
$this->showForm(_('Callback is required.'));
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));
$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;
if ($access_type == 'r') {
$this->app->setAccessFlags(true, false);
} else {
$this->app->setAccessFlags(true, true);
}
$result = $this->app->update($orig);
if (!$result) {
common_log_db_error($app, 'UPDATE', __FILE__);
$this->serverError(_('Could not update application.'));
}
common_redirect(common_local_url('apps',
array('nickname' => $cur->nickname)), 303);
}
}

View File

@ -43,7 +43,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @link http://status.net/ * @link http://status.net/
*/ */
class NewApplicationAction extends Action class NewApplicationAction extends OwnerDesignAction
{ {
var $msg; var $msg;
@ -61,7 +61,7 @@ class NewApplicationAction extends Action
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.')); $this->clientError(_('You must be logged in to register an application.'));
return false; return false;
} }
@ -81,8 +81,19 @@ class NewApplicationAction extends Action
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->trySave();
$cur = common_current_user();
if ($this->arg('cancel')) {
common_redirect(common_local_url('apps',
array('nickname' => $cur->nickname)), 303);
} elseif ($this->arg('save')) {
$this->trySave();
} else {
$this->clientError(_('Unexpected form submission.'));
}
} else { } else {
$this->showForm(); $this->showForm();
} }
@ -112,55 +123,73 @@ class NewApplicationAction extends Action
function trySave() function trySave()
{ {
$name = $this->trimmed('name'); $name = $this->trimmed('name');
$description = $this->trimmed('description'); $description = $this->trimmed('description');
$source_url = $this->trimmed('source_url'); $source_url = $this->trimmed('source_url');
$organization = $this->trimmed('organization'); $organization = $this->trimmed('organization');
$homepage = $this->trimmed('application'); $homepage = $this->trimmed('homepage');
$callback_url = $this->trimmed('callback_url'); $callback_url = $this->trimmed('callback_url');
$this->type = $this->trimmed('type'); $type = $this->arg('app_type');
$this->access_type = $this->trimmed('access_type'); $access_type = $this->arg('access_type');
if (!is_null($name) && mb_strlen($name) > 255) { if (empty($name)) {
$this->showForm(_('Name is required.'));
return;
} elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); $this->showForm(_('Name is too long (max 255 chars).'));
return; return;
} else if (User_group::descriptionTooLong($description)) { } elseif (empty($description)) {
$this->showForm(_('Description is required.'));
return;
} elseif (Oauth_application::descriptionTooLong($description)) {
$this->showForm(sprintf( $this->showForm(sprintf(
_('description is too long (max %d chars).'), _('Description is too long (max %d chars).'),
Oauth_application::maxDescription())); Oauth_application::maxDescription()));
return; return;
} elseif (!is_null($source_url) } elseif (empty($source_url)) {
&& (strlen($source_url) > 0) $this->showForm(_('Source URL is required.'));
return;
} elseif ((strlen($source_url) > 0)
&& !Validate::uri( && !Validate::uri(
$source_url, $source_url,
array('allowed_schemes' => array('http', 'https')) array('allowed_schemes' => array('http', 'https'))
) )
) )
{ {
$this->showForm(_('Source URL is not valid.')); $this->showForm(_('Source URL is not valid.'));
return; return;
} elseif (!is_null($homepage) } elseif (empty($organization)) {
&& (strlen($homepage) > 0) $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( && !Validate::uri(
$homepage, $homepage,
array('allowed_schemes' => array('http', 'https')) array('allowed_schemes' => array('http', 'https'))
) )
) )
{ {
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} elseif (!is_null($callback_url) } elseif (empty($callback_url)) {
&& (strlen($callback_url) > 0) $this->showForm(_('Callback is required.'));
return;
} elseif (strlen($callback_url) > 0
&& !Validate::uri( && !Validate::uri(
$source_url, $source_url,
array('allowed_schemes' => array('http', 'https')) array('allowed_schemes' => array('http', 'https'))
) )
) )
{ {
$this->showForm(_('Callback URL is not valid.')); $this->showForm(_('Callback URL is not valid.'));
return; return;
} }
$cur = common_current_user(); $cur = common_current_user();
// Checked in prepare() above // Checked in prepare() above
@ -171,31 +200,53 @@ class NewApplicationAction extends Action
$app->query('BEGIN'); $app->query('BEGIN');
$app->name = $name; $app->name = $name;
$app->owner = $cur->id; $app->owner = $cur->id;
$app->description = $description; $app->description = $description;
$app->source_url = $souce_url; $app->source_url = $source_url;
$app->organization = $organization; $app->organization = $organization;
$app->homepage = $homepage; $app->homepage = $homepage;
$app->callback_url = $callback_url; $app->callback_url = $callback_url;
$app->type = $type; $app->type = $type;
$app->access_type = $access_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 // generate consumer key and secret
$app->created = common_sql_now(); $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;
$result = $app->insert(); $result = $app->insert();
if (!$result) { if (!$result) {
common_log_db_error($group, 'INSERT', __FILE__); common_log_db_error($app, 'INSERT', __FILE__);
$this->serverError(_('Could not create application.')); $this->serverError(_('Could not create application.'));
$app->query('ROLLBACK');
} }
$group->query('COMMIT');
common_redirect($group->homeUrl(), 303); $app->query('COMMIT');
common_redirect(common_local_url('apps',
array('nickname' => $cur->nickname)), 303);
} }
} }

View File

@ -132,4 +132,17 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
$this->elementEnd('div'); $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('apps', array('nickname' => $cur->nickname))),
'here.');
$this->elementEnd('p');
}
} }

306
actions/showapplication.php Normal file
View File

@ -0,0 +1,306 @@
<?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 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();
$this->elementStart('div', 'entity_actions');
$this->element('a',
array('href' =>
common_local_url(
'editapplication',
array(
'nickname' => $this->owner->nickname,
'id' => $this->application->id
)
)
), 'Edit application');
$this->elementStart('form', array(
'id' => 'forma_reset_key',
'class' => 'form_reset_key',
'method' => 'POST',
'action' => common_local_url('showapplication',
array('nickname' => $cur->nickname,
'id' => $this->application->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->submit('reset', _('Reset Consumer key/secret'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
$this->elementEnd('div');
$consumer = $this->application->getConsumer();
$this->elementStart('div', 'entity-application');
$this->elementStart('ul', 'entity_application_details');
$this->elementStart('li', 'entity_application_name');
$this->element('span', array('class' => 'big'), $this->application->name);
$this->raw(sprintf(_(' by %1$s'), $this->application->organization));
$this->elementEnd('li');
$this->element('li', 'entity_application_description', $this->application->description);
$this->elementStart('li', 'entity_application_statistics');
$defaultAccess = ($this->application->access_type & Oauth_application::$writeAccess)
? 'read-write' : 'read-only';
$profile = Profile::staticGet($this->application->owner);
$userCnt = 0; // XXX: count how many users use the app
$this->raw(sprintf(
_('Created by %1$s - %2$s access by default - %3$d users.'),
$profile->getBestName(),
$defaultAccess,
$userCnt
));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementStart('dl', 'entity_consumer_key');
$this->element('dt', null, _('Consumer key'));
$this->element('dd', 'label', $consumer->consumer_key);
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_consumer_secret');
$this->element('dt', null, _('Consumer secret'));
$this->element('dd', 'label', $consumer->consumer_secret);
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_request_token_url');
$this->element('dt', null, _('Request token URL'));
$this->element('dd', 'label', common_local_url('oauthrequesttoken'));
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_access_token_url');
$this->element('dt', null, _('Access token URL'));
$this->element('dd', 'label', common_local_url('oauthaccesstoken'));
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_authorize_url');
$this->element('dt', null, _('Authorize URL'));
$this->element('dd', 'label', common_local_url('oauthauthorize'));
$this->elementEnd('dl');
$this->element('p', 'oauth-signature-note',
'*We support hmac-sha1 signatures. We do not support the plaintext signature method.');
$this->elementEnd('div');
$this->elementStart('div', 'entity-list-apps');
$this->element('a',
array(
'href' => common_local_url(
'apps',
array('nickname' => $this->owner->nickname)
)
),
'View your applications');
$this->elementEnd('div');
}
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();
}
}

View File

@ -4,7 +4,7 @@
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Consumer extends Memcached_DataObject class Consumer extends Memcached_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */ /* the code below is auto generated do not remove the above tag */
@ -22,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;
}
} }

View File

@ -31,4 +31,48 @@ class Oauth_application 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
// 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;
}
}
} }

View File

@ -219,7 +219,7 @@ create table oauth_application (
organization varchar(255) comment 'name of the organization running the application', organization varchar(255) comment 'name of the organization running the application',
homepage varchar(255) comment 'homepage for the organization', homepage varchar(255) comment 'homepage for the organization',
callback_url varchar(255) not null comment 'url to redirect to after authentication', callback_url varchar(255) not null comment 'url to redirect to after authentication',
type tinyint default 0 comment 'type of app, 0 = browser, 1 = desktop', 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', 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', 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'

View File

@ -100,11 +100,16 @@ class ApplicationEditForm extends Form
function action() function action()
{ {
if ($this->application) { $cur = common_current_user();
if (!empty($this->application)) {
return common_local_url('editapplication', return common_local_url('editapplication',
array('id' => $this->application->id)); array('id' => $this->application->id,
'nickname' => $cur->nickname)
);
} else { } else {
return common_local_url('newapplication'); return common_local_url('newapplication',
array('nickname' => $cur->nickname));
} }
} }
@ -116,7 +121,7 @@ class ApplicationEditForm extends Form
function formLegend() function formLegend()
{ {
$this->out->element('legend', null, _('Register a new application')); $this->out->element('legend', null, _('Edit application'));
} }
/** /**
@ -130,7 +135,7 @@ class ApplicationEditForm extends Form
if ($this->application) { if ($this->application) {
$id = $this->application->id; $id = $this->application->id;
$name = $this->application->name; $name = $this->application->name;
$description = $this->application->description; $description = $this->application->description;
$source_url = $this->application->source_url; $source_url = $this->application->source_url;
$organization = $this->application->organization; $organization = $this->application->organization;
$homepage = $this->application->homepage; $homepage = $this->application->homepage;
@ -151,34 +156,46 @@ class ApplicationEditForm extends Form
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->hidden('application_id', $id); $this->out->hidden('application_id', $id);
$this->out->hidden('token', common_session_token());
$this->out->input('name', _('Name'), $this->out->input('name', _('Name'),
($this->out->arg('name')) ? $this->out->arg('name') : $name); ($this->out->arg('name')) ? $this->out->arg('name') : $name);
$this->out->elementEnd('li'); $this->out->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->input('description', _('Description'),
($this->out->arg('Description')) ? $this->out->arg('discription') : $description); $maxDesc = Oauth_application::maxDesc();
if ($maxDesc > 0) {
$descInstr = sprintf(_('Describe your application in %d chars'),
$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->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->input('source_url', _('Source URL'), $this->out->input('source_url', _('Source URL'),
($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url, ($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url,
_('URL of the homepage of this application')); _('URL of the homepage of this application'));
$this->out->elementEnd('li'); $this->out->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->input('Organization', _('Organization'), $this->out->input('organization', _('Organization'),
($this->out->arg('organization')) ? $this->out->arg('organization') : $orgranization, ($this->out->arg('organization')) ? $this->out->arg('organization') : $organization,
_('Organization responsible for this application')); _('Organization responsible for this application'));
$this->out->elementEnd('li'); $this->out->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->input('homepage', _('Homepage'), $this->out->input('homepage', _('Homepage'),
($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage, ($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
_('URL of the homepage of the organization')); _('URL for the homepage of the organization'));
$this->out->elementEnd('li'); $this->out->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
@ -188,17 +205,86 @@ class ApplicationEditForm extends Form
$this->out->elementEnd('li'); $this->out->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->input('type', _('Application type'),
($this->out->arg('type')) ? $this->out->arg('type') : $type, $attrs = array('name' => 'app_type',
_('Type of application, browser or desktop')); 'type' => 'radio',
'id' => 'app_type-browser',
'class' => 'radio',
'value' => Oauth_application::$browser);
// Default to Browser
if ($this->application->type == Oauth_application::$browser
|| empty($this->applicaiton->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->elementEnd('li');
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->out->input('access_type', _('Default access'),
($this->out->arg('access_type')) ? $this->out->arg('access_type') : $access_type, $attrs = array('name' => 'default_access_type',
_('Default access for this application: read-write, or read-only')); '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('li');
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
} }
@ -210,6 +296,7 @@ class ApplicationEditForm extends Form
function formActions() function formActions()
{ {
$this->out->submit('submit', _('Save')); $this->out->submit('save', _('Save'));
$this->out->submit('cancel', _('Cancel'));
} }
} }

View File

@ -20,7 +20,7 @@
* 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 Public * @category Application
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
@ -39,7 +39,7 @@ define('APPS_PER_PAGE', 20);
/** /**
* Widget to show a list of OAuth applications * Widget to show a list of OAuth applications
* *
* @category Public * @category Application
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @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 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
@ -50,10 +50,10 @@ class ApplicationList extends Widget
{ {
/** Current application, application query */ /** Current application, application query */
var $application = null; var $application = null;
/** Owner of this list */ /** Owner of this list */
var $owner = null; var $owner = null;
/** Action object using us. */ /** Action object using us. */
var $action = null; var $action = null;
@ -87,14 +87,42 @@ class ApplicationList extends Widget
function showApplication() function showApplication()
{ {
$this->out->elementStart('li', array('class' => 'application',
'id' => 'oauthclient-' . $this->application->id));
$user = common_current_user(); $user = common_current_user();
$this->out->raw($this->application->name); $this->out->elementStart('li', array('class' => 'application',
'id' => 'oauthclient-' . $this->application->id));
$this->out->elementEnd('li');
$this->out->elementStart('a',
array('href' => common_local_url(
'showapplication',
array(
'nickname' => $user->nickname,
'id' => $this->application->id
)
),
'class' => 'url')
);
$this->out->raw($this->application->name);
$this->out->elementEnd('a');
$this->out->raw(' by ');
$this->out->elementStart('a',
array(
'href' => $this->application->homepage,
'class' => 'url'
)
);
$this->out->raw($this->application->organization);
$this->out->elementEnd('a');
$this->out->elementStart('p', 'note');
$this->out->raw($this->application->description);
$this->out->elementEnd('p');
$this->out->elementEnd('li');
} }
/* Override this in subclasses. */ /* Override this in subclasses. */

View File

@ -204,6 +204,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),

View File

@ -641,12 +641,29 @@ class Router
array('nickname' => '[a-zA-Z0-9]{1,64}')); array('nickname' => '[a-zA-Z0-9]{1,64}'));
} }
$m->connect('apps/new', array('action' => 'newapplication')); $m->connect(':nickname/apps',
array('action' => 'apps'),
$m->connect(':nickname/apps/edit', array('nickname' => '['.NICKNAME_FMT.']{1,64}'));
array('action' => 'editapplication'), $m->connect(':nickname/apps/show/:id',
array('nickname' => '['.NICKNAME_FMT.']{1,64}') array('action' => 'showapplication'),
array('nickname' => '['.NICKNAME_FMT.']{1,64}',
'id' => '[0-9]+')
); );
$m->connect(':nickname/apps/new',
array('action' => 'newapplication'),
array('nickname' => '['.NICKNAME_FMT.']{1,64}'));
$m->connect(':nickname/apps/edit/:id',
array('action' => 'editapplication'),
array('nickname' => '['.NICKNAME_FMT.']{1,64}',
'id' => '[0-9]+')
);
$m->connect('oauth/request_token',
array('action' => 'oauthrequesttoken'));
$m->connect('oauth/access_token',
array('action' => 'oauthaccesstoken'));
$m->connect('oauth/authorize',
array('action' => 'oauthauthorize'));
foreach (array('subscriptions', 'subscribers') as $a) { foreach (array('subscriptions', 'subscribers') as $a) {
$m->connect(':nickname/'.$a.'/:tag', $m->connect(':nickname/'.$a.'/:tag',