From 0bb2f1470474f3818f6c3357581ea04efa23a15f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 15 Mar 2011 13:17:06 -0700 Subject: [PATCH] AJAX submit actions for tag subscribe/unsubscribe --- plugins/TagSub/TagSub.php | 31 +++++++ plugins/TagSub/TagSubPlugin.php | 34 ++++++- plugins/TagSub/tagsubaction.php | 149 ++++++++++++++++++++++++++++++ plugins/TagSub/tagsubform.php | 142 ++++++++++++++++++++++++++++ plugins/TagSub/tagunsubaction.php | 89 ++++++++++++++++++ plugins/TagSub/tagunsubform.php | 109 ++++++++++++++++++++++ 6 files changed, 550 insertions(+), 4 deletions(-) create mode 100644 plugins/TagSub/tagsubaction.php create mode 100644 plugins/TagSub/tagsubform.php create mode 100644 plugins/TagSub/tagunsubaction.php create mode 100644 plugins/TagSub/tagunsubform.php diff --git a/plugins/TagSub/TagSub.php b/plugins/TagSub/TagSub.php index fdae3e2db0..a734b4fc5f 100644 --- a/plugins/TagSub/TagSub.php +++ b/plugins/TagSub/TagSub.php @@ -106,4 +106,35 @@ class TagSub extends Managed_DataObject ); } + /** + * Start a tag subscription! + * + * @param profile $profile subscriber + * @param string $tag subscribee + * @return TagSub + */ + static function start(Profile $profile, $tag) + { + $ts = new TagSub(); + $ts->tag = $tag; + $ts->profile_id = $profile->id; + $ts->created = common_sql_now(); + $ts->insert(); + return $ts; + } + + /** + * End a tag subscription! + * + * @param profile $profile subscriber + * @param string $tag subscribee + */ + static function cancel(Profile $profile, $tag) + { + $ts = TagSub::pkeyGet(array('tag' => $tag, + 'profile_id' => $profile->id)); + if ($ts) { + $ts->delete(); + } + } } diff --git a/plugins/TagSub/TagSubPlugin.php b/plugins/TagSub/TagSubPlugin.php index b43fcf32ba..e51a7a8b39 100644 --- a/plugins/TagSub/TagSubPlugin.php +++ b/plugins/TagSub/TagSubPlugin.php @@ -73,13 +73,11 @@ class TagSubPlugin extends Plugin switch ($cls) { - case 'TagsubAction': - case 'TagunsubAction': - include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; - return false; case 'TagSub': include_once $dir.'/'.$cls.'.php'; return false; + case 'TagsubAction': + case 'TagunsubAction': case 'TagSubForm': case 'TagUnsubForm': include_once $dir.'/'.strtolower($cls).'.php'; @@ -153,4 +151,32 @@ class TagSubPlugin extends Plugin } return true; } + + /** + * + * @param TagAction $action + * @return boolean hook result + */ + function onStartTagShowContent(TagAction $action) + { + $user = common_current_user(); + if ($user) { + $tag = $action->trimmed('tag'); + $tagsub = TagSub::pkeyGet(array('tag' => $tag, + 'profile_id' => $user->id)); + if ($tagsub) { + $form = new TagUnsubForm($action, $tag); + } else { + $form = new TagSubForm($action, $tag); + } + $action->elementStart('div', 'entity_actions'); + $action->elementStart('ul'); + $action->elementStart('li', 'entity_subscribe'); + $form->show(); + $action->elementEnd('li'); + $action->elementEnd('ul'); + $action->elementEnd('div'); + } + return true; + } } diff --git a/plugins/TagSub/tagsubaction.php b/plugins/TagSub/tagsubaction.php new file mode 100644 index 0000000000..2e4e25d6e1 --- /dev/null +++ b/plugins/TagSub/tagsubaction.php @@ -0,0 +1,149 @@ +. + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Brion Vibber + * @author Evan Prodromou + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Tag subscription action + * + * Takes parameters: + * + * - token: session token to prevent CSRF attacks + * - ajax: boolean; whether to return Ajax or full-browser results + * + * Only works if the current user is logged in. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @author Brion Vibber + * @copyright 2008-2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ +class TagsubAction extends Action +{ + var $user; + var $tag; + + /** + * Check pre-requisites and instantiate attributes + * + * @param Array $args array of arguments (URL, GET, POST) + * + * @return boolean success flag + */ + function prepare($args) + { + parent::prepare($args); + if ($this->boolean('ajax')) { + StatusNet::setApi(true); + } + + // Only allow POST requests + + if ($_SERVER['REQUEST_METHOD'] != 'POST') { + // TRANS: Client error displayed trying to perform any request method other than POST. + // TRANS: Do not translate POST. + $this->clientError(_('This action only accepts POST requests.')); + return false; + } + + // CSRF protection + + $token = $this->trimmed('token'); + + if (!$token || $token != common_session_token()) { + // TRANS: Client error displayed when the session token is not okay. + $this->clientError(_('There was a problem with your session token.'. + ' Try again, please.')); + return false; + } + + // Only for logged-in users + + $this->user = common_current_user(); + + if (empty($this->user)) { + // TRANS: Client error displayed trying to subscribe when not logged in. + $this->clientError(_('Not logged in.')); + return false; + } + + // Profile to subscribe to + + $this->tag = $this->arg('tag'); + + if (empty($this->tag)) { + // TRANS: Client error displayed trying to subscribe to a non-existing profile. + $this->clientError(_('No such profile.')); + return false; + } + + return true; + } + + /** + * Handle request + * + * Does the subscription and returns results. + * + * @param Array $args unused. + * + * @return void + */ + function handle($args) + { + // Throws exception on error + + TagSub::start($this->user->getProfile(), + $this->tag); + + if ($this->boolean('ajax')) { + $this->startHTML('text/xml;charset=utf-8'); + $this->elementStart('head'); + // TRANS: Page title when tag subscription succeeded. + $this->element('title', null, _m('Subscribed')); + $this->elementEnd('head'); + $this->elementStart('body'); + $unsubscribe = new TagUnsubForm($this, $this->tag); + $unsubscribe->show(); + $this->elementEnd('body'); + $this->elementEnd('html'); + } else { + $url = common_local_url('tag', + array('tag' => $this->tag)); + common_redirect($url, 303); + } + } +} diff --git a/plugins/TagSub/tagsubform.php b/plugins/TagSub/tagsubform.php new file mode 100644 index 0000000000..108558be24 --- /dev/null +++ b/plugins/TagSub/tagsubform.php @@ -0,0 +1,142 @@ +. + * + * @category TagSubPlugin + * @package StatusNet + * @author Brion Vibber + * @author Evan Prodromou + * @author Sarven Capadisli + * @copyright 2009-2011 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); +} + +/** + * Form for subscribing to a user + * + * @category TagSubPlugin + * @package StatusNet + * @author Brion Vibber + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see UnsubscribeForm + */ + +class TagSubForm extends Form +{ + /** + * Name of tag to subscribe to + */ + + var $tag = ''; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param string $tag name of tag to subscribe to + */ + + function __construct($out=null, $tag=null) + { + parent::__construct($out); + + $this->tag = $tag; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'tag-subscribe-' . $this->tag; + } + + + /** + * class of the form + * + * @return string of the form class + */ + + function formClass() + { + // class to match existing styles... + return 'form_user_subscribe ajax'; + } + + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('tagsub', array('tag' => $this->tag)); + } + + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + $this->out->element('legend', null, _m('Subscribe to this tag')); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->hidden('subscribeto-' . $this->tag, + $this->tag, + 'subscribeto'); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Subscribe'), 'submit', null, _m('Subscribe to this tag')); + } +} diff --git a/plugins/TagSub/tagunsubaction.php b/plugins/TagSub/tagunsubaction.php new file mode 100644 index 0000000000..26fb9ffec8 --- /dev/null +++ b/plugins/TagSub/tagunsubaction.php @@ -0,0 +1,89 @@ +. + * + * PHP version 5 + * + * @category Action + * @package StatusNet + * @author Brion Vibber + * @author Evan Prodromou + * @copyright 2008-2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Tag unsubscription action + * + * Takes parameters: + * + * - token: session token to prevent CSRF attacks + * - ajax: boolean; whether to return Ajax or full-browser results + * + * Only works if the current user is logged in. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @author Brion Vibber + * @copyright 2008-2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ +class TagunsubAction extends TagsubAction +{ + /** + * Handle request + * + * Does the subscription and returns results. + * + * @param Array $args unused. + * + * @return void + */ + function handle($args) + { + // Throws exception on error + + TagSub::cancel($this->user->getProfile(), + $this->tag); + + if ($this->boolean('ajax')) { + $this->startHTML('text/xml;charset=utf-8'); + $this->elementStart('head'); + // TRANS: Page title when tag unsubscription succeeded. + $this->element('title', null, _m('Unsubscribed')); + $this->elementEnd('head'); + $this->elementStart('body'); + $subscribe = new TagSubForm($this, $this->tag); + $subscribe->show(); + $this->elementEnd('body'); + $this->elementEnd('html'); + } else { + $url = common_local_url('tag', + array('tag' => $this->tag)); + common_redirect($url, 303); + } + } +} diff --git a/plugins/TagSub/tagunsubform.php b/plugins/TagSub/tagunsubform.php new file mode 100644 index 0000000000..0b44648071 --- /dev/null +++ b/plugins/TagSub/tagunsubform.php @@ -0,0 +1,109 @@ +. + * + * @category TagSubPlugin + * @package StatusNet + * @author Brion Vibber + * @author Evan Prodromou + * @author Sarven Capadisli + * @copyright 2009-2011 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); +} + +/** + * Form for subscribing to a user + * + * @category TagSubPlugin + * @package StatusNet + * @author Brion Vibber + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see UnsubscribeForm + */ + +class TagUnsubForm extends TagSubForm +{ + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'tag-unsubscribe-' . $this->tag; + } + + + /** + * class of the form + * + * @return string of the form class + */ + + function formClass() + { + // class to match existing styles... + return 'form_user_unsubscribe ajax'; + } + + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('tagunsub', array('tag' => $this->tag)); + } + + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + $this->out->element('legend', null, _m('Unsubscribe from this tag')); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Unsubscribe'), 'submit', null, _m('Unsubscribe from this tag')); + } +}