Notifications for when someone posted a comment on your node was not created. Root cause was that default values defined in schema was not set, resulting in activity subscriptions not being active. There were 2 bugs preventing them to be set: * The way the caching of markdown as html was implemented caused default values not to be set. * Eve/Cerberus regression causes nested default values to fail https://github.com/pyeve/eve/issues/1174 Also, a 3rd bug caused nodes without a parent not to have a subscription. Migration scripts: How markdown fields is cached has changed, and unused properties of attachments has been removed. ./manage.py maintenance replace_pillar_node_type_schemas Set the default values of activities-subscription ./manage.py maintenance fix_missing_activities_subscription_defaults
194 lines
8.1 KiB
Python
194 lines
8.1 KiB
Python
import bson
|
|
import flask
|
|
from bson import ObjectId
|
|
|
|
from pillar.tests import AbstractPillarTest
|
|
|
|
|
|
class NotificationsTest(AbstractPillarTest):
|
|
def setUp(self, **kwargs):
|
|
super().setUp(**kwargs)
|
|
self.project_id, _ = self.ensure_project_exists()
|
|
self.user1_id = self.create_user(user_id=str(bson.ObjectId()))
|
|
self.user2_id = self.create_user(user_id=str(bson.ObjectId()))
|
|
|
|
def test_create_node(self):
|
|
"""When a node is created, a subscription should also be created"""
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user1_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
|
|
node_id = self.post_node(self.user1_id)
|
|
|
|
self.assertSubscribed(node_id, self.user1_id)
|
|
self.assertNotSubscribed(node_id, self.user2_id)
|
|
|
|
def test_comment_on_own_node(self):
|
|
"""A comment on my own node should not give me any notifications"""
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user1_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
|
|
node_id = self.post_node(self.user1_id)
|
|
comment_id = self.post_comment(node_id)
|
|
|
|
self.assertSubscribed(comment_id, self.user1_id)
|
|
self.assertNotSubscribed(comment_id, self.user2_id)
|
|
|
|
with self.login_as(self.user1_id):
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertIsNone(notification)
|
|
|
|
def test_comment_on_node(self):
|
|
"""A comment on some one else's node should give them a notification, and subscriptions should be created"""
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user1_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
|
|
node_id = self.post_node(self.user1_id)
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user2_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
comment_id = self.post_comment(node_id)
|
|
|
|
self.assertSubscribed(comment_id, self.user2_id)
|
|
self.assertNotSubscribed(comment_id, self.user1_id)
|
|
self.assertSubscribed(node_id, self.user1_id, self.user2_id)
|
|
|
|
with self.login_as(self.user1_id):
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertIsNotNone(notification)
|
|
|
|
def test_mark_notification_as_read(self):
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user1_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
|
|
node_id = self.post_node(self.user1_id)
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user2_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
comment_id = self.post_comment(node_id)
|
|
|
|
with self.login_as(self.user1_id):
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertFalse(notification['is_read'])
|
|
|
|
is_read_toggle_url = flask.url_for('notifications.action_read_toggle', notification_id=notification['_id'])
|
|
self.get(is_read_toggle_url)
|
|
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertTrue(notification['is_read'])
|
|
|
|
self.get(is_read_toggle_url)
|
|
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertFalse(notification['is_read'])
|
|
|
|
def test_unsubscribe(self):
|
|
"""It should be possible to unsubscribe to notifications"""
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user1_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
|
|
node_id = self.post_node(self.user1_id)
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user2_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
comment_id = self.post_comment(node_id)
|
|
|
|
with self.login_as(self.user1_id):
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertTrue(notification['is_subscribed'])
|
|
|
|
is_subscribed_toggle_url =\
|
|
flask.url_for('notifications.action_subscription_toggle', notification_id=notification['_id'])
|
|
self.get(is_subscribed_toggle_url)
|
|
|
|
notification = self.notification_for_object(comment_id)
|
|
self.assertFalse(notification['is_subscribed'])
|
|
|
|
with self.app.app_context():
|
|
self.login_api_as(self.user2_id, roles={'subscriber', 'admin'},
|
|
# This group is hardcoded in the EXAMPLE_PROJECT.
|
|
group_ids=[ObjectId('5596e975ea893b269af85c0e')])
|
|
comment2_id = self.post_comment(node_id)
|
|
|
|
with self.login_as(self.user1_id):
|
|
notification = self.notification_for_object(comment2_id)
|
|
self.assertFalse(notification['is_subscribed'])
|
|
|
|
def assertSubscribed(self, node_id, *user_ids):
|
|
subscriptions_col = self.app.data.driver.db['activities-subscriptions']
|
|
|
|
lookup = {
|
|
'context_object': node_id,
|
|
'notifications.web': True,
|
|
}
|
|
subscriptions = list(subscriptions_col.find(lookup))
|
|
self.assertEquals(len(subscriptions), len(user_ids))
|
|
for s in subscriptions:
|
|
self.assertIn(s['user'], user_ids)
|
|
self.assertEquals(s['context_object_type'], 'node')
|
|
|
|
def assertNotSubscribed(self, node_id, user_id):
|
|
subscriptions_col = self.app.data.driver.db['activities-subscriptions']
|
|
|
|
lookup = {
|
|
'context_object': node_id,
|
|
}
|
|
subscriptions = subscriptions_col.find(lookup)
|
|
for s in subscriptions:
|
|
self.assertNotEquals(s['user'], user_id)
|
|
|
|
def notification_for_object(self, node_id):
|
|
notifications_url = flask.url_for('notifications.index')
|
|
notification_items = self.get(notifications_url).json['items']
|
|
|
|
object_url = flask.url_for('nodes.redirect_to_context', node_id=str(node_id), _external=False)
|
|
for candidate in notification_items:
|
|
if candidate['object_url'] == object_url:
|
|
return candidate
|
|
|
|
def post_node(self, user_id):
|
|
node_doc = {'description': '',
|
|
'project': self.project_id,
|
|
'node_type': 'asset',
|
|
'user': user_id,
|
|
'properties': {'status': 'published',
|
|
'tags': [],
|
|
'order': 0,
|
|
'categories': '',
|
|
},
|
|
'name': 'My first test node'}
|
|
|
|
r, _, _, status = self.app.post_internal('nodes', node_doc)
|
|
self.assertEqual(status, 201, r)
|
|
node_id = r['_id']
|
|
return node_id
|
|
|
|
def post_comment(self, node_id):
|
|
comment_url = flask.url_for('nodes_api.post_node_comment', node_path=str(node_id))
|
|
comment = self.post(
|
|
comment_url,
|
|
json={
|
|
'msg': 'je möder lives at [home](https://cloud.blender.org/)',
|
|
},
|
|
expected_status=201,
|
|
)
|
|
return ObjectId(comment.json['id'])
|