Exemplo n.º 1
0
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)))
Exemplo n.º 2
0
    def test_wildcard_group_mapping(self):
        """
        Test that adds the default notification type mapping
        """
        msg_type = self.store.save_notification_type(
            NotificationType(
                name='open-edx.lms.discussions.new-discussion-added',
                renderer='open-edx.lms.discussions.new-discussion-added',
            )
        )
        # create cohort notification
        msg = self.store.save_notification_message(
            NotificationMessage(
                msg_type=msg_type,
                namespace='cohort-thread-added',
                payload={'subject': 'foo', 'body': 'bar'},
            )
        )
        publish_notification_to_user(self.test_user_id, msg)

        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'true')

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            3
        )
Exemplo n.º 3
0
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))
        )
Exemplo n.º 4
0
    def test_read_notifications(self):
        """
        Test to make sure that we can generate a notification for read notifications as well
        """

        register_namespace_resolver(TestNamespaceResolver())
        set_user_notification_preference(
            self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
            'true')

        # mark the two test notifications as read
        mark_notification_read(self.test_user_id, self.notification1.id)
        mark_notification_read(self.test_user_id, self.notification2.id)

        # make sure read notifications do not generate digests when we only want unread notifications
        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**',
                unread_only=True), 0)

        # make sure read notifications do generate digests when we want all notifications
        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**',
                unread_only=False), 2)
    def test_bad_resolver(self):
        """
        assert that we get exception when trying to use the bad resolver
        """

        register_namespace_resolver(BadNotificationNamespaceResolver())
        with self.assertRaises(NotImplementedError):
            resolve_namespace('foo')
Exemplo n.º 6
0
    def test_bad_resolver(self):
        """
        assert that we get exception when trying to use the bad resolver
        """

        register_namespace_resolver(BadNotificationNamespaceResolver())
        with self.assertRaises(NotImplementedError):
            resolve_namespace('foo')
Exemplo n.º 7
0
def send_digest(request, digest_email):
    # just send to logged in user
    register_namespace_resolver(TestNotificationNamespaceResolver(request.user.email if not digest_email else digest_email))
    send_notifications_digest(
        datetime.now(pytz.UTC) - timedelta(days=1) if const.NOTIFICATION_DIGEST_SEND_TIMEFILTERED else None,
        datetime.now(pytz.UTC),
        const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
        const.NOTIFICATION_DAILY_DIGEST_SUBJECT,
        const.NOTIFICATION_EMAIL_FROM_ADDRESS
    )
Exemplo n.º 8
0
    def test_user_preference_undefined(self):
        """
        Make sure we don't send a digest if the digest preference name is not found
        """
        register_namespace_resolver(TestNamespaceResolver())

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp, self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 0)
Exemplo n.º 9
0
    def test_no_user_resolver(self):
        """
        Asserts no digests were sent if we don't have a user resolver as part of the namespace
        """

        register_namespace_resolver(TestNamespaceResolverNoUsers())

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp, self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 0)
Exemplo n.º 10
0
    def test_default_namespace_resolver(self):
        """
        Assert no digests were sent if we just use the DefaultNotificationNamespaceResolver
        """

        register_namespace_resolver(DefaultNotificationNamespaceResolver())

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp, self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 0)
Exemplo n.º 11
0
    def test_no_namespace_resolver(self):
        """
        Assert no digests were sent if we don't have
        a namespace resolver
        """

        register_namespace_resolver(None)

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp, self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 0)
Exemplo n.º 12
0
    def test_user_preference_false(self):
        """
        Make sure we don't send a digest to a user that does not want digests
        """
        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(
            self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
            'false')

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp, self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 0)
Exemplo n.º 13
0
    def test_happy_path_weekly(self):
        """
        If all is good and enabled, in this test case, we should get two digests sent, one for each namespace
        """

        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(
            self.test_user_id,
            const.NOTIFICATION_WEEKLY_DIGEST_PREFERENCE_NAME, 'true')

        self.assertEqual(
            send_notifications_digest(
                self.weekly_from_timestamp, self.to_timestamp,
                const.NOTIFICATION_WEEKLY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 2)
Exemplo n.º 14
0
    def test_user_preference_undefined(self):
        """
        Make sure we don't send a digest if the digest preference name is not found
        """
        register_namespace_resolver(TestNamespaceResolver())

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            0
        )
Exemplo n.º 15
0
    def test_default_namespace_resolver(self):
        """
        Assert no digests were sent if we just use the DefaultNotificationNamespaceResolver
        """

        register_namespace_resolver(DefaultNotificationNamespaceResolver())

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            0
        )
Exemplo n.º 16
0
    def test_no_user_resolver(self):
        """
        Asserts no digests were sent if we don't have a user resolver as part of the namespace
        """

        register_namespace_resolver(TestNamespaceResolverNoUsers())

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            0
        )
Exemplo n.º 17
0
    def test_user_preference_false(self):
        """
        Make sure we don't send a digest to a user that does not want digests
        """
        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'false')

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            0
        )
