From 4a2511139eaafcbe93a2e720e0c6f170ecb00d77 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 3 Mar 2010 15:43:49 -0800 Subject: [PATCH 01/30] Initial user role controls on profile pages, for owner to add/remove administrator and moderator options. Buttons need to be themed. --- actions/grantrole.php | 99 ++++++++++++++++++++++++++++++++++++++++ actions/revokerole.php | 99 ++++++++++++++++++++++++++++++++++++++++ classes/Profile.php | 4 ++ classes/Profile_role.php | 17 +++++++ lib/grantroleform.php | 93 +++++++++++++++++++++++++++++++++++++ lib/revokeroleform.php | 93 +++++++++++++++++++++++++++++++++++++ lib/right.php | 2 + lib/router.php | 1 + lib/userprofile.php | 26 +++++++++++ 9 files changed, 434 insertions(+) create mode 100644 actions/grantrole.php create mode 100644 actions/revokerole.php create mode 100644 lib/grantroleform.php create mode 100644 lib/revokeroleform.php diff --git a/actions/grantrole.php b/actions/grantrole.php new file mode 100644 index 0000000000..cd6bd4d79a --- /dev/null +++ b/actions/grantrole.php @@ -0,0 +1,99 @@ +. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Sandbox a user. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + +class GrantRoleAction extends ProfileFormAction +{ + /** + * Check parameters + * + * @param array $args action arguments (URL, GET, POST) + * + * @return boolean success flag + */ + + function prepare($args) + { + if (!parent::prepare($args)) { + return false; + } + + $this->role = $this->arg('role'); + if (!Profile_role::isValid($this->role)) { + $this->clientError(_("Invalid role.")); + return false; + } + if (!Profile_role::isSettable($this->role)) { + $this->clientError(_("This role is reserved and cannot be set.")); + return false; + } + + $cur = common_current_user(); + + assert(!empty($cur)); // checked by parent + + if (!$cur->hasRight(Right::GRANTROLE)) { + $this->clientError(_("You cannot grant user roles on this site.")); + return false; + } + + assert(!empty($this->profile)); // checked by parent + + if ($this->profile->hasRole($this->role)) { + $this->clientError(_("User already has this role.")); + return false; + } + + return true; + } + + /** + * Sandbox a user. + * + * @return void + */ + + function handlePost() + { + $this->profile->grantRole($this->role); + } +} diff --git a/actions/revokerole.php b/actions/revokerole.php new file mode 100644 index 0000000000..b78c1c25a4 --- /dev/null +++ b/actions/revokerole.php @@ -0,0 +1,99 @@ +. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Sandbox a user. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + +class RevokeRoleAction extends ProfileFormAction +{ + /** + * Check parameters + * + * @param array $args action arguments (URL, GET, POST) + * + * @return boolean success flag + */ + + function prepare($args) + { + if (!parent::prepare($args)) { + return false; + } + + $this->role = $this->arg('role'); + if (!Profile_role::isValid($this->role)) { + $this->clientError(_("Invalid role.")); + return false; + } + if (!Profile_role::isSettable($this->role)) { + $this->clientError(_("This role is reserved and cannot be set.")); + return false; + } + + $cur = common_current_user(); + + assert(!empty($cur)); // checked by parent + + if (!$cur->hasRight(Right::REVOKEROLE)) { + $this->clientError(_("You cannot revoke user roles on this site.")); + return false; + } + + assert(!empty($this->profile)); // checked by parent + + if (!$this->profile->hasRole($this->role)) { + $this->clientError(_("User doesn't have this role.")); + return false; + } + + return true; + } + + /** + * Sandbox a user. + * + * @return void + */ + + function handlePost() + { + $this->profile->revokeRole($this->role); + } +} diff --git a/classes/Profile.php b/classes/Profile.php index 9c2fa7a0c5..0322c93588 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -743,6 +743,10 @@ class Profile extends Memcached_DataObject case Right::CONFIGURESITE: $result = $this->hasRole(Profile_role::ADMINISTRATOR); break; + case Right::GRANTROLE: + case Right::REVOKEROLE: + $result = $this->hasRole(Profile_role::OWNER); + break; case Right::NEWNOTICE: case Right::NEWMESSAGE: case Right::SUBSCRIBE: diff --git a/classes/Profile_role.php b/classes/Profile_role.php index bf2c453ed0..d0a0b31f0f 100644 --- a/classes/Profile_role.php +++ b/classes/Profile_role.php @@ -53,4 +53,21 @@ class Profile_role extends Memcached_DataObject const ADMINISTRATOR = 'administrator'; const SANDBOXED = 'sandboxed'; const SILENCED = 'silenced'; + + public static function isValid($role) + { + // @fixme could probably pull this from class constants + $known = array(self::OWNER, + self::MODERATOR, + self::ADMINISTRATOR, + self::SANDBOXED, + self::SILENCED); + return in_array($role, $known); + } + + public static function isSettable($role) + { + $allowedRoles = array('administrator', 'moderator'); + return self::isValid($role) && in_array($role, $allowedRoles); + } } diff --git a/lib/grantroleform.php b/lib/grantroleform.php new file mode 100644 index 0000000000..b5f952746e --- /dev/null +++ b/lib/grantroleform.php @@ -0,0 +1,93 @@ +. + * + * @category Form + * @package StatusNet + * @author Evan Prodromou , Brion Vibber + * @copyright 2009-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Form for sandboxing a user + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see UnSandboxForm + */ + +class GrantRoleForm extends ProfileActionForm +{ + function __construct($role, $label, $writer, $profile, $r2args) + { + parent::__construct($writer, $profile, $r2args); + $this->role = $role; + $this->label = $label; + } + + /** + * Action this form provides + * + * @return string Name of the action, lowercased. + */ + + function target() + { + return 'grantrole'; + } + + /** + * Title of the form + * + * @return string Title of the form, internationalized + */ + + function title() + { + return $this->label; + } + + function formData() + { + parent::formData(); + $this->out->hidden('role', $this->role); + } + + /** + * Description of the form + * + * @return string description of the form, internationalized + */ + + function description() + { + return sprintf(_('Grant this user the "%s" role'), $this->label); + } +} diff --git a/lib/revokeroleform.php b/lib/revokeroleform.php new file mode 100644 index 0000000000..ec24b99101 --- /dev/null +++ b/lib/revokeroleform.php @@ -0,0 +1,93 @@ +. + * + * @category Form + * @package StatusNet + * @author Evan Prodromou , Brion Vibber + * @copyright 2009-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Form for sandboxing a user + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see UnSandboxForm + */ + +class RevokeRoleForm extends ProfileActionForm +{ + function __construct($role, $label, $writer, $profile, $r2args) + { + parent::__construct($writer, $profile, $r2args); + $this->role = $role; + $this->label = $label; + } + + /** + * Action this form provides + * + * @return string Name of the action, lowercased. + */ + + function target() + { + return 'revokerole'; + } + + /** + * Title of the form + * + * @return string Title of the form, internationalized + */ + + function title() + { + return $this->label; + } + + function formData() + { + parent::formData(); + $this->out->hidden('role', $this->role); + } + + /** + * Description of the form + * + * @return string description of the form, internationalized + */ + + function description() + { + return sprintf(_('Revoke the "%s" role from this user'), $this->label); + } +} diff --git a/lib/right.php b/lib/right.php index 4e9c5a918d..deb451fde9 100644 --- a/lib/right.php +++ b/lib/right.php @@ -58,5 +58,7 @@ class Right const EMAILONSUBSCRIBE = 'emailonsubscribe'; const EMAILONFAVE = 'emailonfave'; const MAKEGROUPADMIN = 'makegroupadmin'; + const GRANTROLE = 'grantrole'; + const REVOKEROLE = 'revokerole'; } diff --git a/lib/router.php b/lib/router.php index 7e8e22a7db..15f88c959d 100644 --- a/lib/router.php +++ b/lib/router.php @@ -98,6 +98,7 @@ class Router 'groupblock', 'groupunblock', 'sandbox', 'unsandbox', 'silence', 'unsilence', + 'grantrole', 'revokerole', 'repeat', 'deleteuser', 'geocode', diff --git a/lib/userprofile.php b/lib/userprofile.php index 43dfd05be5..8464c24464 100644 --- a/lib/userprofile.php +++ b/lib/userprofile.php @@ -346,6 +346,16 @@ class UserProfile extends Widget $this->out->elementEnd('ul'); $this->out->elementEnd('li'); } + + if ($cur->hasRight(Right::GRANTROLE)) { + $this->out->elementStart('li', 'entity_role'); + $this->out->element('p', null, _('User role')); + $this->out->elementStart('ul'); + $this->roleButton('administrator', _m('role', 'Administrator')); + $this->roleButton('moderator', _m('role', 'Moderator')); + $this->out->elementEnd('ul'); + $this->out->elementEnd('li'); + } } } @@ -359,6 +369,22 @@ class UserProfile extends Widget } } + function roleButton($role, $label) + { + list($action, $r2args) = $this->out->returnToArgs(); + $r2args['action'] = $action; + + $this->out->elementStart('li', "entity_role_$role"); + if ($this->user->hasRole($role)) { + $rf = new RevokeRoleForm($role, $label, $this->out, $this->profile, $r2args); + $rf->show(); + } else { + $rf = new GrantRoleForm($role, $label, $this->out, $this->profile, $r2args); + $rf->show(); + } + $this->out->elementEnd('li'); + } + function showRemoteSubscribeLink() { $url = common_local_url('remotesubscribe', From 610238442e211940716c83126526a42079007fea Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 19:24:18 -0500 Subject: [PATCH 02/30] Added styles for User Role --- theme/base/css/display.css | 15 ++++++++------ theme/base/images/icons/icons-01.gif | Bin 3740 -> 3788 bytes .../images/icons/twotone/green/clipboard.gif | Bin 0 -> 80 bytes theme/default/css/display.css | 19 +++++++++++++++++- 4 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 theme/base/images/icons/twotone/green/clipboard.gif diff --git a/theme/base/css/display.css b/theme/base/css/display.css index b8dd561ccc..01d5dd134d 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -771,10 +771,12 @@ display:none; text-align:center; } -.entity_moderation { +.entity_moderation, +.entity_role { position:relative; } -.entity_moderation p { +.entity_moderation p, +.entity_role p { border-radius:4px; -moz-border-radius:4px; -webkit-border-radius:4px; @@ -782,13 +784,14 @@ font-weight:bold; padding-bottom:2px; margin-bottom:7px; } -.entity_moderation ul { +.entity_moderation ul, +.entity_role ul { display:none; } -.entity_moderation:hover ul { +.entity_moderation:hover ul, +.entity_role:hover ul { display:block; -min-width:21%; -width:100%; +width:110%; padding:11px; position:absolute; top:-1px; diff --git a/theme/base/images/icons/icons-01.gif b/theme/base/images/icons/icons-01.gif index be884ff48944d2ec4694f426ada7644b0aa0e101..deba4970ded5878546d57a08bd48bfd4c926b290 100644 GIT binary patch delta 107 zcmV-x0F?in9n2jJM@dFFIbj+AmjJ4cqs-P6s&GEs^ljPv=wjXeLDg#Z8lulSRNk&EF!gAM}_0Hrp|GXLOWY?&;^ N*TCi;&&bGN4FFdt5x@Wd diff --git a/theme/base/images/icons/twotone/green/clipboard.gif b/theme/base/images/icons/twotone/green/clipboard.gif new file mode 100644 index 0000000000000000000000000000000000000000..9317bdcd083856423ed6cc5b1c3f377f12ff14f6 GIT binary patch literal 80 zcmZ?wbhEHb6krfwn8?KN|NsB^DFQ%}fq_BsCkrD30~3P|kPVa-0J0TB`erVB%P+`a gc){}R;x2QZs@NHpDL?1V&f26IdDKXlo0Y*D0L~K_-T(jq literal 0 HcmV?d00001 diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 8ae2b40141..8ca267c338 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -49,6 +49,7 @@ box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3); .pagination .nav_next a, .form_settings fieldset fieldset, .entity_moderation:hover ul, +.entity_role:hover ul, .dialogbox { border-color:#DDDDDD; } @@ -67,6 +68,7 @@ input.submit, .entity_actions a, .entity_actions input, .entity_moderation p, +.entity_role p, button { box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); -moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); @@ -127,7 +129,8 @@ a, .notice-options input, .entity_actions a, .entity_actions input, -.entity_moderation p { +.entity_moderation p, +.entity_role p { color:#002FA7; } @@ -190,6 +193,9 @@ button.close, .entity_sandbox input.submit, .entity_silence input.submit, .entity_delete input.submit, +.entity_role p, +.entity_role_administrator input.submit, +.entity_role_moderator input.submit, .notice-options .repeated, .form_notice label[for=notice_data-geo], button.minimize, @@ -229,6 +235,7 @@ border-color:transparent; #site_nav_local_views .current a, .entity_send-a-message .form_notice, .entity_moderation:hover ul, +.entity_role:hover ul, .dialogbox { background-color:#FFFFFF; } @@ -319,6 +326,7 @@ background-position: 5px -852px; } .entity_send-a-message .form_notice, .entity_moderation:hover ul, +.entity_role:hover ul, .dialogbox { box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7); -moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7); @@ -350,6 +358,15 @@ background-position: 5px -1445px; .entity_delete input.submit { background-position: 5px -1511px; } +.entity_role p { +background-position: 5px -2436px; +} +.entity_role_administrator input.submit { +background-position: 5px -983px; +} +.entity_role_moderator input.submit { +background-position: 5px -1313px; +} .form_reset_key input.submit { background-position: 5px -1973px; } From 6ebc0f87231de8f6c4acd28ecbddca227e4b3007 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 19:28:54 -0500 Subject: [PATCH 03/30] Updated identica theme for User Role styles --- theme/identica/css/display.css | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 737e3a1032..bc27cfb4d0 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -49,6 +49,7 @@ box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3); .pagination .nav_next a, .form_settings fieldset fieldset, .entity_moderation:hover ul, +.entity_role:hover ul, .dialogbox { border-color:#DDDDDD; } @@ -67,6 +68,7 @@ input.submit, .entity_actions a, .entity_actions input, .entity_moderation p, +.entity_role p, button { box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); -moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3); @@ -128,7 +130,8 @@ a, .notice-options input, .entity_actions a, .entity_actions input, -.entity_moderation p { +.entity_moderation p, +.entity_role p { color:#002FA7; } @@ -191,6 +194,9 @@ button.close, .entity_sandbox input.submit, .entity_silence input.submit, .entity_delete input.submit, +.entity_role p, +.entity_role_administrator input.submit, +.entity_role_moderator input.submit, .notice-options .repeated, .form_notice label[for=notice_data-geo], button.minimize, @@ -230,6 +236,7 @@ border-color:transparent; #site_nav_local_views .current a, .entity_send-a-message .form_notice, .entity_moderation:hover ul, +.entity_role:hover ul, .dialogbox { background-color:#FFFFFF; } @@ -319,6 +326,7 @@ background-position: 5px -852px; } .entity_send-a-message .form_notice, .entity_moderation:hover ul, +.entity_role:hover ul, .dialogbox { box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7); -moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.7); @@ -350,6 +358,15 @@ background-position: 5px -1445px; .entity_delete input.submit { background-position: 5px -1511px; } +.entity_role p { +background-position: 5px -2436px; +} +.entity_role_administrator input.submit { +background-position: 5px -983px; +} +.entity_role_moderator input.submit { +background-position: 5px -1313px; +} .form_reset_key input.submit { background-position: 5px -1973px; } From 04e474c98c9b907fe2d0f263fad79018a15c0783 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 19:29:59 -0500 Subject: [PATCH 04/30] Updated icons README --- theme/base/images/icons/README | 1 + 1 file changed, 1 insertion(+) diff --git a/theme/base/images/icons/README b/theme/base/images/icons/README index ea582149f5..0451fda494 100644 --- a/theme/base/images/icons/README +++ b/theme/base/images/icons/README @@ -25,6 +25,7 @@ White reject with green background White play with green background White pause with green background + White clipboard with green background */ From 9fadf8da1164d620284917b829329e195aa2a226 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 3 Mar 2010 12:51:23 -0800 Subject: [PATCH 05/30] Put all required field setup into AtomUserNoticeFeed and AtomGroupNoticeFeed, consolidating some code. (RSS feeds pulling title, logo etc from the Atom data structure so we don't dupe it.) OStatus now calling the feed classes directly instead of faking a call into the API, should be less flakey. --- actions/apitimelinegroup.php | 45 ++++-------------- actions/apitimelineuser.php | 51 ++++----------------- lib/atom10feed.php | 20 ++++++-- lib/atomgroupnoticefeed.php | 32 ++++++++++++- lib/atomusernoticefeed.php | 41 ++++++++++++++++- plugins/OStatus/lib/ostatusqueuehandler.php | 39 +++------------- 6 files changed, 113 insertions(+), 115 deletions(-) diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index e30a08fb5d..8f971392bf 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -104,30 +104,21 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction function showTimeline() { - $sitename = common_config('site', 'name'); - $avatar = $this->group->homepage_logo; - $title = sprintf(_("%s timeline"), $this->group->nickname); - - $subtitle = sprintf( - _('Updates from %1$s on %2$s!'), - $this->group->nickname, - $sitename - ); - - $logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE); + // We'll pull common formatting out of this for other formats + $atom = new AtomGroupNoticeFeed($this->group); switch($this->format) { case 'xml': $this->showXmlTimeline($this->notices); break; case 'rss': - $this->showRssTimeline( + $this->showRssTimeline( $this->notices, - $title, + $atom->title, $this->group->homeUrl(), - $subtitle, + $atom->subtitle, null, - $logo + $atom->logo ); break; case 'atom': @@ -136,38 +127,22 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction try { - $atom = new AtomGroupNoticeFeed($this->group); - - // @todo set all this Atom junk up inside the feed class - - #$atom->setId($id); - $atom->setTitle($title); - $atom->setSubtitle($subtitle); - $atom->setLogo($logo); - $atom->setUpdated('now'); - $atom->addAuthorRaw($this->group->asAtomAuthor()); $atom->setActivitySubject($this->group->asActivitySubject()); - $atom->addLink($this->group->homeUrl()); - $id = $this->arg('id'); $aargs = array('format' => 'atom'); if (!empty($id)) { $aargs['id'] = $id; } + $self = $this->getSelfUri('ApiTimelineGroup', $aargs); - $atom->setId($this->getSelfUri('ApiTimelineGroup', $aargs)); - - $atom->addLink( - $this->getSelfUri('ApiTimelineGroup', $aargs), - array('rel' => 'self', 'type' => 'application/atom+xml') - ); + $atom->setId($self); + $atom->setSelfLink($self); $atom->addEntryFromNotices($this->notices); - //$this->raw($atom->getString()); - print $atom->getString(); // temp hack until PuSH feeds are redone cleanly + $this->raw($atom->getString()); } catch (Atom10FeedException $e) { $this->serverError( diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 94491946c2..2d0047c046 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -112,19 +112,17 @@ class ApiTimelineUserAction extends ApiBareAuthAction function showTimeline() { $profile = $this->user->getProfile(); - $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s timeline"), $this->user->nickname); + // We'll use the shared params from the Atom stub + // for other feed types. + $atom = new AtomUserNoticeFeed($this->user); + $title = $atom->title; $link = common_local_url( 'showstream', array('nickname' => $this->user->nickname) ); - $subtitle = sprintf( - _('Updates from %1$s on %2$s!'), - $this->user->nickname, $sitename - ); - $logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE); + $subtitle = $atom->subtitle; + $logo = $atom->logo; // FriendFeed's SUP protocol // Also added RSS and Atom feeds @@ -146,47 +144,18 @@ class ApiTimelineUserAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - // @todo set all this Atom junk up inside the feed class - - $atom = new AtomUserNoticeFeed($this->user); - - $atom->setTitle($title); - $atom->setSubtitle($subtitle); - $atom->setLogo($logo); - $atom->setUpdated('now'); - - $atom->addLink( - common_local_url( - 'showstream', - array('nickname' => $this->user->nickname) - ) - ); - $id = $this->arg('id'); $aargs = array('format' => 'atom'); if (!empty($id)) { $aargs['id'] = $id; } - - $atom->setId($this->getSelfUri('ApiTimelineUser', $aargs)); - - $atom->addLink( - $this->getSelfUri('ApiTimelineUser', $aargs), - array('rel' => 'self', 'type' => 'application/atom+xml') - ); - - $atom->addLink( - $suplink, - array( - 'rel' => 'http://api.friendfeed.com/2008/03#sup', - 'type' => 'application/json' - ) - ); + $self = $this->getSelfUri('ApiTimelineUser', $aargs); + $atom->setId($self); + $atom->setSelfLink($self); $atom->addEntryFromNotices($this->notices); - #$this->raw($atom->getString()); - print $atom->getString(); // temporary for output buffering + $this->raw($atom->getString()); break; case 'json': diff --git a/lib/atom10feed.php b/lib/atom10feed.php index 8842840d56..c1fdeaae93 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -49,6 +49,8 @@ class Atom10FeedException extends Exception class Atom10Feed extends XMLStringer { public $xw; + + // @fixme most of these should probably be read-only properties private $namespaces; private $authors; private $subject; @@ -57,10 +59,12 @@ class Atom10Feed extends XMLStringer private $generator; private $icon; private $links; - private $logo; + private $selfLink; + private $selfLinkType; + public $logo; private $rights; - private $subtitle; - private $title; + public $subtitle; + public $title; private $published; private $updated; private $entries; @@ -184,6 +188,10 @@ class Atom10Feed extends XMLStringer $this->renderAuthors(); + if ($this->selfLink) { + $this->addLink($this->selfLink, array('rel' => 'self', + 'type' => $this->selfLinkType)); + } $this->renderLinks(); } @@ -253,6 +261,12 @@ class Atom10Feed extends XMLStringer $this->id = $id; } + function setSelfLink($url, $type='application/atom+xml') + { + $this->selfLink = $url; + $this->selfLinkType = $type; + } + function setTitle($title) { $this->title = $title; diff --git a/lib/atomgroupnoticefeed.php b/lib/atomgroupnoticefeed.php index 52ee4c7d6e..08c1c707c5 100644 --- a/lib/atomgroupnoticefeed.php +++ b/lib/atomgroupnoticefeed.php @@ -49,14 +49,42 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed /** * Constructor * - * @param Group $group the group for the feed (optional) + * @param Group $group the group for the feed * @param boolean $indent flag to turn indenting on or off * * @return void */ - function __construct($group = null, $indent = true) { + function __construct($group, $indent = true) { parent::__construct($indent); $this->group = $group; + + $title = sprintf(_("%s timeline"), $group->nickname); + $this->setTitle($title); + + $sitename = common_config('site', 'name'); + $subtitle = sprintf( + _('Updates from %1$s on %2$s!'), + $group->nickname, + $sitename + ); + $this->setSubtitle($subtitle); + + $avatar = $group->homepage_logo; + $logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE); + $this->setLogo($logo); + + $this->setUpdated('now'); + + $self = common_local_url('ApiTimelineGroup', + array('id' => $group->id, + 'format' => 'atom')); + $this->setId($self); + $this->setSelfLink($self); + + $this->addAuthorRaw($group->asAtomAuthor()); + $this->setActivitySubject($group->asActivitySubject()); + + $this->addLink($group->homeUrl()); } function getGroup() diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index 2ad8de4550..55cebef6df 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -49,19 +49,56 @@ class AtomUserNoticeFeed extends AtomNoticeFeed /** * Constructor * - * @param User $user the user for the feed (optional) + * @param User $user the user for the feed * @param boolean $indent flag to turn indenting on or off * * @return void */ - function __construct($user = null, $indent = true) { + function __construct($user, $indent = true) { parent::__construct($indent); $this->user = $user; if (!empty($user)) { $profile = $user->getProfile(); $this->addAuthor($profile->nickname, $user->uri); } + + $title = sprintf(_("%s timeline"), $user->nickname); + $this->setTitle($title); + + $sitename = common_config('site', 'name'); + $subtitle = sprintf( + _('Updates from %1$s on %2$s!'), + $user->nickname, $sitename + ); + $this->setSubtitle($subtitle); + + $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + $logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE); + $this->setLogo($logo); + + $this->setUpdated('now'); + + $this->addLink( + common_local_url( + 'showstream', + array('nickname' => $user->nickname) + ) + ); + + $self = common_local_url('ApiTimelineUser', + array('id' => $user->id, + 'format' => 'atom')); + $this->setId($self); + $this->setSelfLink($self); + + $this->addLink( + common_local_url('sup', null, null, $user->id), + array( + 'rel' => 'http://api.friendfeed.com/2008/03#sup', + 'type' => 'application/json' + ) + ); } function getUser() diff --git a/plugins/OStatus/lib/ostatusqueuehandler.php b/plugins/OStatus/lib/ostatusqueuehandler.php index 6ca31c485c..d1e58f1d68 100644 --- a/plugins/OStatus/lib/ostatusqueuehandler.php +++ b/plugins/OStatus/lib/ostatusqueuehandler.php @@ -164,46 +164,21 @@ class OStatusQueueHandler extends QueueHandler */ function userFeedForNotice() { - // @fixme this feels VERY hacky... - // should probably be a cleaner way to do it + $atom = new AtomUserNoticeFeed($this->user); + $atom->addEntryFromNotice($this->notice); + $feed = $atom->getString(); - ob_start(); - $api = new ApiTimelineUserAction(); - $api->prepare(array('id' => $this->notice->profile_id, - 'format' => 'atom', - 'max_id' => $this->notice->id, - 'since_id' => $this->notice->id - 1)); - $api->showTimeline(); - $feed = ob_get_clean(); - - // ...and override the content-type back to something normal... eww! - // hope there's no other headers that got set while we weren't looking. - header('Content-Type: text/html; charset=utf-8'); - - common_log(LOG_DEBUG, $feed); return $feed; } function groupFeedForNotice($group_id) { - // @fixme this feels VERY hacky... - // should probably be a cleaner way to do it + $group = User_group::staticGet('id', $group_id); - ob_start(); - $api = new ApiTimelineGroupAction(); - $args = array('id' => $group_id, - 'format' => 'atom', - 'max_id' => $this->notice->id, - 'since_id' => $this->notice->id - 1); - $api->prepare($args); - $api->handle($args); - $feed = ob_get_clean(); - - // ...and override the content-type back to something normal... eww! - // hope there's no other headers that got set while we weren't looking. - header('Content-Type: text/html; charset=utf-8'); + $atom = new AtomGroupNoticeFeed($group); + $atom->addEntryFromNotice($this->notice); + $feed = $atom->getString(); - common_log(LOG_DEBUG, $feed); return $feed; } From 8436306d2872db2d1a50fdaef3cc1f2c8fb0d114 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 3 Mar 2010 16:38:51 -0800 Subject: [PATCH 06/30] Fix notice warning in RSS friends timeline --- actions/allrss.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/allrss.php b/actions/allrss.php index 28b1be27d8..01e737ad7b 100644 --- a/actions/allrss.php +++ b/actions/allrss.php @@ -83,6 +83,7 @@ class AllrssAction extends Rss10Action function getNotices($limit=0) { $cur = common_current_user(); + $user = $this->user; if (!empty($cur) && $cur->id == $user->id) { $notice = $this->user->noticeInbox(0, $limit); @@ -90,7 +91,6 @@ class AllrssAction extends Rss10Action $notice = $this->user->noticesWithFriends(0, $limit); } - $user = $this->user; $notice = $user->noticesWithFriends(0, $limit); $notices = array(); From 61de37ec7bfb620288d3bc3b1fcdfb66725f0f99 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 16:47:27 -0800 Subject: [PATCH 07/30] Move snapshot configuration to its own admin panel Turn on with: $config['admin']['panels'][] = 'snapshot'; --- actions/siteadminpanel.php | 56 +------- actions/snapshotadminpanel.php | 251 +++++++++++++++++++++++++++++++++ lib/adminpanelaction.php | 5 + lib/router.php | 1 + 4 files changed, 263 insertions(+), 50 deletions(-) create mode 100644 actions/snapshotadminpanel.php diff --git a/actions/siteadminpanel.php b/actions/siteadminpanel.php index 4b29819b71..cb3c2e8fde 100644 --- a/actions/siteadminpanel.php +++ b/actions/siteadminpanel.php @@ -66,7 +66,7 @@ class SiteadminpanelAction extends AdminPanelAction function getInstructions() { - return _('Basic settings for this StatusNet site.'); + return _('Basic settings for this StatusNet site'); } /** @@ -90,10 +90,11 @@ class SiteadminpanelAction extends AdminPanelAction function saveSettings() { - static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl', - 'email', 'timezone', 'language', - 'site', 'textlimit', 'dupelimit'), - 'snapshot' => array('run', 'reporturl', 'frequency')); + static $settings = array( + 'site' => array('name', 'broughtby', 'broughtbyurl', + 'email', 'timezone', 'language', + 'site', 'textlimit', 'dupelimit'), + ); $values = array(); @@ -158,25 +159,6 @@ class SiteadminpanelAction extends AdminPanelAction $this->clientError(sprintf(_('Unknown language "%s".'), $values['site']['language'])); } - // Validate report URL - - if (!is_null($values['snapshot']['reporturl']) && - !Validate::uri($values['snapshot']['reporturl'], array('allowed_schemes' => array('http', 'https')))) { - $this->clientError(_("Invalid snapshot report URL.")); - } - - // Validate snapshot run value - - if (!in_array($values['snapshot']['run'], array('web', 'cron', 'never'))) { - $this->clientError(_("Invalid snapshot run value.")); - } - - // Validate snapshot run value - - if (!Validate::number($values['snapshot']['frequency'])) { - $this->clientError(_("Snapshot frequency must be a number.")); - } - // Validate text limit if (!Validate::number($values['site']['textlimit'], array('min' => 140))) { @@ -285,32 +267,6 @@ class SiteAdminPanelForm extends AdminForm $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); - $this->out->elementStart('fieldset', array('id' => 'settings_admin_snapshots')); - $this->out->element('legend', null, _('Snapshots')); - $this->out->elementStart('ul', 'form_data'); - $this->li(); - $snapshot = array('web' => _('Randomly during Web hit'), - 'cron' => _('In a scheduled job'), - 'never' => _('Never')); - $this->out->dropdown('run', _('Data snapshots'), - $snapshot, _('When to send statistical data to status.net servers'), - false, $this->value('run', 'snapshot')); - $this->unli(); - - $this->li(); - $this->input('frequency', _('Frequency'), - _('Snapshots will be sent once every N web hits'), - 'snapshot'); - $this->unli(); - - $this->li(); - $this->input('reporturl', _('Report URL'), - _('Snapshots will be sent to this URL'), - 'snapshot'); - $this->unli(); - $this->out->elementEnd('ul'); - $this->out->elementEnd('fieldset'); - $this->out->elementStart('fieldset', array('id' => 'settings_admin_limits')); $this->out->element('legend', null, _('Limits')); $this->out->elementStart('ul', 'form_data'); diff --git a/actions/snapshotadminpanel.php b/actions/snapshotadminpanel.php new file mode 100644 index 0000000000..a0c2315bc1 --- /dev/null +++ b/actions/snapshotadminpanel.php @@ -0,0 +1,251 @@ +. + * + * @category Settings + * @package StatusNet + * @author Zach Copley + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Manage snapshots + * + * @category Admin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class SnapshotadminpanelAction extends AdminPanelAction +{ + /** + * Returns the page title + * + * @return string page title + */ + + function title() + { + return _('Snapshots'); + } + + /** + * Instructions for using this form. + * + * @return string instructions + */ + + function getInstructions() + { + return _('Manage snapshot configuration'); + } + + /** + * Show the snapshots admin panel form + * + * @return void + */ + + function showForm() + { + $form = new SnapshotAdminPanelForm($this); + $form->show(); + return; + } + + /** + * Save settings from the form + * + * @return void + */ + + function saveSettings() + { + static $settings = array( + 'snapshot' => array('run', 'reporturl', 'frequency') + ); + + $values = array(); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] = $this->trimmed($setting); + } + } + + // This throws an exception on validation errors + + $this->validate($values); + + // assert(all values are valid); + + $config = new Config(); + + $config->query('BEGIN'); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + $config->query('COMMIT'); + + return; + } + + function validate(&$values) + { + // Validate snapshot run value + + if (!in_array($values['snapshot']['run'], array('web', 'cron', 'never'))) { + $this->clientError(_("Invalid snapshot run value.")); + } + + // Validate snapshot frequency value + + if (!Validate::number($values['snapshot']['frequency'])) { + $this->clientError(_("Snapshot frequency must be a number.")); + } + + // Validate report URL + + if (!is_null($values['snapshot']['reporturl']) + && !Validate::uri( + $values['snapshot']['reporturl'], + array('allowed_schemes' => array('http', 'https') + ) + )) { + $this->clientError(_("Invalid snapshot report URL.")); + } + } +} + +class SnapshotAdminPanelForm extends AdminForm +{ + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'form_snapshot_admin_panel'; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_settings'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('snapshotadminpanel'); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_admin_snapshots') + ); + $this->out->element('legend', null, _('Snapshots')); + $this->out->elementStart('ul', 'form_data'); + $this->li(); + $snapshot = array( + 'web' => _('Randomly during Web hit'), + 'cron' => _('In a scheduled job'), + 'never' => _('Never') + ); + $this->out->dropdown( + 'run', + _('Data snapshots'), + $snapshot, + _('When to send statistical data to status.net servers'), + false, + $this->value('run', 'snapshot') + ); + $this->unli(); + + $this->li(); + $this->input( + 'frequency', + _('Frequency'), + _('Snapshots will be sent once every N web hits'), + 'snapshot' + ); + $this->unli(); + + $this->li(); + $this->input( + 'reporturl', + _('Report URL'), + _('Snapshots will be sent to this URL'), + 'snapshot' + ); + $this->unli(); + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit( + 'submit', + _('Save'), + 'submit', + null, + _('Save snapshot settings') + ); + } +} diff --git a/lib/adminpanelaction.php b/lib/adminpanelaction.php index eb622871e7..d1aab3dfcb 100644 --- a/lib/adminpanelaction.php +++ b/lib/adminpanelaction.php @@ -381,6 +381,11 @@ class AdminPanelNav extends Widget _('Edit site notice'), $action_name == 'sitenoticeadminpanel', 'nav_sitenotice_admin_panel'); } + if (AdminPanelAction::canAdmin('snapshot')) { + $this->out->menuItem(common_local_url('snapshotadminpanel'), _('Snapshots'), + _('Snapshots configuration'), $action_name == 'snapshotadminpanel', 'nav_snapshot_admin_panel'); + } + Event::handle('EndAdminPanelNav', array($this)); } $this->action->elementEnd('ul'); diff --git a/lib/router.php b/lib/router.php index 15f88c959d..706120e0bf 100644 --- a/lib/router.php +++ b/lib/router.php @@ -651,6 +651,7 @@ class Router $m->connect('admin/paths', array('action' => 'pathsadminpanel')); $m->connect('admin/sessions', array('action' => 'sessionsadminpanel')); $m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel')); + $m->connect('admin/snapshot', array('action' => 'snapshotadminpanel')); $m->connect('getfile/:filename', array('action' => 'getfile'), From a26d23b39515e42a2f5437203d90d583d9a1be89 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 19:51:41 -0500 Subject: [PATCH 08/30] Changed clipboard icon to magic wand for user role button --- theme/base/images/icons/README | 2 +- theme/base/images/icons/icons-01.gif | Bin 3788 -> 3792 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/base/images/icons/README b/theme/base/images/icons/README index 0451fda494..2e17826029 100644 --- a/theme/base/images/icons/README +++ b/theme/base/images/icons/README @@ -25,7 +25,6 @@ White reject with green background White play with green background White pause with green background - White clipboard with green background */ @@ -46,6 +45,7 @@ White pin with green background White underscore with green background White C with green background + White magic wand with green background */ Created by various authors diff --git a/theme/base/images/icons/icons-01.gif b/theme/base/images/icons/icons-01.gif index deba4970ded5878546d57a08bd48bfd4c926b290..210c44511d9ca31b2b359df4b8b8a60ca9f71100 100644 GIT binary patch delta 86 zcmV-c0IC1X9nc*NM@dFFIbj+Am9kr>I3Uu2WIm5&`&fob`YmKP8JJ356SKL7v# delta 82 zcmV-Y0ImPf9n2jJM@dFFIbj+Am45{OgO{n4^oW@<$(5U_nMTQ(APJgi*^ZD{asdGVJC^kxga7~l From 1761b185bfc275157906c086b20fb469edc37987 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 19:53:09 -0500 Subject: [PATCH 09/30] Removed clipboard icon from core --- .../base/images/icons/twotone/green/clipboard.gif | Bin 80 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 theme/base/images/icons/twotone/green/clipboard.gif diff --git a/theme/base/images/icons/twotone/green/clipboard.gif b/theme/base/images/icons/twotone/green/clipboard.gif deleted file mode 100644 index 9317bdcd083856423ed6cc5b1c3f377f12ff14f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80 zcmZ?wbhEHb6krfwn8?KN|NsB^DFQ%}fq_BsCkrD30~3P|kPVa-0J0TB`erVB%P+`a gc){}R;x2QZs@NHpDL?1V&f26IdDKXlo0Y*D0L~K_-T(jq From 6a5a629afac881fdc8369dfef2924f7f62949fab Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 20:08:55 -0500 Subject: [PATCH 10/30] Updated label and note text for user and group remote subscribe forms --- plugins/OStatus/actions/ostatusgroup.php | 4 ++-- plugins/OStatus/actions/ostatussub.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/OStatus/actions/ostatusgroup.php b/plugins/OStatus/actions/ostatusgroup.php index 4fcd0eb39a..f325ba0532 100644 --- a/plugins/OStatus/actions/ostatusgroup.php +++ b/plugins/OStatus/actions/ostatusgroup.php @@ -72,9 +72,9 @@ class OStatusGroupAction extends OStatusSubAction $this->elementStart('ul', 'form_data'); $this->elementStart('li'); $this->input('profile', - _m('Group profile URL'), + _m('Join group'), $this->profile_uri, - _m('Enter the profile URL of a group on another StatusNet site')); + _m("OStatus group's address, like http://example.net/group/nickname")); $this->elementEnd('li'); $this->elementEnd('ul'); diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 542f7e20ca..7ca8a7869a 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -62,9 +62,9 @@ class OStatusSubAction extends Action $this->elementStart('ul', 'form_data'); $this->elementStart('li'); $this->input('profile', - _m('Address or profile URL'), + _m('Subscribe to'), $this->profile_uri, - _m('Enter the profile URL of a PubSubHubbub-enabled feed')); + _m("OStatus user's address, like nickname@example.com or http://example.net/user/nickname")); $this->elementEnd('li'); $this->elementEnd('ul'); From a4d9171306a06983094fdc90dbf040335c4f803f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 3 Mar 2010 18:23:28 -0800 Subject: [PATCH 11/30] Fix up catching of webfinger setup fails --- plugins/OStatus/actions/ostatussub.php | 3 +-- plugins/OStatus/classes/Ostatus_profile.php | 13 ++++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index 7ca8a7869a..e8a2c78ae0 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -260,7 +260,7 @@ class OStatusSubAction extends Action $this->error = _m('Could not find a feed linked from this URL.'); } catch (FeedSubUnrecognizedTypeException $e) { $this->error = _m('Not a recognized feed type.'); - } catch (FeedSubException $e) { + } catch (Exception $e) { // Any new ones we forgot about $this->error = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); } @@ -315,7 +315,6 @@ class OStatusSubAction extends Action if ($this->pullRemoteProfile()) { $this->validateRemoteProfile(); } - return true; } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 7ab031aa59..b3b4336b52 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1267,6 +1267,11 @@ class Ostatus_profile extends Memcached_DataObject } } + /** + * @param string $addr webfinger address + * @return Ostatus_profile + * @throws Exception on error conditions + */ public static function ensureWebfinger($addr) { // First, try the cache @@ -1275,7 +1280,8 @@ class Ostatus_profile extends Memcached_DataObject if ($uri !== false) { if (is_null($uri)) { - return null; + // Negative cache entry + throw new Exception('Not a valid webfinger address.'); } $oprofile = Ostatus_profile::staticGet('uri', $uri); if (!empty($oprofile)) { @@ -1299,8 +1305,9 @@ class Ostatus_profile extends Memcached_DataObject try { $result = $disco->lookup($addr); } catch (Exception $e) { + // Save negative cache entry so we don't waste time looking it up again. self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null); - return null; + throw new Exception('Not a valid webfinger address.'); } foreach ($result->links as $link) { @@ -1410,7 +1417,7 @@ class Ostatus_profile extends Memcached_DataObject return $oprofile; } - return null; + throw new Exception("Couldn't find a valid profile for '$addr'"); } function saveHTMLFile($title, $rendered) From 14065ca350cae576461f1a2db33694e38cebf751 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 3 Mar 2010 18:28:39 -0800 Subject: [PATCH 12/30] OStatus: code cleanup on webfinger fallback path --- plugins/OStatus/classes/Ostatus_profile.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index b3b4336b52..fcca1a2521 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1306,20 +1306,23 @@ class Ostatus_profile extends Memcached_DataObject $result = $disco->lookup($addr); } catch (Exception $e) { // Save negative cache entry so we don't waste time looking it up again. + // @fixme distinguish temporary failures? self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null); throw new Exception('Not a valid webfinger address.'); } + $hints = array('webfinger' => $addr); + foreach ($result->links as $link) { switch ($link['rel']) { case Discovery::PROFILEPAGE: - $profileUrl = $link['href']; + $hints['profileurl'] = $profileUrl = $link['href']; break; case Salmon::NS_REPLIES: - $salmonEndpoint = $link['href']; + $hints['salmon'] = $salmonEndpoint = $link['href']; break; case Discovery::UPDATESFROM: - $feedUrl = $link['href']; + $hints['feedurl'] = $feedUrl = $link['href']; break; case Discovery::HCARD: $hcardUrl = $link['href']; @@ -1330,11 +1333,6 @@ class Ostatus_profile extends Memcached_DataObject } } - $hints = array('webfinger' => $addr, - 'profileurl' => $profileUrl, - 'feedurl' => $feedUrl, - 'salmon' => $salmonEndpoint); - if (isset($hcardUrl)) { $hcardHints = self::slurpHcard($hcardUrl); // Note: Webfinger > hcard From 24835c1164251e48037f6ddee14e4b696fe57320 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 3 Mar 2010 18:31:35 -0800 Subject: [PATCH 13/30] OStatus: catchable exception instead of fatal when parsing valid XML that isn't a valid XRD doc --- plugins/OStatus/lib/xrd.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/OStatus/lib/xrd.php b/plugins/OStatus/lib/xrd.php index f00e1f8096..aa13ef0242 100644 --- a/plugins/OStatus/lib/xrd.php +++ b/plugins/OStatus/lib/xrd.php @@ -57,6 +57,9 @@ class XRD throw new Exception("Invalid XML"); } $xrd_element = $dom->getElementsByTagName('XRD')->item(0); + if (!$xrd_element) { + throw new Exception("Invalid XML, missing XRD root"); + } // Check for host-meta host $host = $xrd_element->getElementsByTagName('Host')->item(0); From de687d00c0ebe8bf5d185b7037df7f1edfd368a3 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 22:56:50 -0500 Subject: [PATCH 14/30] Updated OStatus subscription error messages to be more user friendly. Hopefully. --- plugins/OStatus/actions/ostatussub.php | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index e8a2c78ae0..bee48a8aed 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -64,7 +64,7 @@ class OStatusSubAction extends Action $this->input('profile', _m('Subscribe to'), $this->profile_uri, - _m("OStatus user's address, like nickname@example.com or http://example.net/user/nickname")); + _m("OStatus user's address, like nickname@example.com or http://example.net/nickname")); $this->elementEnd('li'); $this->elementEnd('ul'); @@ -244,25 +244,33 @@ class OStatusSubAction extends Action } else if (Validate::uri($this->profile_uri)) { $this->oprofile = Ostatus_profile::ensureProfile($this->profile_uri); } else { - $this->error = _m("Invalid address format."); + $this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname"); + common_debug('Invalid address format.', __FILE__); return false; } return true; } catch (FeedSubBadURLException $e) { - $this->error = _m('Invalid URL or could not reach server.'); + $this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname"); + common_debug('Invalid URL or could not reach server.', __FILE__); } catch (FeedSubBadResponseException $e) { - $this->error = _m('Cannot read feed; server returned error.'); + $this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later."); + common_debug('Cannot read feed; server returned error.', __FILE__); } catch (FeedSubEmptyException $e) { - $this->error = _m('Cannot read feed; server returned an empty page.'); + $this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later."); + common_debug('Cannot read feed; server returned an empty page.', __FILE__); } catch (FeedSubBadHTMLException $e) { - $this->error = _m('Bad HTML, could not find feed link.'); + $this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later."); + common_debug('Bad HTML, could not find feed link.', __FILE__); } catch (FeedSubNoFeedException $e) { - $this->error = _m('Could not find a feed linked from this URL.'); + $this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later."); + common_debug('Could not find a feed linked from this URL.', __FILE__); } catch (FeedSubUnrecognizedTypeException $e) { - $this->error = _m('Not a recognized feed type.'); + $this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later."); + common_debug('Not a recognized feed type.', __FILE__); } catch (Exception $e) { // Any new ones we forgot about - $this->error = sprintf(_m('Bad feed URL: %s %s'), get_class($e), $e->getMessage()); + $this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname"); + common_debug(sprintf('Bad feed URL: %s %s', get_class($e), $e->getMessage()), __FILE__); } return false; From 1c8399fde123fa2bc7b4ebf21fb323d215a9e7b4 Mon Sep 17 00:00:00 2001 From: James Walker Date: Wed, 3 Mar 2010 23:20:04 -0500 Subject: [PATCH 15/30] refactor xrd to allow for ownerxrd - xrd document for the site owner. introduced $config['webfinger']['owner'] for a custom xrd subject --- plugins/OStatus/OStatusPlugin.php | 4 +- plugins/OStatus/actions/ownerxrd.php | 56 +++++++++++++++++++ plugins/OStatus/actions/userxrd.php | 48 ++++++++++++++++ .../{actions/xrd.php => lib/xrdaction.php} | 32 ++++------- 4 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 plugins/OStatus/actions/ownerxrd.php create mode 100644 plugins/OStatus/actions/userxrd.php rename plugins/OStatus/{actions/xrd.php => lib/xrdaction.php} (86%) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index cc7e759764..8baa857d8c 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -44,7 +44,9 @@ class OStatusPlugin extends Plugin $m->connect('.well-known/host-meta', array('action' => 'hostmeta')); $m->connect('main/xrd', - array('action' => 'xrd')); + array('action' => 'userxrd')); + $m->connect('main/ownerxrd', + array('action' => 'ownerxrd')); $m->connect('main/ostatus', array('action' => 'ostatusinit')); $m->connect('main/ostatus?nickname=:nickname', diff --git a/plugins/OStatus/actions/ownerxrd.php b/plugins/OStatus/actions/ownerxrd.php new file mode 100644 index 0000000000..9c141d8c79 --- /dev/null +++ b/plugins/OStatus/actions/ownerxrd.php @@ -0,0 +1,56 @@ +. + */ + +/** + * @package OStatusPlugin + * @maintainer James Walker + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } + +class OwnerxrdAction extends XrdAction +{ + + public $uri; + + function prepare($args) + { + $this->user = User::siteOwner(); + + if (!$this->user) { + $this->clientError(_('No such user.'), 404); + return false; + } + + $nick = common_canonical_nickname($this->user->nickname); + $acct = 'acct:' . $nick . '@' . common_config('site', 'server'); + + $this->xrd = new XRD(); + + // Check to see if a $config['webfinger']['owner'] has been set + if ($owner = common_config('webfinger', 'owner')) { + $this->xrd->subject = Discovery::normalize($owner); + $this->xrd->alias[] = $acct; + } else { + $this->xrd->subject = $acct; + } + + return true; + } +} diff --git a/plugins/OStatus/actions/userxrd.php b/plugins/OStatus/actions/userxrd.php new file mode 100644 index 0000000000..414de9364b --- /dev/null +++ b/plugins/OStatus/actions/userxrd.php @@ -0,0 +1,48 @@ +. + */ + +/** + * @package OStatusPlugin + * @maintainer James Walker + */ + +if (!defined('STATUSNET')) { exit(1); } + +class UserxrdAction extends XrdAction +{ + + function prepare($args) + { + parent::prepare($args); + + $this->uri = $this->trimmed('uri'); + $acct = Discovery::normalize($this->uri); + + list($nick, $domain) = explode('@', substr(urldecode($acct), 5)); + $nick = common_canonical_nickname($nick); + + $this->user = User::staticGet('nickname', $nick); + if (!$this->user) { + $this->clientError(_('No such user.'), 404); + return false; + } + + return true; + } +} diff --git a/plugins/OStatus/actions/xrd.php b/plugins/OStatus/lib/xrdaction.php similarity index 86% rename from plugins/OStatus/actions/xrd.php rename to plugins/OStatus/lib/xrdaction.php index f574b60ee1..6881292add 100644 --- a/plugins/OStatus/actions/xrd.php +++ b/plugins/OStatus/lib/xrdaction.php @@ -28,32 +28,24 @@ class XrdAction extends Action { public $uri; + + public $user; - function prepare($args) - { - parent::prepare($args); - - $this->uri = $this->trimmed('uri'); - - return true; - } - + public $xrd; + function handle() { - $acct = Discovery::normalize($this->uri); + $nick = $this->user->nickname; - $xrd = new XRD(); - - list($nick, $domain) = explode('@', substr(urldecode($acct), 5)); - $nick = common_canonical_nickname($nick); - - $this->user = User::staticGet('nickname', $nick); - if (!$this->user) { - $this->clientError(_('No such user.'), 404); - return false; + if (empty($this->xrd)) { + $xrd = new XRD(); + } else { + $xrd = $this->xrd; } - $xrd->subject = $this->uri; + if (empty($xrd->subject)) { + $xrd->subject = Discovery::normalize($this->uri); + } $xrd->alias[] = common_profile_url($nick); $xrd->links[] = array('rel' => Discovery::PROFILEPAGE, 'type' => 'text/html', From 38503096d905fbb4db8552eeb59afc12d4b5e903 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 23:34:48 -0500 Subject: [PATCH 16/30] Puts All groups and Remote sub button in the mini list on the same line --- plugins/OStatus/theme/base/css/ostatus.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/theme/base/css/ostatus.css b/plugins/OStatus/theme/base/css/ostatus.css index ac668623d8..f7d9853cf7 100644 --- a/plugins/OStatus/theme/base/css/ostatus.css +++ b/plugins/OStatus/theme/base/css/ostatus.css @@ -52,7 +52,8 @@ margin-bottom:0; width:405px; } -.aside #entity_subscriptions .more { +.aside #entity_subscriptions .more, +.aside #entity_groups .more { float:left; } From b97ac60209fdec3f2d521f7c9d54acca6d00d274 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 3 Mar 2010 23:47:27 -0500 Subject: [PATCH 17/30] Changed text for authorizing/confirming remote profile --- plugins/OStatus/actions/ostatussub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php index bee48a8aed..65dee2392f 100644 --- a/plugins/OStatus/actions/ostatussub.php +++ b/plugins/OStatus/actions/ostatussub.php @@ -398,7 +398,7 @@ class OStatusSubAction extends Action function title() { // TRANS: Page title for OStatus remote subscription form - return _m('Authorize subscription'); + return _m('Confirm'); } /** From f210cadfecc4f87e1fb8e35cd784a7010c443c31 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 17:35:18 -0800 Subject: [PATCH 18/30] Revert "Revert "Show and no activity actors for user feed"" This reverts commit e2578cfad68c45ca177c51997c4cc7c0abafbd9a. --- classes/Notice.php | 8 +++++--- lib/atomnoticefeed.php | 16 +++++++++++++--- lib/atomusernoticefeed.php | 11 +++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 97cb3b8fbe..4c7e6ab4b7 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1106,7 +1106,7 @@ class Notice extends Memcached_DataObject return $groups; } - function asAtomEntry($namespace=false, $source=false) + function asAtomEntry($namespace=false, $source=false, $author=true) { $profile = $this->getProfile(); @@ -1151,8 +1151,10 @@ class Notice extends Memcached_DataObject $xs->element('title', null, $this->content); - $xs->raw($profile->asAtomAuthor()); - $xs->raw($profile->asActivityActor()); + if ($author) { + $xs->raw($profile->asAtomAuthor()); + $xs->raw($profile->asActivityActor()); + } $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index 3c3556cb95..e4df731fe0 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -107,9 +107,19 @@ class AtomNoticeFeed extends Atom10Feed */ function addEntryFromNotice($notice) { - $this->addEntryRaw($notice->asAtomEntry()); + $source = $this->showSource(); + $author = $this->showAuthor(); + + $this->addEntryRaw($notice->asAtomEntry(false, $source, $author)); } + function showSource() + { + return true; + } + + function showAuthor() + { + return true; + } } - - diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php index 55cebef6df..428cc2de2f 100644 --- a/lib/atomusernoticefeed.php +++ b/lib/atomusernoticefeed.php @@ -61,6 +61,7 @@ class AtomUserNoticeFeed extends AtomNoticeFeed if (!empty($user)) { $profile = $user->getProfile(); $this->addAuthor($profile->nickname, $user->uri); + $this->setActivitySubject($profile->asActivityNoun('subject')); } $title = sprintf(_("%s timeline"), $user->nickname); @@ -105,4 +106,14 @@ class AtomUserNoticeFeed extends AtomNoticeFeed { return $this->user; } + + function showSource() + { + return false; + } + + function showAuthor() + { + return false; + } } From 0e360ad23da4404c47bdb074a1afdb2eed873ecd Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 20:07:13 -0800 Subject: [PATCH 19/30] Test a small user feed to ensure we're taking the activity actor from the subject --- tests/UserFeedParseTest.php | 131 ++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/UserFeedParseTest.php diff --git a/tests/UserFeedParseTest.php b/tests/UserFeedParseTest.php new file mode 100644 index 0000000000..b3f9a64171 --- /dev/null +++ b/tests/UserFeedParseTest.php @@ -0,0 +1,131 @@ +assertFalse(empty($dom)); + + $entries = $dom->getElementsByTagName('entry'); + + $entry1 = $entries->item(0); + $this->assertFalse(empty($entry1)); + + $feedEl = $dom->getElementsByTagName('feed')->item(0); + $this->assertFalse(empty($feedEl)); + + // Test actor (from activity:subject) + + $act1 = new Activity($entry1, $feedEl); + $this->assertFalse(empty($act1)); + $this->assertFalse(empty($act1->actor)); + $this->assertEquals($act1->actor->type, ActivityObject::PERSON); + $this->assertEquals($act1->actor->title, 'Zach Copley'); + $this->assertEquals($act1->actor->id, 'http://localhost/statusnet/user/1'); + $this->assertEquals($act1->actor->link, 'http://localhost/statusnet/zach'); + + $avatars = $act1->actor->avatarLinks; + + $this->assertEquals( + $avatars[0]->url, + 'http://localhost/statusnet/theme/default/default-avatar-profile.png' + ); + + $this->assertEquals( + $avatars[1]->url, + 'http://localhost/statusnet/theme/default/default-avatar-stream.png' + ); + + $this->assertEquals( + $avatars[2]->url, + 'http://localhost/statusnet/theme/default/default-avatar-mini.png' + ); + + $this->assertEquals($act1->actor->displayName, 'Zach Copley'); + + $poco = $act1->actor->poco; + $this->assertEquals($poco->preferredUsername, 'zach'); + $this->assertEquals($poco->address->formatted, 'El Cerrito, CA'); + $this->assertEquals($poco->urls[0]->type, 'homepage'); + $this->assertEquals($poco->urls[0]->value, 'http://zach.copley.name'); + $this->assertEquals($poco->urls[0]->primary, 'true'); + $this->assertEquals($poco->note, 'Zach Hack Attack'); + + // test the post + + //var_export($act1); + $this->assertEquals($act1->object->type, 'http://activitystrea.ms/schema/1.0/note'); + $this->assertEquals($act1->object->title, 'And now for something completely insane...'); + + $this->assertEquals($act1->object->content, 'And now for something completely insane...'); + $this->assertEquals($act1->object->id, 'http://localhost/statusnet/notice/3'); + + } + +} + +$_testfeed1 = << + + http://localhost/statusnet/api/statuses/user_timeline/1.atom + zach timeline + Updates from zach on Zach Dev! + http://localhost/statusnet/theme/default/default-avatar-profile.png + 2010-03-04T01:41:14+00:00 + + zach + http://localhost/statusnet/user/1 + + + + + + + + + + http://activitystrea.ms/schema/1.0/person + http://localhost/statusnet/user/1 + Zach Copley + + + + + +zach +Zach Copley +Zach Hack Attack + + El Cerrito, CA + + + homepage + http://zach.copley.name + true + + + + + And now for something completely insane... + + http://localhost/statusnet/notice/3 + 2010-03-04T01:41:07+00:00 + 2010-03-04T01:41:07+00:00 + + And now for something completely insane... + + + +TESTFEED1; From 8ffb34a90c78502843aabaac71963d2f40c505d8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 20:55:53 -0800 Subject: [PATCH 20/30] Temp fix for problem getting actor from PuSH updates where actor is only specified in subject --- lib/activity.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/activity.php b/lib/activity.php index ce14fa2546..e1bce6f190 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -1060,6 +1060,18 @@ class Activity } $this->entry = $entry; + + // @fixme Don't send in a DOMDocument + if ($feed instanceof DOMDocument) { + common_log( + LOG_WARNING, + 'Activity::__construct() - ' + . 'DOMDocument passed in for feed by mistake. ' + . "Expecting a 'feed' DOMElement." + ); + $feed = $feed->getElementsByTagName('feed')->item(0); + } + $this->feed = $feed; $pubEl = $this->_child($entry, self::PUBLISHED, self::ATOM); From ce9d1618851156cc225a56980c4268a5fe102806 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 4 Mar 2010 00:29:13 -0500 Subject: [PATCH 21/30] Added the inverse icons for badge, sandbox, speech, admin --- theme/base/images/icons/README | 4 ++++ theme/base/images/icons/icons-01.gif | Bin 3792 -> 4095 bytes 2 files changed, 4 insertions(+) diff --git a/theme/base/images/icons/README b/theme/base/images/icons/README index 2e17826029..f701959ca0 100644 --- a/theme/base/images/icons/README +++ b/theme/base/images/icons/README @@ -46,6 +46,10 @@ White underscore with green background White C with green background White magic wand with green background + Green badge with white background + Green sandbox with white background + Green speech bubble broken with white background + Green person with tie with white background */ Created by various authors diff --git a/theme/base/images/icons/icons-01.gif b/theme/base/images/icons/icons-01.gif index 210c44511d9ca31b2b359df4b8b8a60ca9f71100..7c22356738044fb15b7643bcff012f74d216766b 100644 GIT binary patch delta 364 zcmV-y0h9jF9seH;M@dFFIbj+ApbF>yu?+qK6#xJKA^8LW3IP8AEC2ui02%SdS3PO}PXpy>knYbC8zqyeM zNSwwQl>QK$m8qP|*_#~coXq){xe1+GDVx@5kG$wfAhd~{+}WKCIGf=4oUd7)=6Rk` zG@j)7o$5KA-HDtQc%0U0moUhH#CeqTd7l}GkNWACfBZS0Klz{R>6gZtp8$HB_IaT7 zDW3x>LJ7*A%!K0RTG@2d+o} delta 59 zcmew_e?gYV-P6s&GEs_Q2Iq7CjXeLDMB=9iDE?$& Date: Thu, 4 Mar 2010 00:48:48 -0500 Subject: [PATCH 22/30] Updated styles for unsandbox, unsilence, revoke administrator and moderator icons --- theme/base/images/icons/icons-01.gif | Bin 4095 -> 4080 bytes theme/default/css/display.css | 16 ++++++++++++++-- theme/identica/css/display.css | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/theme/base/images/icons/icons-01.gif b/theme/base/images/icons/icons-01.gif index 7c22356738044fb15b7643bcff012f74d216766b..bf0f1230e5e16d75e630a487708d8a45ed4f6abf 100644 GIT binary patch delta 296 zcmV+@0oVTjAMhWr(hh$ad?$I7FbG07IGZX|n zQTbSt59pg27?i|$nZw!)!CVy+PQ&{SaPo!p5i&44>V%k>7CZu zoyhr{ei@uc*`Cm8moT`T@kyPQ`JCM8mp@6L`MIC>xt@MGobZ3ypE@|8Y=n;}$e#zw zo(hUb=h>iu^q}~umgHHX7J8uxbcRcH{t%p%shrE%n;hw!%=wtP37uLgo7QQMyy!_Fw27VE*_{nIo8bAJuUVevd7e=; zp5*zR>N%a=iJTUAoYrZVFvx(!d6e{dpBadc`stVaIiElIpX`6>m&Tc&0D7DDd7$+v zp93mF3Cf=1>7KMHp5Td|7J8u=sz7MSAZYkC3(}$e@S)FFLn2CziC3bw23sgaq#0VIMtY5{jGQ znVtOTodcqjREjSWw@IH-3ZWG$rTbZ(Tw0f4TBXsMoa>3DWeTOtS)5x+rb^1C@7bhd JIv@c706W8cnn?fv diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 8ca267c338..be341813a5 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -358,15 +358,27 @@ background-position: 5px -1445px; .entity_delete input.submit { background-position: 5px -1511px; } +.entity_sandbox .form_user_unsandbox input.submit { +background-position: 5px -2568px; +} +.entity_silence .form_user_unsilence input.submit { +background-position: 5px -2633px; +} .entity_role p { background-position: 5px -2436px; } -.entity_role_administrator input.submit { +.entity_role_administrator .form_user_grantrole input.submit { background-position: 5px -983px; } -.entity_role_moderator input.submit { +.entity_role_moderator .form_user_grantrole input.submit { background-position: 5px -1313px; } +.entity_role_administrator .form_user_revokerole input.submit { +background-position: 5px -2699px; +} +.entity_role_moderator .form_user_revokerole input.submit { +background-position: 5px -2501px; +} .form_reset_key input.submit { background-position: 5px -1973px; } diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index bc27cfb4d0..db85408ebd 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -358,15 +358,27 @@ background-position: 5px -1445px; .entity_delete input.submit { background-position: 5px -1511px; } +.entity_sandbox .form_user_unsandbox input.submit { +background-position: 5px -2568px; +} +.entity_silence .form_user_unsilence input.submit { +background-position: 5px -2633px; +} .entity_role p { background-position: 5px -2436px; } -.entity_role_administrator input.submit { +.entity_role_administrator .form_user_grantrole input.submit { background-position: 5px -983px; } -.entity_role_moderator input.submit { +.entity_role_moderator .form_user_grantrole input.submit { background-position: 5px -1313px; } +.entity_role_administrator .form_user_revokerole input.submit { +background-position: 5px -2699px; +} +.entity_role_moderator .form_user_revokerole input.submit { +background-position: 5px -2501px; +} .form_reset_key input.submit { background-position: 5px -1973px; } From 849f5783c445934da370769310b3b0382bc5d303 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 4 Mar 2010 01:30:15 -0500 Subject: [PATCH 23/30] update xrd -> userxrd --- plugins/OStatus/OStatusPlugin.php | 2 +- plugins/OStatus/actions/hostmeta.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 8baa857d8c..ad4f613891 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -113,7 +113,7 @@ class OStatusPlugin extends Plugin { if ($action instanceof ShowstreamAction) { $acct = 'acct:'. $action->profile->nickname .'@'. common_config('site', 'server'); - $url = common_local_url('xrd'); + $url = common_local_url('userxrd'); $url.= '?uri='. $acct; header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="application/xrd+xml"'); diff --git a/plugins/OStatus/actions/hostmeta.php b/plugins/OStatus/actions/hostmeta.php index 3d00b98ae0..6d35ada6c6 100644 --- a/plugins/OStatus/actions/hostmeta.php +++ b/plugins/OStatus/actions/hostmeta.php @@ -32,7 +32,7 @@ class HostMetaAction extends Action parent::handle(); $domain = common_config('site', 'server'); - $url = common_local_url('xrd'); + $url = common_local_url('userxrd'); $url.= '?uri={uri}'; $xrd = new XRD(); From ddc4a7d2ffde5a925c2cfe7b57e51cd0b2cf0153 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 4 Mar 2010 01:46:34 -0500 Subject: [PATCH 24/30] Catch a previously uncaught exception and add some additional debug logs for signature verification --- plugins/OStatus/lib/magicenvelope.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/lib/magicenvelope.php b/plugins/OStatus/lib/magicenvelope.php index 230d81ba1f..fb8c57c718 100644 --- a/plugins/OStatus/lib/magicenvelope.php +++ b/plugins/OStatus/lib/magicenvelope.php @@ -156,18 +156,32 @@ class MagicEnvelope public function verify($env) { if ($env['alg'] != 'RSA-SHA256') { + common_log(LOG_DEBUG, "Salmon error: bad algorithm"); return false; } if ($env['encoding'] != MagicEnvelope::ENCODING) { + common_log(LOG_DEBUG, "Salmon error: bad encoding"); return false; } $text = base64_decode($env['data']); $signer_uri = $this->getAuthor($text); - $verifier = Magicsig::fromString($this->getKeyPair($signer_uri)); + try { + $keypair = $this->getKeyPair($signer_uri); + } catch (Exception $e) { + common_log(LOG_DEBUG, "Salmon error: ".$e->getMessage()); + return false; + } + + $verifier = Magicsig::fromString($keypair); + if (!$verifier) { + common_log(LOG_DEBUG, "Salmon error: unable to parse keypair"); + return false; + } + return $verifier->verify($env['data'], $env['sig']); } From 37b106d49c7e6c563a1e7e4932ab5f458572964f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 22:22:57 -0800 Subject: [PATCH 25/30] Fix variable name in NoConfigException --- lib/statusnet.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/statusnet.php b/lib/statusnet.php index 7c4df84b4a..eba9ab9b8e 100644 --- a/lib/statusnet.php +++ b/lib/statusnet.php @@ -354,10 +354,10 @@ class StatusNet class NoConfigException extends Exception { - public $config_files; + public $configFiles; - function __construct($msg, $config_files) { + function __construct($msg, $configFiles) { parent::__construct($msg); - $this->config_files = $config_files; + $this->configFiles = $configFiles; } } From 44462ac617b315b206f757e3ee7932feabb3ca14 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 23:26:45 -0800 Subject: [PATCH 26/30] Create an initial user during install, and grant owner, moderator and administrator roles. --- install.php | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/install.php b/install.php index 435f6d63bf..6c0b8d8e6d 100644 --- a/install.php +++ b/install.php @@ -31,6 +31,7 @@ * @author Robin Millette * @author Sarven Capadisli * @author Tom Adams + * @author Zach Copley * @license GNU Affero General Public License http://www.gnu.org/licenses/ * @version 0.9.x * @link http://status.net @@ -490,15 +491,25 @@ function showForm()

Database name

  • - +

    Database username

  • - +

    Database password (optional)

  • +
  • + + +

    Nickname for the initial StatusNet user (administrator)

    +
  • +
  • + + +

    Password for the initial StatusNet user (administrator)

    +
  • @@ -521,6 +532,10 @@ function handlePost() $password = $_POST['password']; $sitename = $_POST['sitename']; $fancy = !empty($_POST['fancy']); + + $adminNick = $_POST['admin_nickname']; + $adminPass = $_POST['admin_password']; + $server = $_SERVER['HTTP_HOST']; $path = substr(dirname($_SERVER['PHP_SELF']), 1); @@ -552,6 +567,16 @@ STR; $fail = true; } + if (empty($adminNick)) { + updateStatus("No initial StatusNet user nickname specified.", true); + $fail = true; + } + + if (empty($adminPass)) { + updateStatus("No initial StatusNet user password specified.", true); + $fail = true; + } + if ($fail) { showForm(); return; @@ -574,13 +599,29 @@ STR; return; } + // Okay, cross fingers and try to register an initial user + if (registerInitialUser($adminNick, $adminPass)) { + updateStatus( + "An initial user with the administrator role has been created." + ); + } else { + updateStatus( + "Could not create initial StatusNet user (administrator).", + true + ); + showForm(); + return; + } + /* TODO https needs to be considered */ $link = "http://".$server.'/'.$path; updateStatus("StatusNet has been installed at $link"); - updateStatus("You can visit your new StatusNet site."); + updateStatus( + "You can visit your new StatusNet site (login as '$adminNick')." + ); } function Pgsql_Db_installer($host, $database, $username, $password) @@ -756,6 +797,33 @@ function runDbScript($filename, $conn, $type = 'mysqli') return true; } +function registerInitialUser($nickname, $password) +{ + define('STATUSNET', true); + define('LACONICA', true); // compatibility + + require_once INSTALLDIR . '/lib/common.php'; + + $user = User::register( + array('nickname' => $nickname, + 'password' => $password, + 'fullname' => $nickname + ) + ); + + if (empty($user)) { + return false; + } + + // give initial user carte blanche + + $user->grantRole('owner'); + $user->grantRole('moderator'); + $user->grantRole('administrator'); + + return true; +} + ?> xml version="1.0" encoding="UTF-8" "; ?> Date: Wed, 3 Mar 2010 23:59:10 -0800 Subject: [PATCH 27/30] Couple of tweaks to the HTML to try and make installer look bettter. This still needs some work. --- install.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/install.php b/install.php index 6c0b8d8e6d..41024c901f 100644 --- a/install.php +++ b/install.php @@ -833,10 +833,10 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" Install StatusNet - - - - + + + + @@ -852,8 +852,10 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    -

    Install StatusNet

    +
    +

    Install StatusNet

    +
    From 79b392a39e9a847c398b697cf8f982a6b220ed56 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 4 Mar 2010 01:16:25 -0800 Subject: [PATCH 28/30] Add generator tag into Atom feeds. --- lib/atom10feed.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/atom10feed.php b/lib/atom10feed.php index c1fdeaae93..2d342e7854 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -176,6 +176,14 @@ class Atom10Feed extends XMLStringer } $this->elementStart('feed', $commonAttrs); + $this->element( + 'generator', array( + 'url' => 'http://status.net', + 'version' => STATUSNET_VERSION + ), + 'StatusNet' + ); + $this->element('id', null, $this->id); $this->element('title', null, $this->title); $this->element('subtitle', null, $this->subtitle); From 14d7f4a598d0e24467fe3eafd9a02b0e651edad8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 4 Mar 2010 01:23:02 -0800 Subject: [PATCH 29/30] Removed unused stub class --- lib/atom10entry.php | 105 -------------------------------------------- 1 file changed, 105 deletions(-) delete mode 100644 lib/atom10entry.php diff --git a/lib/atom10entry.php b/lib/atom10entry.php deleted file mode 100644 index f8f16d5946..0000000000 --- a/lib/atom10entry.php +++ /dev/null @@ -1,105 +0,0 @@ -. - * - * @category Feed - * @package StatusNet - * @author Zach Copley - * @copyright 2010 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -class Atom10EntryException extends Exception -{ -} - -/** - * Class for manipulating an Atom entry in memory. Get the entry as an XML - * string with Atom10Entry::getString(). - * - * @category Feed - * @package StatusNet - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ -class Atom10Entry extends XMLStringer -{ - private $namespaces; - private $categories; - private $content; - private $contributors; - private $id; - private $links; - private $published; - private $rights; - private $source; - private $summary; - private $title; - - function __construct($indent = true) { - parent::__construct($indent); - $this->namespaces = array(); - } - - function addNamespace($namespace, $uri) - { - $ns = array($namespace => $uri); - $this->namespaces = array_merge($this->namespaces, $ns); - } - - function initEntry() - { - - } - - function endEntry() - { - - } - - /** - * Check that all required elements have been set, etc. - * Throws an Atom10EntryException if something's missing. - * - * @return void - */ - function validate() - { - - } - - function getString() - { - $this->validate(); - - $this->initEntry(); - $this->renderEntries(); - $this->endEntry(); - - return $this->xw->outputMemory(); - } - -} \ No newline at end of file From 9f861e9d895325adbb2dc7f1d540a442be2c1b2f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 06:39:46 -0800 Subject: [PATCH 30/30] Fix on sitenotice admin panel save --- actions/sitenoticeadminpanel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/sitenoticeadminpanel.php b/actions/sitenoticeadminpanel.php index 613a2e96be..3931aa9825 100644 --- a/actions/sitenoticeadminpanel.php +++ b/actions/sitenoticeadminpanel.php @@ -99,7 +99,7 @@ class SitenoticeadminpanelAction extends AdminPanelAction $result = Config::save('site', 'notice', $siteNotice); - if (!result) { + if (!$result) { $this->ServerError(_("Unable to save site notice.")); } }