try {
if ($this->approve) {
- $this->profile->completeJoinGroup($this->group);
+ $this->request->complete();
} elseif ($this->cancel) {
- $this->profile->cancelJoinGroup($this->group);
+ $this->request->abort();
}
} catch (Exception $e) {
common_log(LOG_ERROR, "Exception canceling group sub: " . $e->getMessage());
parent::handle($args);
try {
- $this->profile->cancelJoinGroup($this->group);
+ $this->request->abort();
} 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.
($this->arg('autosubscribe')) ?
$this->boolean('autosubscribe') : $user->autosubscribe);
$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');
// TRANS: Button to save input in profile settings.
$bio = $this->trimmed('bio');
$location = $this->trimmed('location');
$autosubscribe = $this->boolean('autosubscribe');
+ $subscribe_policy = $this->trimmed('subscribe_policy');
$language = $this->trimmed('language');
$timezone = $this->trimmed('timezone');
$tagstring = $this->trimmed('tags');
}
// XXX: XOR
- if ($user->autosubscribe ^ $autosubscribe) {
+ if (($user->autosubscribe ^ $autosubscribe) || $user->subscribe_policy != $subscribe_policy) {
$original = clone($user);
$user->autosubscribe = $autosubscribe;
+ $user->subscribe_policy = $subscribe_policy;
$result = $user->update($original);
common_log_db_error($user, 'UPDATE', __FILE__);
// TRANS: Server error thrown when user profile settings could not be updated to
// 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 $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
* this exciting new pending moderation queue item!
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.
*
}
}
- /**
- * Request a subscription to another local or remote profile.
- * This will result in either the subscription going through
- * immediately, being queued for approval, or being rejected
- * immediately.
- *
- * @param Profile $profile
- * @return mixed: Subscription or Subscription_queue object on success
- * @throws Exception of various types on invalid state
- */
- function subscribe($profile)
- {
- //
- }
-
- /**
- * Cancel an outstanding subscription request to the other profile.
- *
- * @param Profile $profile
- */
- function cancelSubscribe($profile)
- {
- $request = Subscribe_join_queue::pkeyGet(array('subscriber' => $this->id,
- 'subscribed' => $profile->id));
- if ($request) {
- if (Event::handle('StartCancelSubscription', array($this, $profile))) {
- $request->delete();
- Event::handle('EndCancelSubscription', array($this, $profile));
- }
- }
- }
-
- /**
- *
- * @param <type> $profile
- */
- function completeSubscribe($profile)
- {
-
- }
-
function getSubscriptions($offset=0, $limit=null)
{
$subs = Subscription::bySubscriber($this->id,
class Subscription extends Memcached_DataObject
{
const CACHE_WINDOW = 201;
+ const FORCE = true;
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
*
* @param Profile $subscriber party to receive new notices
* @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?
if ($subscriber instanceof User) {
}
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);
-
- 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()}");
+ 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();
+
+ 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();
+
+ 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()}");
+ }
}
}
return $rq;
}
+ /**
+ * 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, $other, Subscription::FORCE);
+ if ($sub) {
+ $this->delete();
+ }
+ return $sub;
+ }
+
+ /**
+ * Cancel an outstanding subscription request to the other profile.
+ */
+ public function abort($profile)
+ {
+ $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!
class User extends Memcached_DataObject
{
+ const SUBSCRIBE_POLICY_OPEN = 0;
+ const SUBSCRIBE_POLICY_MODERATE = 1;
+
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $smsemail; // varchar(255)
public $uri; // varchar(255) unique_key
public $autosubscribe; // tinyint(1)
+ public $subscribe_policy; // tinyint(1)
public $urlshorteningservice; // varchar(50) default_ur1.ca
public $inboxed; // tinyint(1)
public $design_id; // int(4)
smsemail = 2
uri = 2
autosubscribe = 17
+subscribe_policy = 17
urlshorteningservice = 2
inboxed = 17
design_id = 1
'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'),
'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'),
'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'),