Notifier re-subcribe via link
* fix assertPrefValid in tests to decrypt instead of compare * rename unsubscribe -> set_subscribe
This commit is contained in:
@@ -9,7 +9,7 @@ from django.test.utils import override_settings
|
|||||||
from mock import Mock, patch
|
from mock import Mock, patch
|
||||||
|
|
||||||
from notification_prefs import NOTIFICATION_PREF_KEY
|
from notification_prefs import NOTIFICATION_PREF_KEY
|
||||||
from notification_prefs.views import ajax_enable, ajax_disable, ajax_status, unsubscribe
|
from notification_prefs.views import ajax_enable, ajax_disable, ajax_status, set_subscription, UsernameCipher
|
||||||
from student.tests.factories import UserFactory
|
from student.tests.factories import UserFactory
|
||||||
from user_api.models import UserPreference
|
from user_api.models import UserPreference
|
||||||
from util.testing import UrlResetMixin
|
from util.testing import UrlResetMixin
|
||||||
@@ -51,10 +51,12 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase):
|
|||||||
|
|
||||||
def assertPrefValid(self, user):
|
def assertPrefValid(self, user):
|
||||||
"""Ensure that the correct preference for the user is persisted"""
|
"""Ensure that the correct preference for the user is persisted"""
|
||||||
self.assertEqual(
|
pref = UserPreference.objects.get(user=user, key=NOTIFICATION_PREF_KEY)
|
||||||
UserPreference.objects.get(user=user, key=NOTIFICATION_PREF_KEY).value,
|
self.assertTrue(pref) # check exists and only 1 (.get)
|
||||||
self.tokens[user]
|
# now coerce username to utf-8 encoded str, since we test with non-ascii unicdoe above and
|
||||||
)
|
# the unittest framework has hard time coercing to unicode.
|
||||||
|
# decrypt also can't take a unicode input, so coerce its input to str
|
||||||
|
self.assertEqual(str(user.username.encode('utf-8')), UsernameCipher().decrypt(str(pref.value)))
|
||||||
|
|
||||||
def assertNotPrefExists(self, user):
|
def assertNotPrefExists(self, user):
|
||||||
"""Ensure that the user does not have a persisted preference"""
|
"""Ensure that the user does not have a persisted preference"""
|
||||||
@@ -177,13 +179,13 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase):
|
|||||||
|
|
||||||
def test_unsubscribe_post(self):
|
def test_unsubscribe_post(self):
|
||||||
request = self.request_factory.post("dummy")
|
request = self.request_factory.post("dummy")
|
||||||
response = unsubscribe(request, "dummy")
|
response = set_subscription(request, "dummy", subscribe=False)
|
||||||
self.assertEqual(response.status_code, 405)
|
self.assertEqual(response.status_code, 405)
|
||||||
|
|
||||||
def test_unsubscribe_invalid_token(self):
|
def test_unsubscribe_invalid_token(self):
|
||||||
def test_invalid_token(token, message):
|
def test_invalid_token(token, message):
|
||||||
request = self.request_factory.get("dummy")
|
request = self.request_factory.get("dummy")
|
||||||
self.assertRaisesRegexp(Http404, "^{}$".format(message), unsubscribe, request, token)
|
self.assertRaisesRegexp(Http404, "^{}$".format(message), set_subscription, request, token, False)
|
||||||
|
|
||||||
# Invalid base64 encoding
|
# Invalid base64 encoding
|
||||||
test_invalid_token("ZOMG INVALID BASE64 CHARS!!!", "base64url")
|
test_invalid_token("ZOMG INVALID BASE64 CHARS!!!", "base64url")
|
||||||
@@ -218,7 +220,7 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase):
|
|||||||
def test_user(user):
|
def test_user(user):
|
||||||
request = self.request_factory.get("dummy")
|
request = self.request_factory.get("dummy")
|
||||||
request.user = AnonymousUser()
|
request.user = AnonymousUser()
|
||||||
response = unsubscribe(request, self.tokens[user])
|
response = set_subscription(request, self.tokens[user], subscribe=False)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertNotPrefExists(user)
|
self.assertNotPrefExists(user)
|
||||||
|
|
||||||
@@ -229,8 +231,8 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase):
|
|||||||
self.create_prefs()
|
self.create_prefs()
|
||||||
request = self.request_factory.get("dummy")
|
request = self.request_factory.get("dummy")
|
||||||
request.user = AnonymousUser()
|
request.user = AnonymousUser()
|
||||||
unsubscribe(request, self.tokens[self.user])
|
set_subscription(request, self.tokens[self.user], False)
|
||||||
response = unsubscribe(request, self.tokens[self.user])
|
response = set_subscription(request, self.tokens[self.user], subscribe=False)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertNotPrefExists(self.user)
|
self.assertNotPrefExists(self.user)
|
||||||
|
|
||||||
@@ -240,10 +242,9 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase):
|
|||||||
self.assertFalse(UserPreference.objects.filter(user=user, key=NOTIFICATION_PREF_KEY))
|
self.assertFalse(UserPreference.objects.filter(user=user, key=NOTIFICATION_PREF_KEY))
|
||||||
request = self.request_factory.get("dummy")
|
request = self.request_factory.get("dummy")
|
||||||
request.user = AnonymousUser()
|
request.user = AnonymousUser()
|
||||||
response = unsubscribe(request, self.tokens[user], resubscribe=True)
|
response = set_subscription(request, self.tokens[user], subscribe=True)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
# this new DB entry will have a new value, so can't use assertPrefValid. Just check existence
|
self.assertPrefValid(user)
|
||||||
self.assertTrue(UserPreference.objects.filter(user=user, key=NOTIFICATION_PREF_KEY))
|
|
||||||
|
|
||||||
for user in self.tokens.keys():
|
for user in self.tokens.keys():
|
||||||
test_user(user)
|
test_user(user)
|
||||||
|
|||||||
@@ -153,13 +153,14 @@ def ajax_status(request):
|
|||||||
|
|
||||||
|
|
||||||
@require_GET
|
@require_GET
|
||||||
def unsubscribe(request, token, resubscribe=False): # pylint: disable=unused-argument
|
def set_subscription(request, token, subscribe): # pylint: disable=unused-argument
|
||||||
"""
|
"""
|
||||||
A view that disables or re-enables notifications for a user who may not be authenticated
|
A view that disables or re-enables notifications for a user who may not be authenticated
|
||||||
|
|
||||||
This view is meant to be the target of an unsubscribe link. The request
|
This view is meant to be the target of an unsubscribe link. The request
|
||||||
must be a GET, and the `token` parameter must decrypt to a valid username.
|
must be a GET, and the `token` parameter must decrypt to a valid username.
|
||||||
The resubscribe feature allows "undo" of accidentally clicking on unsubscribe
|
The subscribe flag feature controls whether the view subscribes or unsubscribes the user, with subscribe=True
|
||||||
|
used to "undo" accidentally clicking on the unsubscribe link
|
||||||
|
|
||||||
A 405 will be returned if the request method is not GET. A 404 will be
|
A 405 will be returned if the request method is not GET. A 404 will be
|
||||||
returned if the token parameter does not decrypt to a valid username. On
|
returned if the token parameter does not decrypt to a valid username. On
|
||||||
@@ -175,13 +176,13 @@ def unsubscribe(request, token, resubscribe=False): # pylint: disable=unused-ar
|
|||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
raise Http404("username")
|
raise Http404("username")
|
||||||
|
|
||||||
if not resubscribe:
|
if subscribe:
|
||||||
UserPreference.objects.filter(user=user, key=NOTIFICATION_PREF_KEY).delete()
|
|
||||||
return render_to_response("unsubscribe.html", {'token': token})
|
|
||||||
else:
|
|
||||||
UserPreference.objects.get_or_create(user=user,
|
UserPreference.objects.get_or_create(user=user,
|
||||||
key=NOTIFICATION_PREF_KEY,
|
key=NOTIFICATION_PREF_KEY,
|
||||||
defaults={
|
defaults={
|
||||||
"value": UsernameCipher.encrypt(user.username)
|
"value": UsernameCipher.encrypt(user.username)
|
||||||
})
|
})
|
||||||
return render_to_response("resubscribe.html", {'token': token})
|
return render_to_response("resubscribe.html", {'token': token})
|
||||||
|
else:
|
||||||
|
UserPreference.objects.filter(user=user, key=NOTIFICATION_PREF_KEY).delete()
|
||||||
|
return render_to_response("unsubscribe.html", {'token': token})
|
||||||
|
|||||||
@@ -338,9 +338,10 @@ if settings.COURSEWARE_ENABLED:
|
|||||||
url(r'^notification_prefs/enable/', 'notification_prefs.views.ajax_enable'),
|
url(r'^notification_prefs/enable/', 'notification_prefs.views.ajax_enable'),
|
||||||
url(r'^notification_prefs/disable/', 'notification_prefs.views.ajax_disable'),
|
url(r'^notification_prefs/disable/', 'notification_prefs.views.ajax_disable'),
|
||||||
url(r'^notification_prefs/status/', 'notification_prefs.views.ajax_status'),
|
url(r'^notification_prefs/status/', 'notification_prefs.views.ajax_status'),
|
||||||
url(r'^notification_prefs/unsubscribe/(?P<token>[a-zA-Z0-9-_=]+)/', 'notification_prefs.views.unsubscribe'),
|
url(r'^notification_prefs/unsubscribe/(?P<token>[a-zA-Z0-9-_=]+)/',
|
||||||
|
'notification_prefs.views.set_subscription', {'subscribe': False}, name="unsubscribe_forum_update"),
|
||||||
url(r'^notification_prefs/resubscribe/(?P<token>[a-zA-Z0-9-_=]+)/',
|
url(r'^notification_prefs/resubscribe/(?P<token>[a-zA-Z0-9-_=]+)/',
|
||||||
'notification_prefs.views.unsubscribe', {'resubscribe': True}, name="resubscribe_forum_update"),
|
'notification_prefs.views.set_subscription', {'subscribe': True}, name="resubscribe_forum_update"),
|
||||||
)
|
)
|
||||||
urlpatterns += (
|
urlpatterns += (
|
||||||
# This MUST be the last view in the courseware--it's a catch-all for custom tabs.
|
# This MUST be the last view in the courseware--it's a catch-all for custom tabs.
|
||||||
|
|||||||
Reference in New Issue
Block a user