Exemplo n.º 18
0
    def test_no_namespace_resolver(self):
        """
        Assert no digests were sent if we don't have
        a namespace resolver
        """

        register_namespace_resolver(None)

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            0
        )
Exemplo n.º 19
0
    def test_to_not_send_digest(self):
        """
        If there are no unread notifications for the user for given timestamps
        Then don't send digest emails to the user.
        """

        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(
            self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
            'true')

        # there will be no unread notifications to send for the digest.
        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp + datetime.timedelta(days=2),
                self.to_timestamp + datetime.timedelta(days=1),
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 0)
Exemplo n.º 20
0
    def test_happy_path_weekly(self):
        """
        If all is good and enabled, in this test case, we should get two digests sent, one for each namespace
        """

        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(self.test_user_id, const.NOTIFICATION_WEEKLY_DIGEST_PREFERENCE_NAME, 'true')

        self.assertEqual(
            send_notifications_digest(
                self.weekly_from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_WEEKLY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            2
        )
Exemplo n.º 21
0
    def test_default_resolver(self):
        """
        Assert that the default works as expected
        """

        register_namespace_resolver(DefaultNotificationNamespaceResolver())

        namespace = 'foo'
        response = resolve_namespace(namespace)

        self.assertIsNotNone(response)
        self.assertEqual(
            response, {
                'namespace': namespace,
                'display_name': namespace,
                'features': {
                    'digests': False,
                },
                'default_user_resolver': None
            })
Exemplo n.º 22
0
    def test_happy_path_without_styling(self):
        """
        If all is good and enabled, but the css and image are not supplied,
        in this test case, we should still get two digests sent, one for each namespace,
        but the resulting emails would not have any css or images.
        """

        register_namespace_resolver(TestNamespaceResolver())

        const.NOTIFICATION_DIGEST_EMAIL_CSS = 'bad.css.file'
        const.NOTIFICATION_BRANDED_DEFAULT_LOGO = 'bad.image.file'

        set_user_notification_preference(
            self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
            'true')

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp, self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'subject',
                '*****@*****.**'), 2)
Exemplo n.º 23
0
    def test_to_not_send_digest(self):
        """
        If there are no unread notifications for the user for given timestamps
        Then don't send digest emails to the user.
        """

        register_namespace_resolver(TestNamespaceResolver())

        set_user_notification_preference(self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'true')

        # there will be no unread notifications to send for the digest.
        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp + datetime.timedelta(days=2),
                self.to_timestamp + datetime.timedelta(days=1),
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            0
        )
Exemplo n.º 24
0
    def test_default_resolver(self):
        """
        Assert that the default works as expected
        """

        register_namespace_resolver(DefaultNotificationNamespaceResolver())

        namespace = 'foo'
        response = resolve_namespace(namespace)

        self.assertIsNotNone(response)
        self.assertEqual(
            response,
            {
                'namespace': namespace,
                'display_name': namespace,
                'features': {
                    'digests': False,
                },
                'default_user_resolver': None
            }
        )
Exemplo n.º 25
0
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)
Exemplo n.º 26
0
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)
Exemplo n.º 27
0
    def test_read_notifications(self):
        """
        Test to make sure that we can generate a notification for read notifications as well
        """

        register_namespace_resolver(TestNamespaceResolver())
        set_user_notification_preference(self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'true')

        # mark the two test notifications as read
        mark_notification_read(self.test_user_id, self.notification1.id)
        mark_notification_read(self.test_user_id, self.notification2.id)

        # make sure read notifications do not generate digests when we only want unread notifications
        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**',
                unread_only=True
            ),
            0
        )

        # make sure read notifications do generate digests when we want all notifications
        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**',
                unread_only=False
            ),
            2
        )
Exemplo n.º 28
0
    def test_happy_path_without_styling(self):
        """
        If all is good and enabled, but the css and image are not supplied,
        in this test case, we should still get two digests sent, one for each namespace,
        but the resulting emails would not have any css or images.
        """

        register_namespace_resolver(TestNamespaceResolver())

        const.NOTIFICATION_DIGEST_EMAIL_CSS = 'bad.css.file'
        const.NOTIFICATION_BRANDED_DEFAULT_LOGO = 'bad.image.file'

        set_user_notification_preference(self.test_user_id, const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME, 'true')

        self.assertEqual(
            send_notifications_digest(
                self.from_timestamp,
                self.to_timestamp,
                const.NOTIFICATION_DAILY_DIGEST_PREFERENCE_NAME,
                'subject',
                '*****@*****.**'
            ),
            2
        )
Exemplo n.º 29
0
 def test_no_resolver(self):
     """
     Assert that None is returned
     """
     register_namespace_resolver(None)
     self.assertIsNone(resolve_namespace('foo'))
Exemplo n.º 30
0
 def test_no_resolver(self):
     """
     Assert that None is returned
     """
     register_namespace_resolver(None)
     self.assertIsNone(resolve_namespace('foo'))