Skip to content

Commit

Permalink
+ add unsubscribe to the notify controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Spuds committed Jan 6, 2020
1 parent c527f5e commit 6cc585c
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 6 deletions.
1 change: 0 additions & 1 deletion sources/SiteDispatcher.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ class Site_Dispatcher
'moderate' => array('ModerationCenter_Controller', 'action_index'),
'movetopic' => array('MoveTopic_Controller', 'action_movetopic'),
'movetopic2' => array('MoveTopic_Controller', 'action_movetopic2'),
'notify' => array('Notify_Controller', 'action_notify'),
'notifyboard' => array('Notify_Controller', 'action_notifyboard'),
'openidreturn' => array('OpenID_Controller', 'action_openidreturn'),
'xrds' => array('OpenID_Controller', 'action_xrds'),
Expand Down
150 changes: 149 additions & 1 deletion sources/controllers/Notify.controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,20 @@ public function pre_dispatch()
*/
public function action_index()
{
// The number of choices is boggling, ok there are just 2
$subActions = array(
'notify' => array($this, 'action_notify'),
'unsubscribe' => array($this, 'action_unsubscribe'),
);

// We like action, so lets get ready for some
$action = new Action('');

// Get the subAction, or just go to action_notify
$subAction = $action->initialize($subActions, 'notify');

// forward to our respective method.
// $this->action_notify();
$action->dispatch($subAction);
}

/**
Expand Down Expand Up @@ -393,4 +405,140 @@ private function _toggle_topic_watch()

setTopicWatch($user_info['id'], $topic, $this->_req->query->sa === 'on');
}

/**
* Accessed via the unsubscribe link provided in site emails. This will then
* unsubscribe the user from a board or a topic (depending on the link) without them
* having to login.
*/
public function action_unsubscribe()
{
// Looks like we need to unsubscribe someone
if ($this->_validateUnsubscribeToken($member, $area, $extra))
{
global $user_info, $board, $topic;

// Look away while we stuff the old ballet box, power to the people!
$user_info['id'] = $member['id_member'];
$this->_req->query->sa = 'off';

switch ($area)
{
case 'topic':
$topic = $extra;
$this->_toggle_topic_notification();
case 'board':
$board = $extra;
$this->_toggle_board_notification();
break;
case 'buddy':
case 'likemsg':
case 'mentionmem':
case 'quotedmem':
case 'rlikemsg':
$this->_setUserNotificationArea($member['id_member'], $area, 1);
break;
}

die('made it');
}
}

/**
* Validates a supplied token and extracts the needed bits
*
* @param mixed[] $member Member info from getBasicMemberData
* @param string $area area they want to be removed from
* @param string $extra parameters needed for some areas
* @return bool
*/
private function _validateUnsubscribeToken(&$member, &$area, &$extra)
{
$potentialAreas = array('topic', 'board', 'buddy', 'likemsg', 'mentionmem', 'quotedmem', 'rlikemsg');

// Token was passed and matches our expected pattern
$token = $this->_req->getQuery('token', 'trim', '');
$token = urldecode($token);
if (empty($token) || preg_match('~^(\d+_[a-zA-Z0-9./]{53}_.*)$~', $token, $match) !== 1)
{
return false;
}

// Expand the token
list ($id_member, $hash, $area, $extra, $time) = explode('_', $match[1]);
require_once(SUBSDIR . '/Members.subs.php');

// The area is a known one
if (!in_array($area, $potentialAreas))
{
return false;
}

// Not so old, 2 weeks is plenty
if (time() - $time > 60 * 60 * 24 * 14)
{
return false;
}

// Find the claimed member
$member = getBasicMemberData((int) $id_member, array('authentication' => true));
if (empty($member))
{
return false;
}

// Validate its this members token
require_once(SUBSDIR . '/Notification.subs.php');

return validateNotifierToken(
$member['email_address'],
$member['password_salt'],
$area . $extra . $time,
$hash
);
}

/**
* Used to set a specific mention area to a new value while keeping other
* areas as they are.
*
* @param int $memID
* @param string $area buddy, likemsg, mentionmem, quotedmem, rlikemsg
* @param int $value 1=notify 2=immediate email 3=daily email 4=weekly email
*/
private function _setUserNotificationArea($memID, $area, $value)
{
require_once(SUBSDIR . '/Profile.subs.php');

$to_save = array();
foreach (getMemberNotificationsProfile($memID) as $mention => $data)
{
$to_save[$mention] = 0;

// The area we are changing
if ($mention === $area)
{
// Off is always an option, but if the choice is valid set it
if (isset($data['data'][$value]))
{
$to_save[$mention] = (int) $value;
}

continue;
}

// Some other area, keep the existing choice
foreach ($data['data'] as $key => $choice)
{
if ($choice['enabled'] === true)
{
$to_save[$mention] = (int) $key;

break;
}
}
}

saveUserNotificationsPreferences($memID, $to_save);
}
}
4 changes: 2 additions & 2 deletions sources/subs/Members.subs.php
Original file line number Diff line number Diff line change
Expand Up @@ -1649,7 +1649,7 @@ function maxMemberID()
* - 'sort' (string) a column to sort the results
* - 'moderation' (bool) includes member_ip, id_group, additional_groups, last_login
* - 'authentication' (bool) includes secret_answer, secret_question, openid_uri,
* is_activated, validation_code, passwd_flood
* is_activated, validation_code, passwd_flood, password_salt
* - 'preferences' (bool) includes lngfile, mod_prefs, notify_types, signature
* @return array
*/
Expand Down Expand Up @@ -1686,7 +1686,7 @@ function getBasicMemberData($member_ids, $options = array())
$request = $db->query('', '
SELECT id_member, member_name, real_name, email_address, hide_email, posts, id_theme' . (!empty($options['moderation']) ? ',
member_ip, id_group, additional_groups, last_login, id_post_group' : '') . (!empty($options['authentication']) ? ',
secret_answer, secret_question, openid_uri, is_activated, validation_code, passwd_flood' : '') . (!empty($options['preferences']) ? ',
secret_answer, secret_question, openid_uri, is_activated, validation_code, passwd_flood, password_salt' : '') . (!empty($options['preferences']) ? ',
lngfile, mod_prefs, notify_types, signature' : '') . '
FROM {db_prefix}members
WHERE id_member IN ({array_int:member_list})
Expand Down
4 changes: 2 additions & 2 deletions sources/subs/NotificationsTask.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @copyright ElkArte Forum contributors
* @license BSD http://opensource.org/licenses/BSD-3-Clause
*
* @version 1.1
* @version 1.1.7
*
*/

Expand Down Expand Up @@ -96,7 +96,7 @@ public function getMembersData()
if ($this->_members_data === null)
{
require_once(SUBSDIR . '/Members.subs.php');
$this->_members_data = getBasicMemberData($this->getMembers(), array('preferences' => true));
$this->_members_data = getBasicMemberData($this->getMembers(), array('preferences' => true, 'authentication' => true));
}

return $this->_members_data;
Expand Down

0 comments on commit 6cc585c

Please sign in to comment.