forked from GNUsocial/gnu-social
Merge branch '1.0.x' into limitdist2
This commit is contained in:
commit
e862dcdb8a
@ -152,12 +152,12 @@ class ApprovegroupAction extends Action
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->approve) {
|
if ($this->approve) {
|
||||||
$this->profile->completeJoinGroup($this->group);
|
$this->request->complete();
|
||||||
} elseif ($this->cancel) {
|
} elseif ($this->cancel) {
|
||||||
$this->profile->cancelJoinGroup($this->group);
|
$this->request->abort();
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} 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: 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.
|
// 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->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
|
||||||
|
145
actions/approvesub.php
Normal file
145
actions/approvesub.php
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -139,9 +139,9 @@ class CancelgroupAction extends Action
|
|||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->profile->cancelJoinGroup($this->group);
|
$this->request->abort();
|
||||||
} catch (Exception $e) {
|
} 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: 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.
|
// 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->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
|
||||||
|
119
actions/cancelsubscription.php
Normal file
119
actions/cancelsubscription.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -156,7 +156,7 @@ class GroupqueueAction extends GroupDesignAction
|
|||||||
$members->free();
|
$members->free();
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
|
||||||
$this->page, 'groupmembers',
|
$this->page, 'groupqueue',
|
||||||
array('nickname' => $this->group->nickname));
|
array('nickname' => $this->group->nickname));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,17 @@ class ProfilesettingsAction extends SettingsAction
|
|||||||
($this->arg('autosubscribe')) ?
|
($this->arg('autosubscribe')) ?
|
||||||
$this->boolean('autosubscribe') : $user->autosubscribe);
|
$this->boolean('autosubscribe') : $user->autosubscribe);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->dropdown('subscribe_policy',
|
||||||
|
// TRANS: Dropdown field label on profile settings, for what policies to apply when someone else tries to subscribe to your updates.
|
||||||
|
_('Subscription policy'),
|
||||||
|
array(User::SUBSCRIBE_POLICY_OPEN => _('Let anyone follow me'),
|
||||||
|
User::SUBSCRIBE_POLICY_MODERATE => _('Ask me first')),
|
||||||
|
// TRANS: Dropdown field title on group edit form.
|
||||||
|
_('Whether other users need your permission to follow your updates.'),
|
||||||
|
false,
|
||||||
|
(empty($user->subscribe_policy)) ? User::SUBSCRIBE_POLICY_OPEN : $user->subscribe_policy);
|
||||||
|
$this->elementEnd('li');
|
||||||
}
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
// TRANS: Button to save input in profile settings.
|
// TRANS: Button to save input in profile settings.
|
||||||
@ -234,6 +245,7 @@ class ProfilesettingsAction extends SettingsAction
|
|||||||
$bio = $this->trimmed('bio');
|
$bio = $this->trimmed('bio');
|
||||||
$location = $this->trimmed('location');
|
$location = $this->trimmed('location');
|
||||||
$autosubscribe = $this->boolean('autosubscribe');
|
$autosubscribe = $this->boolean('autosubscribe');
|
||||||
|
$subscribe_policy = $this->trimmed('subscribe_policy');
|
||||||
$language = $this->trimmed('language');
|
$language = $this->trimmed('language');
|
||||||
$timezone = $this->trimmed('timezone');
|
$timezone = $this->trimmed('timezone');
|
||||||
$tagstring = $this->trimmed('tags');
|
$tagstring = $this->trimmed('tags');
|
||||||
@ -333,11 +345,12 @@ class ProfilesettingsAction extends SettingsAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XXX: XOR
|
// XXX: XOR
|
||||||
if ($user->autosubscribe ^ $autosubscribe) {
|
if (($user->autosubscribe ^ $autosubscribe) || $user->subscribe_policy != $subscribe_policy) {
|
||||||
|
|
||||||
$original = clone($user);
|
$original = clone($user);
|
||||||
|
|
||||||
$user->autosubscribe = $autosubscribe;
|
$user->autosubscribe = $autosubscribe;
|
||||||
|
$user->subscribe_policy = $subscribe_policy;
|
||||||
|
|
||||||
$result = $user->update($original);
|
$result = $user->update($original);
|
||||||
|
|
||||||
@ -345,7 +358,7 @@ class ProfilesettingsAction extends SettingsAction
|
|||||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||||
// TRANS: Server error thrown when user profile settings could not be updated to
|
// TRANS: Server error thrown when user profile settings could not be updated to
|
||||||
// TRANS: automatically subscribe to any subscriber.
|
// TRANS: automatically subscribe to any subscriber.
|
||||||
$this->serverError(_('Could not update user for autosubscribe.'));
|
$this->serverError(_('Could not update user for autosubscribe or subscribe_policy.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
142
actions/subqueue.php
Normal file
142
actions/subqueue.php
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<?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');
|
||||||
|
}
|
||||||
|
}
|
@ -139,8 +139,8 @@ class SubscribeAction extends Action
|
|||||||
{
|
{
|
||||||
// Throws exception on error
|
// Throws exception on error
|
||||||
|
|
||||||
Subscription::start($this->user->getProfile(),
|
$sub = Subscription::start($this->user->getProfile(),
|
||||||
$this->other);
|
$this->other);
|
||||||
|
|
||||||
if ($this->boolean('ajax')) {
|
if ($this->boolean('ajax')) {
|
||||||
$this->startHTML('text/xml;charset=utf-8');
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
@ -149,8 +149,12 @@ class SubscribeAction extends Action
|
|||||||
$this->element('title', null, _('Subscribed'));
|
$this->element('title', null, _('Subscribed'));
|
||||||
$this->elementEnd('head');
|
$this->elementEnd('head');
|
||||||
$this->elementStart('body');
|
$this->elementStart('body');
|
||||||
$unsubscribe = new UnsubscribeForm($this, $this->other);
|
if ($sub instanceof Subscription) {
|
||||||
$unsubscribe->show();
|
$form = new UnsubscribeForm($this, $this->other);
|
||||||
|
} else {
|
||||||
|
$form = new CancelSubscriptionForm($this, $this->other);
|
||||||
|
}
|
||||||
|
$form->show();
|
||||||
$this->elementEnd('body');
|
$this->elementEnd('body');
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
|
@ -56,6 +56,71 @@ class Group_join_queue extends Managed_DataObject
|
|||||||
return $rq;
|
return $rq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMember()
|
||||||
|
{
|
||||||
|
$member = Profile::staticGet('id', $this->profile_id);
|
||||||
|
|
||||||
|
if (empty($member)) {
|
||||||
|
// TRANS: Exception thrown providing an invalid profile ID.
|
||||||
|
// TRANS: %s is the invalid profile ID.
|
||||||
|
throw new Exception(sprintf(_("Profile ID %s is invalid."),$this->profile_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $member;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGroup()
|
||||||
|
{
|
||||||
|
$group = User_group::staticGet('id', $this->group_id);
|
||||||
|
|
||||||
|
if (empty($group)) {
|
||||||
|
// TRANS: Exception thrown providing an invalid group ID.
|
||||||
|
// TRANS: %s is the invalid group ID.
|
||||||
|
throw new Exception(sprintf(_("Group ID %s is invalid."),$this->group_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort the pending group join...
|
||||||
|
*
|
||||||
|
* @param User_group $group
|
||||||
|
*/
|
||||||
|
function abort()
|
||||||
|
{
|
||||||
|
$profile = $this->getMember();
|
||||||
|
$group = $this->getGroup();
|
||||||
|
if ($request) {
|
||||||
|
if (Event::handle('StartCancelJoinGroup', array($profile, $group))) {
|
||||||
|
$this->delete();
|
||||||
|
Event::handle('EndCancelJoinGroup', array($profile, $group));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete a pending group join...
|
||||||
|
*
|
||||||
|
* @return Group_member object on success
|
||||||
|
*/
|
||||||
|
function complete(User_group $group)
|
||||||
|
{
|
||||||
|
$join = null;
|
||||||
|
$profile = $this->getMember();
|
||||||
|
$group = $this->getGroup();
|
||||||
|
if (Event::handle('StartJoinGroup', array($profile, $group))) {
|
||||||
|
$join = Group_member::join($group->id, $profile->id);
|
||||||
|
$this->delete();
|
||||||
|
Event::handle('EndJoinGroup', array($profile, $group));
|
||||||
|
}
|
||||||
|
if (!$join) {
|
||||||
|
throw new Exception('Internal error: group join failed.');
|
||||||
|
}
|
||||||
|
$join->notify();
|
||||||
|
return $join;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send notifications via email etc to group administrators about
|
* Send notifications via email etc to group administrators about
|
||||||
* this exciting new pending moderation queue item!
|
* this exciting new pending moderation queue item!
|
||||||
|
@ -297,49 +297,6 @@ class Profile extends Memcached_DataObject
|
|||||||
return $join;
|
return $join;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Complete a pending group join on our end...
|
|
||||||
*
|
|
||||||
* @param User_group $group
|
|
||||||
*/
|
|
||||||
function completeJoinGroup(User_group $group)
|
|
||||||
{
|
|
||||||
$join = null;
|
|
||||||
$request = Group_join_queue::pkeyGet(array('profile_id' => $this->id,
|
|
||||||
'group_id' => $group->id));
|
|
||||||
if ($request) {
|
|
||||||
if (Event::handle('StartJoinGroup', array($group, $this))) {
|
|
||||||
$join = Group_member::join($group->id, $this->id);
|
|
||||||
$request->delete();
|
|
||||||
Event::handle('EndJoinGroup', array($group, $this));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TRANS: Exception thrown trying to approve a non-existing group join request.
|
|
||||||
throw new Exception(_('Invalid group join approval: not pending.'));
|
|
||||||
}
|
|
||||||
if ($join) {
|
|
||||||
$join->notify();
|
|
||||||
}
|
|
||||||
return $join;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leave a group that this profile is a member of.
|
* Leave a group that this profile is a member of.
|
||||||
*
|
*
|
||||||
@ -399,6 +356,36 @@ class Profile extends Memcached_DataObject
|
|||||||
return new ArrayWrapper($profiles);
|
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()
|
function subscriptionCount()
|
||||||
{
|
{
|
||||||
$c = Cache::instance();
|
$c = Cache::instance();
|
||||||
@ -457,6 +444,17 @@ class Profile extends Memcached_DataObject
|
|||||||
return Subscription::exists($this, $other);
|
return Subscription::exists($this, $other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a pending subscription request is outstanding for this...
|
||||||
|
*
|
||||||
|
* @param Profile $other
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
function hasPendingSubscription($other)
|
||||||
|
{
|
||||||
|
return Subscription_queue::exists($this, $other);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are these two profiles subscribed to each other?
|
* Are these two profiles subscribed to each other?
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
|||||||
class Subscription extends Memcached_DataObject
|
class Subscription extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
const CACHE_WINDOW = 201;
|
const CACHE_WINDOW = 201;
|
||||||
|
const FORCE = true;
|
||||||
|
|
||||||
###START_AUTOCODE
|
###START_AUTOCODE
|
||||||
/* the code below is auto generated do not remove the above tag */
|
/* the code below is auto generated do not remove the above tag */
|
||||||
@ -58,11 +59,12 @@ class Subscription extends Memcached_DataObject
|
|||||||
*
|
*
|
||||||
* @param Profile $subscriber party to receive new notices
|
* @param Profile $subscriber party to receive new notices
|
||||||
* @param Profile $other party sending notices; publisher
|
* @param Profile $other party sending notices; publisher
|
||||||
|
* @param bool $force pass Subscription::FORCE to override local subscription approval
|
||||||
*
|
*
|
||||||
* @return Subscription new subscription
|
* @return mixed Subscription or Subscription_queue: new subscription info
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static function start($subscriber, $other)
|
static function start($subscriber, $other, $force=false)
|
||||||
{
|
{
|
||||||
// @fixme should we enforce this as profiles in callers instead?
|
// @fixme should we enforce this as profiles in callers instead?
|
||||||
if ($subscriber instanceof User) {
|
if ($subscriber instanceof User) {
|
||||||
@ -88,35 +90,39 @@ class Subscription extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Event::handle('StartSubscribe', array($subscriber, $other))) {
|
if (Event::handle('StartSubscribe', array($subscriber, $other))) {
|
||||||
$sub = self::saveNew($subscriber->id, $other->id);
|
|
||||||
$sub->notify();
|
|
||||||
|
|
||||||
self::blow('user:notices_with_friends:%d', $subscriber->id);
|
|
||||||
|
|
||||||
self::blow('subscription:by-subscriber:'.$subscriber->id);
|
|
||||||
self::blow('subscription:by-subscribed:'.$other->id);
|
|
||||||
|
|
||||||
$subscriber->blowSubscriptionCount();
|
|
||||||
$other->blowSubscriberCount();
|
|
||||||
|
|
||||||
$otherUser = User::staticGet('id', $other->id);
|
$otherUser = User::staticGet('id', $other->id);
|
||||||
|
if ($otherUser && $otherUser->subscribe_policy == User::SUBSCRIBE_POLICY_MODERATE && !$force) {
|
||||||
|
$sub = Subscription_queue::saveNew($subscriber, $other);
|
||||||
|
$sub->notify();
|
||||||
|
} else {
|
||||||
|
$sub = self::saveNew($subscriber->id, $other->id);
|
||||||
|
$sub->notify();
|
||||||
|
|
||||||
if (!empty($otherUser) &&
|
self::blow('user:notices_with_friends:%d', $subscriber->id);
|
||||||
$otherUser->autosubscribe &&
|
|
||||||
!self::exists($other, $subscriber) &&
|
|
||||||
!$subscriber->hasBlocked($other)) {
|
|
||||||
|
|
||||||
try {
|
self::blow('subscription:by-subscriber:'.$subscriber->id);
|
||||||
self::start($other, $subscriber);
|
self::blow('subscription:by-subscribed:'.$other->id);
|
||||||
} catch (Exception $e) {
|
|
||||||
common_log(LOG_ERR, "Exception during autosubscribe of {$other->nickname} to profile {$subscriber->id}: {$e->getMessage()}");
|
$subscriber->blowSubscriptionCount();
|
||||||
|
$other->blowSubscriberCount();
|
||||||
|
|
||||||
|
if (!empty($otherUser) &&
|
||||||
|
$otherUser->autosubscribe &&
|
||||||
|
!self::exists($other, $subscriber) &&
|
||||||
|
!$subscriber->hasBlocked($other)) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
self::start($other, $subscriber);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_ERR, "Exception during autosubscribe of {$other->nickname} to profile {$subscriber->id}: {$e->getMessage()}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::handle('EndSubscribe', array($subscriber, $other));
|
Event::handle('EndSubscribe', array($subscriber, $other));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return $sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
105
classes/Subscription_queue.php
Normal file
105
classes/Subscription_queue.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Table Definition for subscription_queue
|
||||||
|
*/
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
class Subscription_queue extends Managed_DataObject
|
||||||
|
{
|
||||||
|
###START_AUTOCODE
|
||||||
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
|
public $__table = 'subscription_queue'; // table name
|
||||||
|
public $subscriber;
|
||||||
|
public $subscribed;
|
||||||
|
public $created;
|
||||||
|
|
||||||
|
/* Static get */
|
||||||
|
function staticGet($k,$v=null)
|
||||||
|
{ return Memcached_DataObject::staticGet('Subscription_queue',$k,$v); }
|
||||||
|
|
||||||
|
/* Pkey get */
|
||||||
|
function pkeyGet($k)
|
||||||
|
{ return Memcached_DataObject::pkeyGet('Subscription_queue',$k); }
|
||||||
|
|
||||||
|
/* the code above is auto generated do not remove the tag below */
|
||||||
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
public static function schemaDef()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'description' => 'Holder for subscription requests awaiting moderation.',
|
||||||
|
'fields' => array(
|
||||||
|
'subscriber' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local profile making the request'),
|
||||||
|
'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local profile being subscribed to'),
|
||||||
|
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||||
|
),
|
||||||
|
'primary key' => array('subscriber', 'subscribed'),
|
||||||
|
'indexes' => array(
|
||||||
|
'subscription_queue_subscriber_created_idx' => array('subscriber', 'created'),
|
||||||
|
'subscription_queue_subscribed_created_idx' => array('subscribed', 'created'),
|
||||||
|
),
|
||||||
|
'foreign keys' => array(
|
||||||
|
'subscription_queue_subscriber_fkey' => array('profile', array('subscriber' => 'id')),
|
||||||
|
'subscription_queue_subscribed_fkey' => array('profile', array('subscribed' => 'id')),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveNew(Profile $subscriber, Profile $subscribed)
|
||||||
|
{
|
||||||
|
$rq = new Subscription_queue();
|
||||||
|
$rq->subscriber = $subscriber->id;
|
||||||
|
$rq->subscribed = $subscribed->id;
|
||||||
|
$rq->created = common_sql_now();
|
||||||
|
$rq->insert();
|
||||||
|
return $rq;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists($subscriber, $other)
|
||||||
|
{
|
||||||
|
$sub = Subscription_queue::pkeyGet(array('subscriber' => $subscriber->id,
|
||||||
|
'subscribed' => $other->id));
|
||||||
|
return (empty($sub)) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete a pending subscription, as we've got approval of some sort.
|
||||||
|
*
|
||||||
|
* @return Subscription
|
||||||
|
*/
|
||||||
|
public function complete()
|
||||||
|
{
|
||||||
|
$subscriber = Profile::staticGet('id', $this->subscriber);
|
||||||
|
$subscribed = Profile::staticGet('id', $this->subscribed);
|
||||||
|
$sub = Subscription::start($subscriber, $subscribed, Subscription::FORCE);
|
||||||
|
if ($sub) {
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
|
return $sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel an outstanding subscription request to the other profile.
|
||||||
|
*/
|
||||||
|
public function abort()
|
||||||
|
{
|
||||||
|
$subscriber = Profile::staticGet('id', $this->subscriber);
|
||||||
|
$subscribed = Profile::staticGet('id', $this->subscribed);
|
||||||
|
if (Event::handle('StartCancelSubscription', array($subscriber, $subscribed))) {
|
||||||
|
$this->delete();
|
||||||
|
Event::handle('EndCancelSubscription', array($subscriber, $subscribed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send notifications via email etc to group administrators about
|
||||||
|
* this exciting new pending moderation queue item!
|
||||||
|
*/
|
||||||
|
public function notify()
|
||||||
|
{
|
||||||
|
$other = Profile::staticGet('id', $this->subscriber);
|
||||||
|
$listenee = User::staticGet('id', $this->subscribed);
|
||||||
|
mail_subscribe_pending_notify_profile($listenee, $other);
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,9 @@ require_once 'Validate.php';
|
|||||||
|
|
||||||
class User extends Memcached_DataObject
|
class User extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
|
const SUBSCRIBE_POLICY_OPEN = 0;
|
||||||
|
const SUBSCRIBE_POLICY_MODERATE = 1;
|
||||||
|
|
||||||
###START_AUTOCODE
|
###START_AUTOCODE
|
||||||
/* the code below is auto generated do not remove the above tag */
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ class User extends Memcached_DataObject
|
|||||||
public $smsemail; // varchar(255)
|
public $smsemail; // varchar(255)
|
||||||
public $uri; // varchar(255) unique_key
|
public $uri; // varchar(255) unique_key
|
||||||
public $autosubscribe; // tinyint(1)
|
public $autosubscribe; // tinyint(1)
|
||||||
|
public $subscribe_policy; // tinyint(1)
|
||||||
public $urlshorteningservice; // varchar(50) default_ur1.ca
|
public $urlshorteningservice; // varchar(50) default_ur1.ca
|
||||||
public $inboxed; // tinyint(1)
|
public $inboxed; // tinyint(1)
|
||||||
public $design_id; // int(4)
|
public $design_id; // int(4)
|
||||||
@ -86,6 +90,12 @@ class User extends Memcached_DataObject
|
|||||||
return $profile->isSubscribed($other);
|
return $profile->isSubscribed($other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasPendingSubscription($other)
|
||||||
|
{
|
||||||
|
$profile = $this->getProfile();
|
||||||
|
return $profile->hasPendingSubscription($other);
|
||||||
|
}
|
||||||
|
|
||||||
// 'update' won't write key columns, so we have to do it ourselves.
|
// 'update' won't write key columns, so we have to do it ourselves.
|
||||||
|
|
||||||
function updateKeys(&$orig)
|
function updateKeys(&$orig)
|
||||||
|
@ -591,6 +591,7 @@ smsreplies = 17
|
|||||||
smsemail = 2
|
smsemail = 2
|
||||||
uri = 2
|
uri = 2
|
||||||
autosubscribe = 17
|
autosubscribe = 17
|
||||||
|
subscribe_policy = 17
|
||||||
urlshorteningservice = 2
|
urlshorteningservice = 2
|
||||||
inboxed = 17
|
inboxed = 17
|
||||||
design_id = 1
|
design_id = 1
|
||||||
|
@ -118,6 +118,7 @@ $schema['user'] = array(
|
|||||||
'smsemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'built from sms and carrier'),
|
'smsemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'built from sms and carrier'),
|
||||||
'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
|
'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
|
||||||
'autosubscribe' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'automatically subscribe to users who subscribe to us'),
|
'autosubscribe' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'automatically subscribe to users who subscribe to us'),
|
||||||
|
'subscribe_policy' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => '0 = anybody can subscribe; 1 = require approval'),
|
||||||
'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
|
'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
|
||||||
'inboxed' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'has an inbox been created for this user?'),
|
'inboxed' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'has an inbox been created for this user?'),
|
||||||
'design_id' => array('type' => 'int', 'description' => 'id of a design'),
|
'design_id' => array('type' => 'int', 'description' => 'id of a design'),
|
||||||
@ -1031,3 +1032,5 @@ $schema['schema_version'] = array(
|
|||||||
);
|
);
|
||||||
|
|
||||||
$schema['group_join_queue'] = Group_join_queue::schemaDef();
|
$schema['group_join_queue'] = Group_join_queue::schemaDef();
|
||||||
|
|
||||||
|
$schema['subscription_queue'] = Subscription_queue::schemaDef();
|
||||||
|
@ -144,6 +144,9 @@ class AccountProfileBlock extends ProfileBlock
|
|||||||
if ($cur->isSubscribed($this->profile)) {
|
if ($cur->isSubscribed($this->profile)) {
|
||||||
$usf = new UnsubscribeForm($this->out, $this->profile);
|
$usf = new UnsubscribeForm($this->out, $this->profile);
|
||||||
$usf->show();
|
$usf->show();
|
||||||
|
} else if ($cur->hasPendingSubscription($this->profile)) {
|
||||||
|
$sf = new CancelSubscriptionForm($this->out, $this->profile);
|
||||||
|
$sf->show();
|
||||||
} else {
|
} else {
|
||||||
$sf = new SubscribeForm($this->out, $this->profile);
|
$sf = new SubscribeForm($this->out, $this->profile);
|
||||||
$sf->show();
|
$sf->show();
|
||||||
|
114
lib/approvesubform.php
Normal file
114
lib/approvesubform.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?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'));
|
||||||
|
}
|
||||||
|
}
|
129
lib/cancelsubscriptionform.php
Normal file
129
lib/cancelsubscriptionform.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?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'));
|
||||||
|
}
|
||||||
|
}
|
43
lib/mail.php
43
lib/mail.php
@ -259,6 +259,49 @@ function mail_subscribe_notify_profile($listenee, $other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mail_subscribe_pending_notify_profile($listenee, $other)
|
||||||
|
{
|
||||||
|
if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
|
||||||
|
$listenee->email && $listenee->emailnotifysub) {
|
||||||
|
|
||||||
|
$profile = $listenee->getProfile();
|
||||||
|
|
||||||
|
$name = $profile->getBestName();
|
||||||
|
|
||||||
|
$long_name = ($other->fullname) ?
|
||||||
|
($other->fullname . ' (' . $other->nickname . ')') : $other->nickname;
|
||||||
|
|
||||||
|
$recipients = $listenee->email;
|
||||||
|
|
||||||
|
// use the recipient's localization
|
||||||
|
common_switch_locale($listenee->language);
|
||||||
|
|
||||||
|
$headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname);
|
||||||
|
$headers['From'] = mail_notify_from();
|
||||||
|
$headers['To'] = $name . ' <' . $listenee->email . '>';
|
||||||
|
// TRANS: Subject of pending new-subscriber notification e-mail.
|
||||||
|
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
|
||||||
|
$headers['Subject'] = sprintf(_('%1$s would like to listen to '.
|
||||||
|
'your notices on %2$s.'),
|
||||||
|
$other->getBestName(),
|
||||||
|
common_config('site', 'name'));
|
||||||
|
|
||||||
|
// TRANS: Main body of pending new-subscriber notification e-mail.
|
||||||
|
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
|
||||||
|
$body = sprintf(_('%1$s would like to listen to your notices on %2$s. ' .
|
||||||
|
'You may approve or reject their subscription at %3$s'),
|
||||||
|
$long_name,
|
||||||
|
common_config('site', 'name'),
|
||||||
|
common_local_url('subqueue', array('nickname' => $listenee->nickname))) .
|
||||||
|
mail_profile_block($other) .
|
||||||
|
mail_footer_block();
|
||||||
|
|
||||||
|
// reset localization
|
||||||
|
common_switch_locale();
|
||||||
|
mail_send($recipients, $headers, $body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function mail_footer_block()
|
function mail_footer_block()
|
||||||
{
|
{
|
||||||
// TRANS: Common footer block for StatusNet notification emails.
|
// TRANS: Common footer block for StatusNet notification emails.
|
||||||
|
@ -199,7 +199,8 @@ class Router
|
|||||||
// main stuff is repetitive
|
// main stuff is repetitive
|
||||||
|
|
||||||
$main = array('login', 'logout', 'register', 'subscribe',
|
$main = array('login', 'logout', 'register', 'subscribe',
|
||||||
'unsubscribe', 'confirmaddress', 'recoverpassword',
|
'unsubscribe', 'cancelsubscription', 'approvesub',
|
||||||
|
'confirmaddress', 'recoverpassword',
|
||||||
'invite', 'favor', 'disfavor', 'sup',
|
'invite', 'favor', 'disfavor', 'sup',
|
||||||
'block', 'unblock', 'subedit',
|
'block', 'unblock', 'subedit',
|
||||||
'groupblock', 'groupunblock',
|
'groupblock', 'groupunblock',
|
||||||
@ -843,6 +844,10 @@ class Router
|
|||||||
array('tag' => self::REGEX_TAG));
|
array('tag' => self::REGEX_TAG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$m->connect('subscribers/pending',
|
||||||
|
array('action' => 'subqueue',
|
||||||
|
'nickname' => $nickname));
|
||||||
|
|
||||||
foreach (array('rss', 'groups') as $a) {
|
foreach (array('rss', 'groups') as $a) {
|
||||||
$m->connect($a,
|
$m->connect($a,
|
||||||
array('action' => 'user'.$a,
|
array('action' => 'user'.$a,
|
||||||
@ -899,6 +904,9 @@ class Router
|
|||||||
array('action' => $a),
|
array('action' => $a),
|
||||||
array('nickname' => Nickname::DISPLAY_FMT));
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
}
|
}
|
||||||
|
$m->connect(':nickname/subscribers/pending',
|
||||||
|
array('action' => 'subqueue'),
|
||||||
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
foreach (array('subscriptions', 'subscribers') as $a) {
|
foreach (array('subscriptions', 'subscribers') as $a) {
|
||||||
$m->connect(':nickname/'.$a.'/:tag',
|
$m->connect(':nickname/'.$a.'/:tag',
|
||||||
|
@ -96,6 +96,20 @@ class SubGroupNav extends Menu
|
|||||||
$this->user->nickname),
|
$this->user->nickname),
|
||||||
$action == 'subscribers',
|
$action == 'subscribers',
|
||||||
'nav_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',
|
$this->out->menuItem(common_local_url('usergroups',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$this->user->nickname)),
|
$this->user->nickname)),
|
||||||
@ -118,4 +132,11 @@ class SubGroupNav extends Menu
|
|||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function countPendingSubs()
|
||||||
|
{
|
||||||
|
$req = new Subscription_queue();
|
||||||
|
$req->subscribed = $this->user->id;
|
||||||
|
return $req->count();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class ShortenAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle($args=null)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
header('Content-Type: text/plain');
|
header('Content-Type: text/plain');
|
||||||
|
Loading…
Reference in New Issue
Block a user