$this->request->abort();
}
} catch (Exception $e) {
- common_log(LOG_ERROR, "Exception canceling group sub: " . $e->getMessage());
+ common_log(LOG_ERR, "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.'),
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Leave a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Group
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * 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 <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class ApprovesubAction extends Action
+{
+ var $profile = null;
+
+ /**
+ * Prepare to run
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $cur = common_current_user();
+ if (empty($cur)) {
+ // TRANS: Client error displayed trying to approve group membership while not logged in.
+ $this->clientError(_('Must be logged in.'), 403);
+ return false;
+ }
+ if ($this->arg('profile_id')) {
+ $this->profile = Profile::staticGet('id', $this->arg('profile_id'));
+ } else {
+ // TRANS: Client error displayed trying to approve subscriptionswithout specifying a profile to approve.
+ $this->clientError(_('Must specify a profile.'));
+ return false;
+ }
+
+ $this->request = Subscription_queue::pkeyGet(array('subscriber' => $this->profile->id,
+ 'subscribed' => $cur->id));
+
+ if (empty($this->request)) {
+ // TRANS: Client error displayed trying to approve subscription for a non-existing request.
+ $this->clientError(sprintf(_('%s is not in the moderation queue for your subscriptions.'), $this->profile->nickname), 403);
+ }
+
+ $this->approve = (bool)$this->arg('approve');
+ $this->cancel = (bool)$this->arg('cancel');
+ if (!$this->approve && !$this->cancel) {
+ // TRANS: Client error displayed trying to approve/deny subscription.
+ $this->clientError(_('Internal error: received neither cancel nor abort.'));
+ }
+ if ($this->approve && $this->cancel) {
+ // TRANS: Client error displayed trying to approve/deny subscription
+ $this->clientError(_('Internal error: received both cancel and abort.'));
+ }
+ 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);
+ $cur = common_current_user();
+
+ try {
+ if ($this->approve) {
+ $this->request->complete();
+ } elseif ($this->cancel) {
+ $this->request->abort();
+ }
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Exception canceling sub: " . $e->getMessage());
+ // TRANS: Server error displayed when cancelling a queued subscription request fails.
+ // TRANS: %1$s is the leaving user's nickname, $2$s is the nickname for which the leave failed.
+ $this->serverError(sprintf(_('Could not cancel or approve request for user %1$s to join group %2$s.'),
+ $this->profile->nickname, $cur->nickname));
+ return;
+ }
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Title for subscription approval ajax return
+ // TRANS: %1$s is the approved user's nickname
+ $this->element('title', null, sprintf(_m('TITLE','%1$s\'s request'),
+ $this->profile->nickname));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ if ($this->approve) {
+ // TRANS: Message on page for user after approving a subscription request.
+ $this->element('p', 'success', _('Subscription approved.'));
+ } elseif ($this->cancel) {
+ // TRANS: Message on page for user after rejecting a subscription request.
+ $this->element('p', 'success', _('Subscription canceled.'));
+ }
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect(common_local_url('subqueue', array('nickname' =>
+ $cur->nickname)),
+ 303);
+ }
+ }
+}
try {
$this->request->abort();
} catch (Exception $e) {
- common_log(LOG_ERROR, "Exception canceling group sub: " . $e->getMessage());
+ common_log(LOG_ERR, "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.'),
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Leave a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Group
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * 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 <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class CancelsubscriptionAction extends Action
+{
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true);
+ }
+ if (!common_logged_in()) {
+ $this->clientError(_('Not logged in.'));
+ return;
+ }
+
+ $user = common_current_user();
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ common_redirect(common_local_url('subscriptions',
+ array('nickname' => $user->nickname)));
+ return;
+ }
+
+ /* Use a session token for CSRF protection. */
+
+ $token = $this->trimmed('token');
+
+ if (!$token || $token != common_session_token()) {
+ $this->clientError(_('There was a problem with your session token. ' .
+ 'Try again, please.'));
+ return;
+ }
+
+ $other_id = $this->arg('unsubscribeto');
+
+ if (!$other_id) {
+ $this->clientError(_('No profile ID in request.'));
+ return;
+ }
+
+ $other = Profile::staticGet('id', $other_id);
+
+ if (!$other) {
+ $this->clientError(_('No profile with that ID.'));
+ return;
+ }
+
+ $this->request = Subscription_queue::pkeyGet(array('subscriber' => $user->id,
+ 'subscribed' => $other->id));
+
+ if (empty($this->request)) {
+ // TRANS: Client error displayed when trying to approve a non-existing group join request.
+ // TRANS: %s is a user nickname.
+ $this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
+ }
+
+ $this->request->abort();
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ $this->element('title', null, _('Unsubscribed'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $subscribe = new SubscribeForm($this, $other);
+ $subscribe->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect(common_local_url('subscriptions',
+ array('nickname' => $user->nickname)),
+ 303);
+ }
+ }
+}
$members->free();
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
- $this->page, 'groupmembers',
+ $this->page, 'groupqueue',
array('nickname' => $this->group->nickname));
}
}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of group members
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Group
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once(INSTALLDIR.'/lib/profilelist.php');
+
+/**
+ * List of group members
+ *
+ * @category Group
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class SubqueueAction extends GalleryAction
+{
+ var $page = null;
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ // @todo FIXME: most of this belongs in a base class, sounds common to most group actions?
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $cur = common_current_user();
+ if (!$cur || $cur->id != $this->profile->id) {
+ // TRANS: Client error displayed when trying to approve group applicants without being a group administrator.
+ $this->clientError(_('You may only approve your own pending subscriptions.'));
+ return false;
+ }
+ return true;
+ }
+
+ function title()
+ {
+ if ($this->page == 1) {
+ // TRANS: Title of the first page showing pending subscribers still awaiting approval.
+ // TRANS: %s is the name of the user.
+ return sprintf(_('%s subscribers awaiting approval'),
+ $this->profile->nickname);
+ } else {
+ // TRANS: Title of all but the first page showing pending subscribersmembers still awaiting approval.
+ // TRANS: %1$s is the name of the user, %2$d is the page number of the members list.
+ return sprintf(_('%1$s subscribers awaiting approval, page %2$d'),
+ $this->profile->nickname,
+ $this->page);
+ }
+ }
+
+ function showPageNotice()
+ {
+ $this->element('p', 'instructions',
+ // TRANS: Page notice for group members page.
+ _('A list of users awaiting approval to subscribe to you.'));
+ }
+
+
+ function showContent()
+ {
+ $offset = ($this->page-1) * PROFILES_PER_PAGE;
+ $limit = PROFILES_PER_PAGE + 1;
+
+ $cnt = 0;
+
+ $members = $this->profile->getRequests($offset, $limit);
+
+ if ($members) {
+ // @fixme change!
+ $member_list = new SubQueueList($members, $this);
+ $cnt = $member_list->show();
+ }
+
+ $members->free();
+
+ $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
+ $this->page, 'subqueue',
+ array('nickname' => $this->profile->nickname)); // urgh
+ }
+}
+
+class SubQueueList extends ProfileList
+{
+ function newListItem($profile)
+ {
+ return new SubQueueListItem($profile, $this->action);
+ }
+}
+
+class SubQueueListItem extends ProfileListItem
+{
+ function showActions()
+ {
+ $this->startActions();
+ if (Event::handle('StartProfileListItemActionElements', array($this))) {
+ $this->showApproveButtons();
+ Event::handle('EndProfileListItemActionElements', array($this));
+ }
+ $this->endActions();
+ }
+
+ function showApproveButtons()
+ {
+ $this->out->elementStart('li', 'entity_approval');
+ $form = new ApproveSubForm($this->out, $this->profile);
+ $form->show();
+ $this->out->elementEnd('li');
+ }
+}
return new ArrayWrapper($profiles);
}
+ /**
+ * Get pending subscribers, who have not yet been approved.
+ *
+ * @param int $offset
+ * @param int $limit
+ * @return Profile
+ */
+ function getRequests($offset=0, $limit=null)
+ {
+ $qry =
+ 'SELECT profile.* ' .
+ 'FROM profile JOIN subscription_queue '.
+ 'ON profile.id = subscription_queue.subscriber ' .
+ 'WHERE subscription_queue.subscribed = %d ' .
+ 'ORDER BY subscription_queue.created DESC ';
+
+ if ($limit != null) {
+ if (common_config('db','type') == 'pgsql') {
+ $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
+ } else {
+ $qry .= ' LIMIT ' . $offset . ', ' . $limit;
+ }
+ }
+
+ $members = new Profile();
+
+ $members->query(sprintf($qry, $this->id));
+ return $members;
+ }
+
function subscriptionCount()
{
$c = Cache::instance();
Event::handle('EndSubscribe', array($subscriber, $other));
}
- return true;
+ return $sub;
}
/**
{
$subscriber = Profile::staticGet('id', $this->subscriber);
$subscribed = Profile::staticGet('id', $this->subscribed);
- $sub = Subscription::start($subscriber, $other, Subscription::FORCE);
+ $sub = Subscription::start($subscriber, $subscribed, Subscription::FORCE);
if ($sub) {
$this->delete();
}
/**
* Cancel an outstanding subscription request to the other profile.
*/
- public function abort($profile)
+ public function abort()
{
$subscriber = Profile::staticGet('id', $this->subscriber);
$subscribed = Profile::staticGet('id', $this->subscribed);
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for leaving a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @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 <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see UnsubscribeForm
+ */
+class ApproveSubForm extends Form
+{
+ var $profile = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile user whose request to accept or drop
+ */
+ function __construct($out=null, $profile=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return string ID of the form
+ */
+ function id()
+ {
+ return 'sub-queue-' . $this->profile->id;
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+ function formClass()
+ {
+ return 'form_sub_queue ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ $params = array();
+ if ($this->profile) {
+ $params['profile_id'] = $this->profile->id;
+ }
+ return common_local_url('approvesub',
+ array(), $params);
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ // TRANS: Submit button text to accept a subscription request on approve sub form.
+ $this->out->submit('approve', _m('BUTTON','Accept'));
+ // TRANS: Submit button text to reject a subscription request on approve sub form.
+ $this->out->submit('cancel', _m('BUTTON','Reject'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for leaving a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @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 <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see UnsubscribeForm
+ */
+
+class CancelSubscriptionForm extends Form
+{
+ /**
+ * user being subscribed to
+ */
+
+ var $profile = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Profile $profile being subscribed to
+ */
+
+ function __construct($out=null, $profile=null)
+ {
+ parent::__construct($out);
+
+ $this->profile = $profile;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return string ID of the form
+ */
+
+ function id()
+ {
+ return 'subscription-cancel-' . $this->profile->id;
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+
+ function formClass()
+ {
+ return 'form_unsubscribe ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('cancelsubscription',
+ array(),
+ array('id' => $this->profile->id));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden('unsubscribeto-' . $this->profile->id,
+ $this->profile->id,
+ 'unsubscribeto');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Cancel sub request'));
+ }
+}
// main stuff is repetitive
$main = array('login', 'logout', 'register', 'subscribe',
- 'unsubscribe', 'cancelsubscription',
+ 'unsubscribe', 'cancelsubscription', 'approvesub',
'confirmaddress', 'recoverpassword',
'invite', 'favor', 'disfavor', 'sup',
'block', 'unblock', 'subedit',
array('tag' => self::REGEX_TAG));
}
+ $m->connect('subscribers/pending',
+ array('action' => 'subqueue',
+ 'nickname' => $nickname));
+
foreach (array('rss', 'groups') as $a) {
$m->connect($a,
array('action' => 'user'.$a,
array('action' => $a),
array('nickname' => Nickname::DISPLAY_FMT));
}
+ $m->connect(':nickname/subscribers/pending',
+ array('action' => 'subqueue'),
+ array('nickname' => Nickname::DISPLAY_FMT));
foreach (array('subscriptions', 'subscribers') as $a) {
$m->connect(':nickname/'.$a.'/:tag',
$this->user->nickname),
$action == 'subscribers',
'nav_subscribers');
+ if ($cur && $cur->id == $this->user->id) {
+ // Possibly site admins should be able to get in here too
+ $pending = $this->countPendingSubs();
+ if ($pending || $cur->subscribe_policy == User::SUBSCRIBE_POLICY_MODERATE) {
+ $this->out->menuItem(common_local_url('subqueue',
+ array('nickname' =>
+ $this->user->nickname)),
+ sprintf(_('Pending (%d)'), $pending),
+ sprintf(_('Approve pending subscription requests'),
+ $this->user->nickname),
+ $action == 'subqueueaction',
+ 'nav_subscribers');
+ }
+ }
$this->out->menuItem(common_local_url('usergroups',
array('nickname' =>
$this->user->nickname)),
$this->out->elementEnd('ul');
}
+
+ function countPendingSubs()
+ {
+ $req = new Subscription_queue();
+ $req->subscribed = $this->user->id;
+ return $req->count();
+ }
}