Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
d9f98b84
Commit
d9f98b84
authored
Jan 23, 2014
by
Jason Bau
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2226 from edx/jbau/resubscribe-notifer
resubscribe feature for notifier
parents
5bacfcc3
dfacbbdd
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
84 additions
and
21 deletions
+84
-21
lms/djangoapps/notification_prefs/tests.py
+29
-11
lms/djangoapps/notification_prefs/views.py
+14
-5
lms/templates/resubscribe.html
+24
-0
lms/templates/unsubscribe.html
+13
-4
lms/urls.py
+4
-1
No files found.
lms/djangoapps/notification_prefs/tests.py
View file @
d9f98b84
...
...
@@ -9,13 +9,14 @@ from django.test.utils import override_settings
from
mock
import
Mock
,
patch
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
user_api.models
import
UserPreference
from
util.testing
import
UrlResetMixin
@override_settings
(
SECRET_KEY
=
"test secret key"
)
class
NotificationPrefViewTest
(
TestCase
):
class
NotificationPrefViewTest
(
UrlResetMixin
,
TestCase
):
INITIALIZATION_VECTOR
=
"
\x00
"
*
16
@classmethod
...
...
@@ -23,7 +24,9 @@ class NotificationPrefViewTest(TestCase):
# Make sure global state is set up appropriately
Client
()
.
get
(
"/"
)
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
):
super
(
NotificationPrefViewTest
,
self
)
.
setUp
()
self
.
user
=
UserFactory
.
create
(
username
=
"testuser"
)
# Tokens are intentionally hard-coded instead of computed to help us
# avoid breaking existing links.
...
...
@@ -48,10 +51,12 @@ class NotificationPrefViewTest(TestCase):
def
assertPrefValid
(
self
,
user
):
"""Ensure that the correct preference for the user is persisted"""
self
.
assertEqual
(
UserPreference
.
objects
.
get
(
user
=
user
,
key
=
NOTIFICATION_PREF_KEY
)
.
value
,
self
.
tokens
[
user
]
)
pref
=
UserPreference
.
objects
.
get
(
user
=
user
,
key
=
NOTIFICATION_PREF_KEY
)
self
.
assertTrue
(
pref
)
# check exists and only 1 (.get)
# 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
):
"""Ensure that the user does not have a persisted preference"""
...
...
@@ -174,13 +179,13 @@ class NotificationPrefViewTest(TestCase):
def
test_unsubscribe_post
(
self
):
request
=
self
.
request_factory
.
post
(
"dummy"
)
response
=
unsubscribe
(
request
,
"dummy"
)
response
=
set_subscription
(
request
,
"dummy"
,
subscribe
=
False
)
self
.
assertEqual
(
response
.
status_code
,
405
)
def
test_unsubscribe_invalid_token
(
self
):
def
test_invalid_token
(
token
,
message
):
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
test_invalid_token
(
"ZOMG INVALID BASE64 CHARS!!!"
,
"base64url"
)
...
...
@@ -215,7 +220,7 @@ class NotificationPrefViewTest(TestCase):
def
test_user
(
user
):
request
=
self
.
request_factory
.
get
(
"dummy"
)
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
.
assertNotPrefExists
(
user
)
...
...
@@ -226,7 +231,20 @@ class NotificationPrefViewTest(TestCase):
self
.
create_prefs
()
request
=
self
.
request_factory
.
get
(
"dummy"
)
request
.
user
=
AnonymousUser
()
unsubscribe
(
request
,
self
.
tokens
[
self
.
user
]
)
response
=
unsubscribe
(
request
,
self
.
tokens
[
self
.
user
]
)
set_subscription
(
request
,
self
.
tokens
[
self
.
user
],
False
)
response
=
set_subscription
(
request
,
self
.
tokens
[
self
.
user
],
subscribe
=
False
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertNotPrefExists
(
self
.
user
)
def
test_resubscribe_success
(
self
):
def
test_user
(
user
):
# start without a pref key
self
.
assertFalse
(
UserPreference
.
objects
.
filter
(
user
=
user
,
key
=
NOTIFICATION_PREF_KEY
))
request
=
self
.
request_factory
.
get
(
"dummy"
)
request
.
user
=
AnonymousUser
()
response
=
set_subscription
(
request
,
self
.
tokens
[
user
],
subscribe
=
True
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertPrefValid
(
user
)
for
user
in
self
.
tokens
.
keys
():
test_user
(
user
)
lms/djangoapps/notification_prefs/views.py
View file @
d9f98b84
...
...
@@ -153,12 +153,14 @@ def ajax_status(request):
@require_GET
def
unsubscribe
(
request
,
token
):
def
set_subscription
(
request
,
token
,
subscribe
):
# pylint: disable=unused-argument
"""
A view that disables 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
must be a GET, and the `token` parameter must decrypt to a valid username.
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
returned if the token parameter does not decrypt to a valid username. On
...
...
@@ -174,6 +176,13 @@ def unsubscribe(request, token):
except
User
.
DoesNotExist
:
raise
Http404
(
"username"
)
UserPreference
.
objects
.
filter
(
user
=
user
,
key
=
NOTIFICATION_PREF_KEY
)
.
delete
()
return
render_to_response
(
"unsubscribe.html"
,
{})
if
subscribe
:
UserPreference
.
objects
.
get_or_create
(
user
=
user
,
key
=
NOTIFICATION_PREF_KEY
,
defaults
=
{
"value"
:
UsernameCipher
.
encrypt
(
user
.
username
)
})
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
})
lms/templates/resubscribe.html
0 → 100644
View file @
d9f98b84
<
%!
from
django
.
core
.
urlresolvers
import
reverse
from
django
.
utils
.
translation
import
ugettext
as
_
from
django
.
conf
import
settings
%
>
<
%
inherit
file=
"main.html"
/>
<
%
namespace
name=
'static'
file=
'static_content.html'
/>
<section
class=
"container unsubscribe"
>
<section
class=
"message"
>
<h1>
${_("Re-subscribe Successful!")}
</h1>
<hr
class=
"horizontal-divider"
>
<p>
${_("You have re-enabled forum notification emails from {platform_name}. "
"Click {dashboard_link_start}here{link_end} to return to your dashboard. ").format(
platform_name=settings.PLATFORM_NAME,
dashboard_link_start="
<a
href=
'{}'
>
".format(reverse('dashboard')),
link_end="
</a>
",)}
</p>
</section>
</section>
lms/templates/unsubscribe.html
View file @
d9f98b84
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
django
.
core
.
urlresolvers
import
reverse
from
django
.
utils
.
translation
import
ugettext
as
_
from
django
.
conf
import
settings
%
>
<
%
inherit
file=
"main.html"
/>
<
%
namespace
name=
'static'
file=
'static_content.html'
/>
...
...
@@ -6,12 +10,17 @@
<section
class=
"container unsubscribe"
>
<section
class=
"message"
>
<h1>
Unsubscribe Successful!
</h1>
<h1>
${_("Unsubscribe Successful!")}
</h1>
<hr
class=
"horizontal-divider"
>
<p>
You will no longer receive notification emails from edX.
Click
<a
href=
"${reverse('dashboard')}"
>
here
</a>
to return to your dashboard.
${_("You will no longer receive forum notification emails from {platform_name}. "
"Click {dashboard_link_start}here{link_end} to return to your dashboard. "
"If you did not mean to do this, click {undo_link_start}here{link_end} to re-subscribe.").format(
platform_name=settings.PLATFORM_NAME,
dashboard_link_start="
<a
href=
'{}'
>
".format(reverse('dashboard')),
undo_link_start="
<a
id=
'resub_link'
href=
'{}'
>
".format(reverse('resubscribe_forum_update', args=[token])),
link_end="
</a>
",)}
</p>
</section>
</section>
lms/urls.py
View file @
d9f98b84
...
...
@@ -338,7 +338,10 @@ if settings.COURSEWARE_ENABLED:
url
(
r'^notification_prefs/enable/'
,
'notification_prefs.views.ajax_enable'
),
url
(
r'^notification_prefs/disable/'
,
'notification_prefs.views.ajax_disable'
),
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-_=]+)/'
,
'notification_prefs.views.set_subscription'
,
{
'subscribe'
:
True
},
name
=
"resubscribe_forum_update"
),
)
urlpatterns
+=
(
# This MUST be the last view in the courseware--it's a catch-all for custom tabs.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment