def unsubscribe(request): token = request.REQUEST.get('token', '') email = request.REQUEST.get('email') unsubscribe_all_link = 'http://{}/unsubscribe?'.format(settings.DOMAIN) + urlencode({ 'action': 'ALL', 'token': util.token(email), 'email': email, }) ctx = { 'token': token, 'email': email, 'unsubscribed': False, 'unsubscribed_on_get': False, 'unsubscribed_settings': None, 'user': None, 'error': False, 'action': request.REQUEST.get('action'), 'unsubscribe_all_link': unsubscribe_all_link, } template_name = 'unsubscribe.html' if email and util.token(email) == token: # No user_id associated with the sent email, unsubscribe this email address from all email find_user = User.objects.filter(email=email) # If there is one and only one user with that email address, then pick them, otherwise we'll fall back to just an email address user = ctx['unsubscribing_user'] = find_user[0] if find_user.count() == 1 else None else: ctx['error'] = True return r2r_jinja(template_name, ctx, request) all_actions = EmailChannel.all_handled_actions() if user: # Support for unsubscribe headers. # We support passing in 'actions' action = request.REQUEST.get('action') if action and (action in EmailChannel.all_handled_actions() or action.upper() == 'ALL'): ctx['unsubscribed_on_get'] = ctx['unsubscribed'] = True user.kv.subscriptions.unsubscribe(action) Metrics.unsubscribe_action.record(request, action=action, method=request.method) if request.method == 'POST': # Handle the 'ALL' case separately because the semantics for it are inverted. # ie, if ALL is checked, it means to DISABLE. While if REMIXED is checked, it means ENABLE. handle_unsubscribe_post(user, request.REQUEST, request) # We use this dictionary to render the checkboxes in the html. ctx['unsubscribed'] = ctx['unsubscribed'] or get_unsubscriptions(user, all_actions) ctx['unsubscribed_settings'] = get_unsubscriptions(user) template_name = 'unsubscribe_for_user.html' else: ctx['error'] = True return r2r_jinja(template_name, ctx, request) return r2r_jinja(template_name, ctx, request)
def make_action_unsubscribe_link(self, action, recipient): if settings.PROJECT == 'drawquest': #TODO individual action unsubscriptions: action instead of 'ALL' return '{}/unsubscribe?action={}&token={}&email={}'.format( "http://" + settings.DOMAIN, 'ALL', util.token(recipient.email), recipient.email) else: return string.Template( "$absolute_path/unsubscribe?action=$action&token=$token&user_id=$user_id" ).substitute( dict(absolute_path="http://" + settings.DOMAIN, action=action, user_id=recipient.id, token=util.token(recipient.id)), )
def test_unsubscribe_page_without_user_id(self): user = create_user() resp = self.get('/unsubscribe?' + urllib.urlencode({ 'token': util.token(user.email), 'email': user.email, })) self.assertNumCssMatches(0, resp, 'input[name="user_id"]')
def make_thread_unsubscribe_link(self, comment, recipient): return string.Template("$absolute_path/unsubscribe?post=$post&token=$token&user_id=$user_id").substitute( dict(absolute_path="http://" + settings.DOMAIN, post=comment.thread.op.id, user_id=recipient.id, token=util.token(recipient.id)), )
def make_thread_unsubscribe_link(self, comment, recipient): return string.Template( "$absolute_path/unsubscribe?post=$post&token=$token&user_id=$user_id" ).substitute( dict(absolute_path="http://" + settings.DOMAIN, post=comment.thread.op.id, user_id=recipient.id, token=util.token(recipient.id)), )
def make_action_unsubscribe_link(self, action, recipient): if settings.PROJECT == "drawquest": # TODO individual action unsubscriptions: action instead of 'ALL' return "http://{}/unsubscribe?".format(settings.DOMAIN) + urlencode( {"action": action, "token": util.token(recipient.email), "email": recipient.email} ) else: return string.Template( "$absolute_path/unsubscribe?action=$action&token=$token&user_id=$user_id" ).substitute( dict( absolute_path="http://" + settings.DOMAIN, action=action, user_id=recipient.id, token=util.token(recipient.id), ) )
def unsubscribe(request): token = request.REQUEST.get('token', '') email = request.REQUEST.get('email') ctx = { 'token': token, 'email': email, 'unsubscribed': False, 'unsubscribed_on_get': False, 'unsubscribed_settings': None, 'user': None, 'error': False, } template_name = 'unsubscribe.html' if email and util.token(email) == token: # No user_id associated with the sent email, unsubscribe this email address from all email find_user = User.objects.filter(email=email) # If there is one and only one user with that email address, then pick them, otherwise we'll fall back to just an email address user = ctx['user'] = find_user[0] if find_user.count() == 1 else None else: ctx['error'] = True return r2r_jinja(template_name, ctx, request) all_actions = EmailChannel.all_handled_actions() if user: # Support for unsubscribe headers. # We support passing in 'actions' action = request.REQUEST.get('action') if action and (action in EmailChannel.all_handled_actions() or action.upper() == 'ALL'): ctx['unsubscribed_on_get'] = ctx['unsubscribed'] = True user.kv.subscriptions.unsubscribe(action) Metrics.unsubscribe_action.record(request, action=action, method=request.method) if request.method == 'POST': # Handle the 'ALL' case separately because the semantics for it are inverted. # ie, if ALL is checked, it means to DISABLE. While if REMIXED is checked, it means ENABLE. handle_unsubscribe_post(user, request.REQUEST, request) # We use this dictionary to render the checkboxes in the html. ctx['unsubscribed'] = ctx['unsubscribed'] or get_unsubscriptions( user, all_actions) ctx['unsubscribed_settings'] = get_unsubscriptions(user) template_name = 'unsubscribe_for_user.html' else: unsubscribe_newsletter(email) ctx['unsubscribed'] = True Metrics.unsubscribe_email_address.record(request) return r2r_jinja(template_name, ctx, request)
def test_email_token_allows_unsubscribe_from_all(self): email = "*****@*****.**" url = "/unsubscribe?" + urllib.urlencode({ 'token': util.token(email), 'email': email, }) self.assertFalse(EmailUnsubscribe.objects.get_or_none(email=email)) self.assertStatus(200, url, user=AnonymousUser()) self.assertTrue(EmailUnsubscribe.objects.get_or_none(email=email))
def test_email_token_that_corresponds_to_user_allows_from_channel(self): user = create_user() url = "/unsubscribe?" + urllib.urlencode({ 'action': 'remixed', 'token': util.token(user.email), 'email': user.email, }) self.assertTrue(user.kv.subscriptions.can_receive('remixed')) self.assertStatus(200, url, user=AnonymousUser()) self.assertFalse(user.kv.subscriptions.can_receive('remixed'))
def test_user_id_token_allows_unsubscribe(self): user = create_user() url = "/unsubscribe?" + urllib.urlencode({ 'action': 'remixed', 'token': util.token(user.id), 'user_id': user.id, }) self.assertTrue(user.kv.subscriptions.can_receive('remixed')) self.assertStatus(200, url, user=AnonymousUser()) self.assertFalse(user.kv.subscriptions.can_receive('remixed'))
def make_action_unsubscribe_link(self, action, recipient): if settings.PROJECT == 'drawquest': #TODO individual action unsubscriptions: action instead of 'ALL' return '{}/unsubscribe?action={}&token={}&email={}'.format("http://" + settings.DOMAIN, 'ALL', util.token(recipient.email), recipient.email) else: return string.Template("$absolute_path/unsubscribe?action=$action&token=$token&user_id=$user_id").substitute( dict(absolute_path="http://" + settings.DOMAIN, action=action, user_id=recipient.id, token=util.token(recipient.id)), )
def test_email_token_that_corresponds_to_user_allows_from_channel(self): user = create_user() url = "/unsubscribe?" + urllib.urlencode( { 'action': 'remixed', 'token': util.token(user.email), 'email': user.email, }) self.assertTrue(user.kv.subscriptions.can_receive('remixed')) self.assertStatus(200, url, user=AnonymousUser()) self.assertFalse(user.kv.subscriptions.can_receive('remixed'))
def unsubscribe(request): token = request.REQUEST.get('token', '') email = request.REQUEST.get('email') user_id = request.REQUEST.get('user_id') token_user = User.objects.get_or_none(id=user_id) if user_id else None unsubscribed = False unsubscribed_on_get = False if user_id and util.token(user_id) == token and token_user: user = token_user elif email and util.token(email) == token: # No user_id associated with the sent email, unsubscribe this email address from all email find_user = User.objects.filter(email=email) # If there is one and only one user with that email address, then pick them, otherwise we'll fall back to just an email address user = find_user[0] if find_user.count() == 1 else None elif request.user.is_authenticated(): # Token mismatch, but we have a logged in user. user = request.user else: error = True return r2r('unsubscribe.django.html', locals()) all_actions = EmailChannel.all_handled_actions() if user: subscriptions = user.kv.subscriptions # We need to handle any posts that are passed in the URL comment_id = request.GET.get('post') if comment_id: try: unsubscribed_post = Comment.objects.get(pk=int(comment_id)) except ObjectDoesNotExist: pass else: user.redis.mute_thread(unsubscribed_post) unsubscribed_from_thread = unsubscribed_on_get = unsubscribed = True Metrics.mute_thread.record(request) # Support for unsubscribe headers. # We support passing in 'actions' action = request.REQUEST.get('action') if action and action in EmailChannel.all_handled_actions(): unsubscribed_on_get = unsubscribed = True user.kv.subscriptions.unsubscribe(action) Metrics.unsubscribe_action.record(request, action=action, method=request.method) if request.method == 'POST': # Handle the 'ALL' case separately because the semantics for it are inverted. # ie, if ALL is checked, it means to DISABLE. While if REMIXED is checked, it means ENABLE. handle_unsubscribe_post(user, request.REQUEST, request) # We use this dictionary to render the checkboxes in the html. unsubscribed = unsubscribed or get_unsubscriptions(user, all_actions) unsubscribed_settings = get_unsubscriptions(user) else: unsubscribe_newsletter(email) unsubscribed = True Metrics.unsubscribe_email_address.record(request) return r2r('unsubscribe.django.html', locals())