def startup_notification_subsystem(): """ Initialize the Notification subsystem """ try: startup.initialize() # register the scope resolvers that the runtime will be providing # to edx-notifications register_user_scope_resolver('course_enrollments', CourseEnrollmentsScopeResolver()) register_user_scope_resolver('course_group', CourseGroupScopeResolver()) register_user_scope_resolver('group_project_participants', GroupProjectParticipantsScopeResolver()) register_user_scope_resolver('group_project_workgroup', GroupProjectParticipantsScopeResolver()) register_user_scope_resolver('user_email_resolver', StudentEmailScopeResolver()) # register namespace resolver register_namespace_resolver(CourseNamespaceResolver()) except Exception, ex: # Note this will fail when we try to run migrations as manage.py will call startup.py # and startup.initialze() will try to manipulate some database tables. # We need to research how to identify when we are being started up as part of # a migration script log.error( 'There was a problem initializing notifications subsystem. ' 'This could be because the database tables have not yet been created and ' './manage.py lms syncdb needs to run setup.py. Error was "{err_msg}". Continuing...'.format(err_msg=str(ex)) )
def setUp(self): """ start up stuff """ register_user_scope_resolver('list_scope', TestListScopeResolver()) self.store = notification_store() self.msg_type = self.store.save_notification_type( NotificationType( name='foo.bar', renderer='foo', ) ) msg = NotificationMessage( msg_type=self.msg_type, payload={'foo': 'bar'}, ) msg.add_payload( { 'extra': 'stuff' }, channel_name='other_channel' ) self.msg = self.store.save_notification_message(msg)
def test_publish_to_scope(self): """ Make sure we can bulk publish to a number of users passing in a resultset from a Django ORM query """ register_user_scope_resolver("list_scope", TestListScopeResolver()) msg = NotificationMessage(namespace='test-runner', msg_type=self.msg_type, payload={'foo': 'bar'}) bulk_publish_notification_to_scope( scope_name="list_scope", # the TestListScopeResolver expects a "range" property in the context scope_context={"range": 5}, msg=msg) for user_id in range(4): # have to fudge this a bit as the contract on user_id # says > 0 only allowed user_id = user_id + 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 startup_notification_subsystem(): """ Initialize the Notification subsystem """ try: startup.initialize() # register the scope resolvers that the runtime will be providing # to edx-notifications register_user_scope_resolver('course_enrollments', CourseEnrollmentsScopeResolver()) register_user_scope_resolver('course_group', CourseGroupScopeResolver()) register_user_scope_resolver('group_project_participants', GroupProjectParticipantsScopeResolver()) register_user_scope_resolver('group_project_workgroup', GroupProjectParticipantsScopeResolver()) register_user_scope_resolver('user_email_resolver', StudentEmailScopeResolver()) # register namespace resolver register_namespace_resolver(CourseNamespaceResolver()) except Exception, ex: # Note this will fail when we try to run migrations as manage.py will call startup.py # and startup.initialze() will try to manipulate some database tables. # We need to research how to identify when we are being started up as part of # a migration script log.error( 'There was a problem initializing notifications subsystem. ' 'This could be because the database tables have not yet been created and ' './manage.py lms syncdb needs to run setup.py. Error was "{err_msg}". Continuing...' .format(err_msg=str(ex)))
def test_cant_no_scope(self): """ Asserts that if a scope cannot be resolved, then nothing is sent """ self.timer_for_group.context['distribution_scope'][ 'scope_name'] = 'nonexisting' results = self.callback.notification_timer_callback( self.timer_for_group) self.assertIsNotNone(results) self.assertEqual(results['num_dispatched'], 0) self.assertEqual(len(results['errors']), 1) self.assertIsNone(results['reschedule_in_mins']) register_user_scope_resolver('nonexisting', TestListScopeResolver()) results = self.callback.notification_timer_callback( self.timer_for_group) self.assertIsNotNone(results) self.assertEqual(results['num_dispatched'], 0) self.assertEqual(len(results['errors']), 1) self.assertIsNone(results['reschedule_in_mins'])
def test_publish_to_scope(self): """ Make sure we can bulk publish to a number of users passing in a resultset from a Django ORM query """ register_user_scope_resolver("list_scope", TestListScopeResolver()) msg = NotificationMessage(namespace="test-runner", msg_type=self.msg_type, payload={"foo": "bar"}) bulk_publish_notification_to_scope( scope_name="list_scope", # the TestListScopeResolver expects a "range" property in the context scope_context={"range": 5}, msg=msg, ) for user_id in range(4): # have to fudge this a bit as the contract on user_id # says > 0 only allowed user_id = user_id + 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_no_resolution(self): """ Asserts that None is returned if the Resolvers can resolve """ register_user_scope_resolver('none_resolver', TestListScopeResolver()) self.assertIsNone(resolve_user_scope('none_resolver', {}))
def test_bad_return_type(self): """ Asserts that we can't allow for an illegal type to be returned """ register_user_scope_resolver('badtype_scope', TestListScopeResolver()) with self.assertRaises(TypeError): resolve_user_scope('badtype_scope', {})
def test_no_instantiation(self): """ Asserts that NotificationScopeResolver is an abstract base clas """ with self.assertRaises(TypeError): NotificationUserScopeResolver() register_user_scope_resolver('bad_scope', BadTestScopeResolver()) with self.assertRaises(NotImplementedError): resolve_user_scope('bad_scope', {})
def test_no_instantiation(self): """ Asserts that NotificationScopeResolver is an abstract base clas """ with self.assertRaises(TypeError): NotificationUserScopeResolver() # pylint: disable=abstract-class-instantiated register_user_scope_resolver('bad_scope', BadTestScopeResolver()) with self.assertRaises(NotImplementedError): resolve_user_scope('bad_scope', {})
def setUp(self): """ start up stuff """ register_user_scope_resolver('list_scope', TestListScopeResolver()) self.store = notification_store() self.callback = NotificationDispatchMessageCallback() self.msg_type = self.store.save_notification_type( NotificationType( name='foo.bar', renderer='foo', ) ) self.msg = self.store.save_notification_message( NotificationMessage( msg_type=self.msg_type, payload={'foo': 'bar'}, ) ) self.timer_for_user = NotificationCallbackTimer( context={ 'msg_id': self.msg.id, 'distribution_scope': { 'scope_name': 'user', 'scope_context': { 'user_id': 1 } } } ) self.timer_for_group = NotificationCallbackTimer( context={ 'msg_id': self.msg.id, 'distribution_scope': { 'scope_name': 'list_scope', 'scope_context': { 'range': 5 } } } )
def setUp(self): """ start up stuff """ register_user_scope_resolver('list_scope', TestListScopeResolver()) self.store = notification_store() self.callback = NotificationDispatchMessageCallback() self.msg_type = self.store.save_notification_type( NotificationType( name='foo.bar', renderer='foo', )) self.msg = self.store.save_notification_message( NotificationMessage( msg_type=self.msg_type, payload={'foo': 'bar'}, )) self.timer_for_user = NotificationCallbackTimer( context={ 'msg_id': self.msg.id, 'distribution_scope': { 'scope_name': 'user', 'scope_context': { 'user_id': 1 } } }) self.timer_for_group = NotificationCallbackTimer( context={ 'msg_id': self.msg.id, 'distribution_scope': { 'scope_name': 'list_scope', 'scope_context': { 'range': 5 } } })
def setUp(self): clear_user_scope_resolvers() register_user_scope_resolver('list_scope', TestListScopeResolver()) register_user_scope_resolver('generator_scope', TestGeneratorScopeResolver()) register_user_scope_resolver('values_list_query_set', DjangoORMResolver()) register_user_scope_resolver('values_query_set', DjangoORMResolver()) # create a test user in the Django ORM self.test_user = User(username='******', email='*****@*****.**', first_name='Foo', last_name='Bar') self.test_user.is_active = True self.test_user.save()
def setUp(self): """ Test setup """ startup.initialize() register_user_scope_resolver('user_email_resolver', TestUserResolver()) self.store = notification_store() self.msg_type = self.store.get_notification_type(name='open-edx.lms.discussions.reply-to-thread') self.msg = NotificationMessage( namespace='test-runner', msg_type=self.msg_type, payload={ '_schema_version': 1, '_click_link': 'http://localhost', 'original_poster_id': 1, 'action_username': '******', 'thread_title': 'A demo posting to the discussion forums', } )
def setUp(self): """ Test setup """ startup.initialize() register_user_scope_resolver("user_email_resolver", TestUserResolver()) self.store = notification_store() self.msg_type = self.store.get_notification_type(name="open-edx.lms.discussions.reply-to-thread") self.msg = NotificationMessage( namespace="test-runner", msg_type=self.msg_type, payload={ "_schema_version": 1, "_click_link": "http://localhost", "original_poster_id": 1, "action_username": "******", "thread_title": "A demo posting to the discussion forums", }, )
def test_cant_no_scope(self): """ Asserts that if a scope cannot be resolved, then nothing is sent """ self.timer_for_group.context['distribution_scope']['scope_name'] = 'nonexisting' results = self.callback.notification_timer_callback(self.timer_for_group) self.assertIsNotNone(results) self.assertEqual(results['num_dispatched'], 0) self.assertEqual(len(results['errors']), 1) self.assertIsNone(results['reschedule_in_mins']) register_user_scope_resolver('nonexisting', TestListScopeResolver()) results = self.callback.notification_timer_callback(self.timer_for_group) self.assertIsNotNone(results) self.assertEqual(results['num_dispatched'], 0) self.assertEqual(len(results['errors']), 1) self.assertIsNone(results['reschedule_in_mins'])
def initialize(namespace_resolver=None, register_system_types=True): """ Startup entry point for the Notification subsystem """ # alert the application tiers that they should register their # notification types, but this optional (default=True) if register_system_types: perform_type_registrations.send(sender=None) # alert the application tiers that they should register their # notification timers/callbacks perform_timer_registrations.send(sender=None) # install the system-defined Notification Preferences create_default_notification_preferences() register_user_scope_resolver('user', SingleUserScopeResolver(), {}) if not namespace_resolver: namespace_resolver = DefaultNotificationNamespaceResolver() register_namespace_resolver(namespace_resolver, None)
def index(request): """ Returns a basic HTML snippet rendering of a notification count """ global NAMESPACE if request.method == 'POST': register_user_scope_resolver('user_email_resolver', TestUserResolver(request.user)) if request.POST.get('change_namespace'): namespace_str = request.POST['namespace'] NAMESPACE = namespace_str if namespace_str != "None" else None elif request.POST.get('send_digest'): send_digest(request, request.POST.get('digest_email')) else: type_name = request.POST['notification_type'] channel_name = request.POST['notification_channel'] if not channel_name: channel_name = None msg_type = get_notification_type(type_name) msg = NotificationMessage( msg_type=msg_type, namespace=NAMESPACE, payload=CANNED_TEST_PAYLOAD[type_name], ) if type_name == 'testserver.msg-with-resolved-click-link': msg.add_click_link_params({ 'param1': 'param_val1', 'param2': 'param_val2', }) publish_notification_to_user(request.user.id, msg, preferred_channel=channel_name) template = loader.get_template('index.html') # call to the helper method to build up all the context we need # to render the "notification_widget" that is embedded in our # test page context_dict = get_notifications_widget_context({ 'user': request.user, 'notification_types': get_all_notification_types(), 'global_variables': { 'app_name': 'Notification Test Server', 'hide_link_is_visible': settings.HIDE_LINK_IS_VISIBLE, 'always_show_dates_on_unread': True, 'notification_preference_tab_is_visible': settings.NOTIFICATION_PREFERENCES_IS_VISIBLE, }, # for test purposes, set up a short-poll which contacts the server # every 10 seconds to see if there is a new notification # # NOTE: short-poll technique should not be used in a production setting with # any reasonable number of concurrent users. This is just for # testing purposes. # 'refresh_watcher': { 'name': 'short-poll', 'args': { 'poll_period_secs': 10, }, }, 'include_framework_js': True, 'namespace': NAMESPACE, }) return HttpResponse(template.render(RequestContext(request, context_dict)))