def test_bulk_publish_list_exclude(self): """ Make sure we can bulk publish to a number of users passing in a list, and also pass in an exclusion list to make sure the people in the exclude list does not get the notification """ msg = NotificationMessage(namespace='test-runner', msg_type=self.msg_type, payload={'foo': 'bar'}) user_ids = list( range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1)) exclude_user_ids = list( range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1, 2)) # now send to more than our internal chunking size bulk_publish_notification_to_users(user_ids, msg, exclude_user_ids=exclude_user_ids) # now read them all back for user_id in range( 1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1): notifications = get_notifications_for_user(user_id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1 if user_id not in exclude_user_ids else 0) if user_id not in exclude_user_ids: self.assertTrue(isinstance(notifications[0], UserNotification))
def test_bulk_publish_generator(self): """ Make sure we can bulk publish to a number of users passing in a generator function """ msg = NotificationMessage(namespace='test-runner', msg_type=self.msg_type, payload={'foo': 'bar'}) def _user_id_generator(): """ Just spit our an generator that goes from 1 to 100 """ for user_id in range(1, 100): yield user_id # now send to more than our internal chunking size bulk_publish_notification_to_users(_user_id_generator(), msg) # now read them all back for user_id in range(1, 100): notifications = get_notifications_for_user(user_id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1) self.assertTrue(isinstance(notifications[0], UserNotification))
def publish_course_notifications_task(course_id, notification_msg, exclude_user_ids=None): # pylint: disable=invalid-name """ This function will call the edx_notifications api method "bulk_publish_notification_to_users" and run as a new Celery task. """ # get the enrolled and active user_id list for this course. user_ids = CourseEnrollment.objects.values_list('user_id', flat=True).filter( is_active=1, course_id=course_id ) try: bulk_publish_notification_to_users(user_ids, notification_msg, exclude_user_ids=exclude_user_ids) # if we have a course announcement notification publish it to urban airship too if notification_msg.msg_type.name == 'open-edx.studio.announcements.new-announcement': # fetch all active mobile apps to send notifications to all apps mobile_apps = MobileApp.objects.filter(is_active=True) for mobile_app in mobile_apps: channel_context = { "api_credentials": mobile_app.get_api_keys() } preferred_channel = mobile_app.get_notification_provider_name() if preferred_channel: bulk_publish_notification_to_users( user_ids, notification_msg, exclude_user_ids=exclude_user_ids, preferred_channel=preferred_channel, channel_context=channel_context ) except Exception, ex: # Notifications are never critical, so we don't want to disrupt any # other logic processing. So log and continue. log.exception(ex)
def publish_course_notifications_task(course_id, notification_msg, exclude_user_ids=None): # pylint: disable=invalid-name """ This function will call the edx_notifications api method "bulk_publish_notification_to_users" and run as a new Celery task. """ # get the enrolled and active user_id list for this course. user_ids = CourseEnrollment.objects.values_list( 'user_id', flat=True).filter(is_active=1, course_id=course_id) try: bulk_publish_notification_to_users(user_ids, notification_msg, exclude_user_ids=exclude_user_ids) # if we have a course announcement notification publish it to urban airship too if notification_msg.msg_type.name == 'open-edx.studio.announcements.new-announcement': # fetch all active mobile apps to send notifications to all apps mobile_apps = MobileApp.objects.filter(is_active=True) for mobile_app in mobile_apps: channel_context = { "api_credentials": mobile_app.get_api_keys() } preferred_channel = mobile_app.get_notification_provider_name() if preferred_channel: bulk_publish_notification_to_users( user_ids, notification_msg, exclude_user_ids=exclude_user_ids, preferred_channel=preferred_channel, channel_context=channel_context) except Exception as ex: # Notifications are never critical, so we don't want to disrupt any # other logic processing. So log and continue. log.exception(ex)
def test_bulk_publish_generator(self): """ Make sure we can bulk publish to a number of users passing in a generator function """ msg = NotificationMessage(namespace="test-runner", msg_type=self.msg_type, payload={"foo": "bar"}) def _user_id_generator(): """ Just spit our an generator that goes from 1 to 100 """ for user_id in range(1, 100): yield user_id # now send to more than our internal chunking size bulk_publish_notification_to_users(_user_id_generator(), msg) # now read them all back for user_id in range(1, 100): notifications = get_notifications_for_user(user_id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1) self.assertTrue(isinstance(notifications[0], UserNotification))
def test_bulk_publish_list(self): """ Make sure we can bulk publish to a number of users passing in a list """ msg = NotificationMessage( namespace='test-runner', msg_type=self.msg_type, payload={ 'foo': 'bar' } ) # now send to more than our internal chunking size bulk_publish_notification_to_users( list(range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1)), msg ) # now read them all back for user_id in range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1): notifications = get_notifications_for_user(user_id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1) self.assertTrue(isinstance(notifications[0], UserNotification))
def test_bulk_publish_bad_type(self): """ Make sure we have to pass in the right type """ msg = NotificationMessage(namespace="test-runner", msg_type=self.msg_type, payload={"foo": "bar"}) with self.assertRaises(TypeError): bulk_publish_notification_to_users("this should fail", msg)
def test_bulk_publish_bad_type(self): """ Make sure we have to pass in the right type """ msg = NotificationMessage(namespace='test-runner', msg_type=self.msg_type, payload={'foo': 'bar'}) with self.assertRaises(TypeError): bulk_publish_notification_to_users("this should fail", msg)
def test_bulk_user_notification(self, mock_ua_push_api): """ Test publish notification to list of users """ mock_ua_push_api.return_value = {'ok': 'true'} response = bulk_publish_notification_to_users([10, 11, 12], self.msg, preferred_channel='urban-airship') self.assertEqual(response['ok'], 'true')
def _send_to_scoped_users(msg, scope_name, scope_context, preferred_channel=None, channel_context=None): """ Helper method to send to a scoped set of users. scope_context contains all of the information that can be passed into a NotificationScopeResolver """ # user_ids can be a list, a generator function, or a ValuesQuerySet/ValuesListQuerySet (Django ORM) user_ids = resolve_user_scope(scope_name, scope_context) if not user_ids: err_msg = ( 'Could not resolve distribution scope "{name}" with context {context}! ' 'Message id "{_id}" was not sent!').format(name=scope_name, context=scope_context, _id=msg.id) raise Exception(err_msg) # optional parameter to exclude certain # ids exclude_list = scope_context.get('exclude_user_ids') num_dispatched = bulk_publish_notification_to_users( user_ids, msg, exclude_user_ids=exclude_list, preferred_channel=preferred_channel, channel_context=channel_context) return num_dispatched
def publish_mobile_apps_notifications_task(user_ids, notification_msg, api_keys, provider): """ This function will call the edx_notifications api method "bulk_publish_notification_to_users" and run as a new Celery task. """ try: bulk_publish_notification_to_users( user_ids, notification_msg, preferred_channel=provider, channel_context={"api_credentials": api_keys}) except Exception as ex: # Notifications are never critical, so we don't want to disrupt any # other logic processing. So log and continue. log.exception(ex)
def test_bulk_dispatch_notification_count(self): # pylint: disable=invalid-name """ Test bulk dispatch notification using email channel count should be valid """ count = bulk_publish_notification_to_users( [1001, 1002], self.msg, preferred_channel='triggered-email') self.assertEqual(count, 2)
def test_bulk_publish_orm_query(self): """ Make sure we can bulk publish to a number of users passing in a resultset from a Django ORM query """ # set up some test users in Django User's model User(username='******').save() User(username='******').save() User(username='******').save() msg = NotificationMessage(namespace='test-runner', msg_type=self.msg_type, payload={'foo': 'bar'}) resultset = User.objects.values_list('id', flat=True).all() # pylint: disable=no-member num_sent = bulk_publish_notification_to_users(resultset, msg) # make sure we sent 3 self.assertEqual(num_sent, 3) # now read them back for user in User.objects.all(): # pylint: disable=no-member notifications = get_notifications_for_user(user.id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1) self.assertTrue(isinstance(notifications[0], UserNotification))
def _send_to_scoped_users(msg, scope_name, scope_context, preferred_channel=None, channel_context=None): """ Helper method to send to a scoped set of users. scope_context contains all of the information that can be passed into a NotificationScopeResolver """ # user_ids can be a list, a generator function, or a ValuesQuerySet/ValuesListQuerySet (Django ORM) user_ids = resolve_user_scope(scope_name, scope_context) if not user_ids: err_msg = ( 'Could not resolve distribution scope "{name}" with context {context}! ' 'Message id "{_id}" was not sent!' ).format(name=scope_name, context=scope_context, _id=msg.id) raise Exception(err_msg) # optional parameter to exclude certain # ids exclude_list = scope_context.get('exclude_user_ids') num_dispatched = bulk_publish_notification_to_users( user_ids, msg, exclude_user_ids=exclude_list, preferred_channel=preferred_channel, channel_context=channel_context ) return num_dispatched
def test_bulk_publish_orm_query(self): """ Make sure we can bulk publish to a number of users passing in a resultset from a Django ORM query """ # set up some test users in Django User's model User(username="******").save() User(username="******").save() User(username="******").save() msg = NotificationMessage(namespace="test-runner", msg_type=self.msg_type, payload={"foo": "bar"}) resultset = User.objects.values_list("id", flat=True).all() num_sent = bulk_publish_notification_to_users(resultset, msg) # make sure we sent 3 self.assertEqual(num_sent, 3) # now read them back for user in User.objects.all(): notifications = get_notifications_for_user(user.id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1) self.assertTrue(isinstance(notifications[0], UserNotification))
def publish_course_group_notification_task(course_group_id, notification_msg, exclude_user_ids=None): # pylint: disable=invalid-name """ This function will call the edx_notifications api method "bulk_publish_notification_to_users" and run as a new Celery task in order to broadcast a message to an entire course cohort """ # get the enrolled and active user_id list for this course. user_ids = CourseUserGroup.objects.values_list('users', flat=True).filter( id=course_group_id ) try: bulk_publish_notification_to_users(user_ids, notification_msg, exclude_user_ids=exclude_user_ids) except Exception, ex: # pylint: disable=broad-except # Notifications are never critical, so we don't want to disrupt any # other logic processing. So log and continue. log.exception(ex)
def publish_course_group_notification_task(course_group_id, notification_msg, exclude_user_ids=None): # pylint: disable=invalid-name """ This function will call the edx_notifications api method "bulk_publish_notification_to_users" and run as a new Celery task in order to broadcast a message to an entire course cohort """ # get the enrolled and active user_id list for this course. user_ids = CourseUserGroup.objects.values_list('users', flat=True).filter( id=course_group_id ) try: bulk_publish_notification_to_users(user_ids, notification_msg, exclude_user_ids=exclude_user_ids) except Exception as ex: # pylint: disable=broad-except # Notifications are never critical, so we don't want to disrupt any # other logic processing. So log and continue. log.exception(ex)
def test_tag_group_notification(self, mock_ua_push_api): """ Test publish notification to a tag group """ mock_ua_push_api.return_value = {'ok': 'true'} self.msg.payload['open_url'] = 'http://example.com' self.msg.payload['tag_group'] = 'enrollments' response = bulk_publish_notification_to_users([], self.msg, preferred_channel='urban-airship') self.assertTrue(response) self.assertEqual(response['ok'], 'true')
def test_bulk_publish_list(self): """ Make sure we can bulk publish to a number of users passing in a list """ msg = NotificationMessage(namespace="test-runner", msg_type=self.msg_type, payload={"foo": "bar"}) # now send to more than our internal chunking size bulk_publish_notification_to_users( [user_id for user_id in range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1)], msg ) # now read them all back for user_id in range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1): notifications = get_notifications_for_user(user_id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1) self.assertTrue(isinstance(notifications[0], UserNotification))
def test_bulk_publish_list_exclude(self): """ Make sure we can bulk publish to a number of users passing in a list, and also pass in an exclusion list to make sure the people in the exclude list does not get the notification """ msg = NotificationMessage(namespace="test-runner", msg_type=self.msg_type, payload={"foo": "bar"}) user_ids = [user_id for user_id in range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1)] exclude_user_ids = [user_id for user_id in range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1, 2)] # now send to more than our internal chunking size bulk_publish_notification_to_users(user_ids, msg, exclude_user_ids=exclude_user_ids) # now read them all back for user_id in range(1, const.NOTIFICATION_BULK_PUBLISH_CHUNK_SIZE * 2 + 1): notifications = get_notifications_for_user(user_id) self.assertTrue(isinstance(notifications, list)) self.assertEqual(len(notifications), 1 if user_id not in exclude_user_ids else 0) if user_id not in exclude_user_ids: self.assertTrue(isinstance(notifications[0], UserNotification))
def test_bulk_dispatch_notification_count(self): # pylint: disable=invalid-name """ Test bulk dispatch notification using email channel count should be valid """ count = bulk_publish_notification_to_users([1001, 1002], self.msg, preferred_channel="triggered-email") self.assertEqual(count, 2)