From 471a4805871c44ad8770342ca8ca05536068dc85 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 21 Mar 2011 16:26:41 -0700 Subject: [PATCH] Logic to have group joins turn into pending joins automatically when group is set to mod; allow users to cancel their pending group requests. --- actions/cancelgroup.php | 154 +++++++++++++++++++++++++++++++++++ actions/joingroup.php | 14 +++- classes/Group_join_queue.php | 4 + classes/Profile.php | 24 ++++++ lib/cancelgroupform.php | 116 ++++++++++++++++++++++++++ lib/groupprofileblock.php | 8 +- lib/router.php | 2 +- 7 files changed, 316 insertions(+), 6 deletions(-) create mode 100644 actions/cancelgroup.php create mode 100644 lib/cancelgroupform.php diff --git a/actions/cancelgroup.php b/actions/cancelgroup.php new file mode 100644 index 0000000000..089b4d751e --- /dev/null +++ b/actions/cancelgroup.php @@ -0,0 +1,154 @@ +. + * + * @category Group + * @package StatusNet + * @author Evan Prodromou + * @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); +} + +/** + * Leave a group + * + * This is the action for leaving a group. It works more or less like the subscribe action + * for users. + * + * @category Group + * @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/ + */ +class CancelgroupAction extends Action +{ + var $group = null; + + /** + * Prepare to run + */ + function prepare($args) + { + parent::prepare($args); + + if (!common_logged_in()) { + // TRANS: Client error displayed when trying to leave a group while not logged in. + $this->clientError(_('You must be logged in to leave a group.')); + return false; + } + + $nickname_arg = $this->trimmed('nickname'); + $id = intval($this->arg('id')); + if ($id) { + $this->group = User_group::staticGet('id', $id); + } else if ($nickname_arg) { + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + common_redirect(common_local_url('leavegroup', $args), 301); + return false; + } + + $local = Local_group::staticGet('nickname', $nickname); + + if (!$local) { + // TRANS: Client error displayed when trying to leave a non-local group. + $this->clientError(_('No such group.'), 404); + return false; + } + + $this->group = User_group::staticGet('id', $local->group_id); + } else { + // TRANS: Client error displayed when trying to leave a group without providing a group name or group ID. + $this->clientError(_('No nickname or ID.'), 404); + return false; + } + + if (!$this->group) { + // TRANS: Client error displayed when trying to leave a non-existing group. + $this->clientError(_('No such group.'), 404); + return false; + } + + $cur = common_current_user(); + $this->profile = $cur->getProfile(); + + $this->request = Group_join_queue::pkeyGet(array('profile_id' => $this->profile->id, + 'group_id' => $this->group->id)); + + if (empty($this->request)) { + $this->clientError(_('You are not in the moderation queue for this group.'), 403); + } + return true; + } + + /** + * Handle the request + * + * On POST, add the current user to the group + * + * @param array $args unused + * + * @return void + */ + function handle($args) + { + parent::handle($args); + + try { + $this->profile->cancelJoinGroup($this->group); + } catch (Exception $e) { + common_log(LOG_ERROR, "Exception canceling group sub: " . $e->getMessage()); + // TRANS: Server error displayed when cancelling a queued group join request fails. + // TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed. + $this->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'), + $this->profile->nickname, $this->group->nickname)); + return; + } + + if ($this->boolean('ajax')) { + $this->startHTML('text/xml;charset=utf-8'); + $this->elementStart('head'); + // TRANS: Title for leave group page after leaving. + $this->element('title', null, sprintf(_m('TITLE','%1$s left group %2$s'), + $this->profile->nickname, + $this->group->nickname)); + $this->elementEnd('head'); + $this->elementStart('body'); + $jf = new JoinForm($this, $this->group); + $jf->show(); + $this->elementEnd('body'); + $this->elementEnd('html'); + } else { + common_redirect(common_local_url('groupmembers', array('nickname' => + $this->group->nickname)), + 303); + } + } +} diff --git a/actions/joingroup.php b/actions/joingroup.php index 8675dbaed3..f302b39e79 100644 --- a/actions/joingroup.php +++ b/actions/joingroup.php @@ -129,7 +129,7 @@ class JoingroupAction extends Action $cur = common_current_user(); try { - $cur->joinGroup($this->group); + $result = $cur->joinGroup($this->group); } catch (Exception $e) { // TRANS: Server error displayed when joining a group failed in the database. // TRANS: %1$s is the joining user's nickname, $2$s is the group nickname for which the join failed. @@ -147,8 +147,16 @@ class JoingroupAction extends Action $this->group->nickname)); $this->elementEnd('head'); $this->elementStart('body'); - $lf = new LeaveForm($this, $this->group); - $lf->show(); + + if ($result instanceof Group_member) { + $form = new LeaveForm($this, $this->group); + } else if ($result instanceof Group_join_queue) { + $form = new CancelGroupForm($this, $this->group); + } else { + // wtf? + throw new Exception(_m("Unknown error joining group.")); + } + $form->show(); $this->elementEnd('body'); $this->elementEnd('html'); } else { diff --git a/classes/Group_join_queue.php b/classes/Group_join_queue.php index d8deb253b1..ee47b4932d 100644 --- a/classes/Group_join_queue.php +++ b/classes/Group_join_queue.php @@ -18,6 +18,10 @@ class Group_join_queue extends Managed_DataObject function staticGet($k,$v=null) { return Memcached_DataObject::staticGet('Group_join_queue',$k,$v); } + /* Pkey get */ + function pkeyGet($k) + { return Memcached_DataObject::pkeyGet('Group_join_queue',$k); } + /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE diff --git a/classes/Profile.php b/classes/Profile.php index d4b288fa7a..57522d28dc 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -313,6 +313,13 @@ class Profile extends Memcached_DataObject } } + function isPendingMember($group) + { + $request = Group_join_queue::pkeyGet(array('profile_id' => $this->id, + 'group_id' => $group->id)); + return !empty($request); + } + function getGroups($offset=0, $limit=null) { $qry = @@ -360,6 +367,23 @@ class Profile extends Memcached_DataObject return $ok; } + /** + * Cancel a pending group join... + * + * @param User_group $group + */ + function cancelJoinGroup(User_group $group) + { + $request = Group_join_queue::pkeyGet(array('profile_id' => $this->id, + 'group_id' => $group->id)); + if ($request) { + if (Event::handle('StartCancelJoinGroup', array($group, $this))) { + $request->delete(); + Event::handle('EndCancelJoinGroup', array($group, $this)); + } + } + } + /** * Leave a group that this profile is a member of. * diff --git a/lib/cancelgroupform.php b/lib/cancelgroupform.php new file mode 100644 index 0000000000..e71144f0ed --- /dev/null +++ b/lib/cancelgroupform.php @@ -0,0 +1,116 @@ +. + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @author Sarven Capadisli + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/form.php'; + +/** + * Form for leaving a group + * + * @category Form + * @package StatusNet + * @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 CancelGroupForm extends Form +{ + /** + * group for user to leave + */ + + var $group = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param group $group group to leave + */ + + function __construct($out=null, $group=null) + { + parent::__construct($out); + + $this->group = $group; + } + + /** + * ID of the form + * + * @return string ID of the form + */ + + function id() + { + return 'group-cancel-' . $this->group->id; + } + + /** + * class of the form + * + * @return string of the form class + */ + + function formClass() + { + return 'form_group_leave ajax'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('cancelgroup', + array('id' => $this->group->id)); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Cancel join request')); + } +} diff --git a/lib/groupprofileblock.php b/lib/groupprofileblock.php index 9df541e343..819c0fbdcc 100644 --- a/lib/groupprofileblock.php +++ b/lib/groupprofileblock.php @@ -97,10 +97,14 @@ class GroupProfileBlock extends ProfileBlock $this->out->elementStart('li', 'entity_subscribe'); if (Event::handle('StartGroupSubscribe', array($this, $this->group))) { if ($cur) { - if ($cur->isMember($this->group)) { + $profile = $cur->getProfile(); + if ($profile->isMember($this->group)) { $lf = new LeaveForm($this->out, $this->group); $lf->show(); - } else if (!Group_block::isBlocked($this->group, $cur->getProfile())) { + } else if ($profile->isPendingMember($this->group)) { + $cf = new CancelGroupForm($this->out, $this->group); + $cf->show(); + } else if (!Group_block::isBlocked($this->group, $profile)) { $jf = new JoinForm($this->out, $this->group); $jf->show(); } diff --git a/lib/router.php b/lib/router.php index efbd2c6cdd..d6f5a37b06 100644 --- a/lib/router.php +++ b/lib/router.php @@ -366,7 +366,7 @@ class Router $m->connect('group/new', array('action' => 'newgroup')); - foreach (array('edit', 'join', 'leave', 'delete') as $v) { + foreach (array('edit', 'join', 'leave', 'delete', 'cancel') as $v) { $m->connect('group/:nickname/'.$v, array('action' => $v.'group'), array('nickname' => Nickname::DISPLAY_FMT)); -- 2.39.5