Update version for release.
[mediagoblin.git] / mediagoblin / tests / test_notifications.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import pytest
18
19 import six.moves.urllib.parse as urlparse
20
21 from mediagoblin.tools import template, mail
22
23 from mediagoblin.db.models import Notification, CommentSubscription
24 from mediagoblin.db.base import Session
25
26 from mediagoblin.notifications import mark_comment_notification_seen
27
28 from mediagoblin.tests.tools import fixture_add_comment, \
29 fixture_media_entry, fixture_add_user, \
30 fixture_comment_subscription
31
32
33 class TestNotifications:
34 @pytest.fixture(autouse=True)
35 def setup(self, test_app):
36 self.test_app = test_app
37
38 # TODO: Possibly abstract into a decorator like:
39 # @as_authenticated_user('chris')
40 self.test_user = fixture_add_user(privileges=[u'active',u'commenter'])
41
42 self.current_user = None
43
44 self.login()
45
46 def login(self, username=u'chris', password=u'toast'):
47 response = self.test_app.post(
48 '/auth/login/', {
49 'username': username,
50 'password': password})
51
52 response.follow()
53
54 assert urlparse.urlsplit(response.location)[2] == '/'
55 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
56
57 ctx = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
58
59 assert Session.merge(ctx['request'].user).username == username
60
61 self.current_user = ctx['request'].user
62
63 def logout(self):
64 self.test_app.get('/auth/logout/')
65 self.current_user = None
66
67 @pytest.mark.parametrize('wants_email', [True, False])
68 def test_comment_notification(self, wants_email):
69 '''
70 Test
71 - if a notification is created when posting a comment on
72 another users media entry.
73 - that the comment data is consistent and exists.
74
75 '''
76 user = fixture_add_user('otherperson', password='nosreprehto',
77 wants_comment_notification=wants_email,
78 privileges=[u'active',u'commenter'])
79
80 assert user.wants_comment_notification == wants_email
81
82 user_id = user.id
83
84 media_entry = fixture_media_entry(uploader=user.id, state=u'processed')
85
86 media_entry_id = media_entry.id
87
88 subscription = fixture_comment_subscription(media_entry)
89
90 subscription_id = subscription.id
91
92 media_uri_id = '/u/{0}/m/{1}/'.format(user.username,
93 media_entry.id)
94 media_uri_slug = '/u/{0}/m/{1}/'.format(user.username,
95 media_entry.slug)
96
97 self.test_app.post(
98 media_uri_id + 'comment/add/',
99 {
100 'comment_content': u'Test comment #42'
101 }
102 )
103
104 notifications = Notification.query.filter_by(
105 user_id=user.id).all()
106
107 assert len(notifications) == 1
108
109 notification = notifications[0]
110
111 assert notification.seen == False
112 assert notification.user_id == user.id
113 assert notification.obj().comment().get_actor.id == self.test_user.id
114 assert notification.obj().comment().content == u'Test comment #42'
115
116 if wants_email == True:
117 # Why the `or' here? In Werkzeug 0.11.0 and above
118 # werkzeug stopped showing the port for localhost when
119 # rendering something like this. As long as we're
120 # supporting pre-0.11.0 we'll keep this `or', but maybe
121 # in the future we can kill it.
122 assert (
123 mail.EMAIL_TEST_MBOX_INBOX == [
124 {'from': 'notice@mediagoblin.example.org',
125 'message': 'Content-Type: text/plain; \
126 charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: \
127 base64\nSubject: GNU MediaGoblin - chris commented on your \
128 post\nFrom: notice@mediagoblin.example.org\nTo: \
129 otherperson@example.com\n\nSGkgb3RoZXJwZXJzb24sCmNocmlzIGNvbW1lbnRlZCBvbiB5b3VyIHBvc3QgKGh0dHA6Ly9sb2Nh\nbGhvc3Q6ODAvdS9vdGhlcnBlcnNvbi9tL3NvbWUtdGl0bGUvYy8xLyNjb21tZW50KSBhdCBHTlUg\nTWVkaWFHb2JsaW4KClRlc3QgY29tbWVudCAjNDIKCkdOVSBNZWRpYUdvYmxpbg==\n',
130 'to': [u'otherperson@example.com']}]
131 or mail.EMAIL_TEST_MBOX_INBOX == [
132 {'from': 'notice@mediagoblin.example.org',
133 'message': 'Content-Type: text/plain; \
134 charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: \
135 base64\nSubject: GNU MediaGoblin - chris commented on your \
136 post\nFrom: notice@mediagoblin.example.org\nTo: \
137 otherperson@example.com\n\nSGkgb3RoZXJwZXJzb24sCmNocmlzIGNvbW1lbnRlZCBvbiB5b3VyIHBvc3QgKGh0dHA6Ly9sb2Nh\nbGhvc3QvdS9vdGhlcnBlcnNvbi9tL3NvbWUtdGl0bGUvYy8xLyNjb21tZW50KSBhdCBHTlUgTWVk\naWFHb2JsaW4KClRlc3QgY29tbWVudCAjNDIKCkdOVSBNZWRpYUdvYmxpbg==\n',
138 'to': [u'otherperson@example.com']}])
139 else:
140 assert mail.EMAIL_TEST_MBOX_INBOX == []
141
142
143 # Save the ids temporarily because of DetachedInstanceError
144 notification_id = notification.id
145 comment_id = notification.obj().id
146
147 self.logout()
148 self.login('otherperson', 'nosreprehto')
149
150 self.test_app.get(media_uri_slug + 'c/{0}/'.format(comment_id))
151
152 notification = Notification.query.filter_by(id=notification_id).first()
153
154 assert notification.seen == True
155
156 self.test_app.get(media_uri_slug + 'notifications/silence/')
157
158 subscription = CommentSubscription.query.filter_by(id=subscription_id)\
159 .first()
160
161 assert subscription.notify == False
162
163 notifications = Notification.query.filter_by(
164 user_id=user_id).all()
165
166 # User should not have been notified
167 assert len(notifications) == 1
168
169 def test_mark_all_comment_notifications_seen(self):
170 """ Test that mark_all_comments_seen works"""
171
172 user = fixture_add_user('otherperson', password='nosreprehto',
173 privileges=[u'active'])
174
175 media_entry = fixture_media_entry(uploader=user.id, state=u'processed')
176
177 fixture_comment_subscription(media_entry)
178
179 media_uri_id = '/u/{0}/m/{1}/'.format(user.username,
180 media_entry.id)
181
182 # add 2 comments
183 self.test_app.post(
184 media_uri_id + 'comment/add/',
185 {
186 'comment_content': u'Test comment #43'
187 }
188 )
189
190 self.test_app.post(
191 media_uri_id + 'comment/add/',
192 {
193 'comment_content': u'Test comment #44'
194 }
195 )
196
197 notifications = Notification.query.filter_by(
198 user_id=user.id).all()
199
200 assert len(notifications) == 2
201
202 # both comments should not be marked seen
203 assert notifications[0].seen == False
204 assert notifications[1].seen == False
205
206 # login with other user to mark notifications seen
207 self.logout()
208 self.login('otherperson', 'nosreprehto')
209
210 # mark all comment notifications seen
211 res = self.test_app.get('/notifications/comments/mark_all_seen/')
212 res.follow()
213
214 assert urlparse.urlsplit(res.location)[2] == '/'
215
216 notifications = Notification.query.filter_by(
217 user_id=user.id).all()
218
219 # both notifications should be marked seen
220 assert notifications[0].seen == True
221 assert notifications[1].seen == True