示例#1
0
def register_notification_types(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Register some standard NotificationTypes.
    This will be called automatically on the Notification subsystem startup (because we are
    receiving the 'perform_type_registrations' signal)
    """

    register_notification_type(
        NotificationType(
            name=u'open-edx.lms.leaderboard.progress.rank-changed',
            renderer=
            'edx_notifications.openedx.leaderboard.LeaderboardRankChangedRenderer',
        ))

    register_notification_type(
        NotificationType(
            name=u'open-edx.lms.leaderboard.gradebook.rank-changed',
            renderer=
            'edx_notifications.openedx.leaderboard.LeaderboardRankChangedRenderer',
        ))

    register_notification_type(
        NotificationType(
            name=u'open-edx.lms.leaderboard.engagement.rank-changed',
            renderer=
            'edx_notifications.openedx.leaderboard.LeaderboardRankChangedRenderer',
        ))
示例#2
0
    def test_data_object_inequality(self):
        """
        Make sure that we can verify inequality between two objects
        """

        obj1 = DataObjectWithTypedFields(id=1,
                                         test_int_field=100,
                                         test_dict_field={'foo': 'bar'},
                                         test_class_field=NotificationMessage(
                                             msg_type=NotificationType(
                                                 name='testing',
                                                 renderer='foo.renderer',
                                             ),
                                             namespace='namespace',
                                             payload={'field': 'value'}))

        obj2 = DataObjectWithTypedFields(id=1,
                                         test_int_field=100,
                                         test_dict_field={'foo': 'bar'},
                                         test_class_field=NotificationMessage(
                                             msg_type=NotificationType(
                                                 name='something-different',
                                                 renderer='foo.renderer',
                                             ),
                                             namespace='namespace',
                                             payload={'field': 'value'}))

        self.assertNotEqual(obj1, obj2)
def register_notification_types(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Register some standard NotificationTypes.
    This will be called automatically on the Notification subsystem startup (because we are
    receiving the 'perform_type_registrations' signal)
    """
    mapping = {
        NotificationMessageTypes.FILE_UPLOADED: 'GroupProjectFileUploadedRenderer',
        NotificationMessageTypes.STAGE_OPEN: 'GroupProjectStageOpenRenderer',
        NotificationMessageTypes.STAGE_DUE: 'GroupProjectStageDueRenderer',
        NotificationMessageTypes.GRADES_POSTED: 'GroupProjectGradesPostedRenderer',
    }

    for message_type, renderer in six.iteritems(mapping):
        register_notification_type(
            NotificationType(
                name=u"{prefix}.{type}".format(prefix=GROUP_PROJECT_V1_NOTIFICATION_PREFIX, type=message_type),
                renderer="{prefix}.{renderer}".format(prefix=GROUP_PROJECT_RENDERER_PREFIX, renderer=renderer),
            )
        )

        # GP v2 can reuse GP v1 renderers
        register_notification_type(
            NotificationType(
                name=u"{prefix}.{type}".format(prefix=GROUP_PROJECT_V2_NOTIFICATION_PREFIX, type=message_type),
                renderer="{prefix}.{renderer}".format(prefix=GROUP_PROJECT_RENDERER_PREFIX, renderer=renderer),
            )
        )
示例#4
0
    def setUp(self):
        """
        Initialize tests, by creating users and populating some
        unread notifications
        """
        create_default_notification_preferences()
        self.store = notification_store()
        self.test_user_id = 1001
        self.from_timestamp = datetime.datetime.now(
            pytz.UTC) - datetime.timedelta(days=1)
        self.weekly_from_timestamp = datetime.datetime.now(
            pytz.UTC) - datetime.timedelta(days=7)
        self.to_timestamp = datetime.datetime.now(pytz.UTC)

        self.msg_type = self.store.save_notification_type(
            NotificationType(
                name='foo.bar',
                renderer=
                'edx_notifications.renderers.basic.BasicSubjectBodyRenderer',
            ))

        self.msg_type_no_renderer = self.store.save_notification_type(
            NotificationType(
                name='foo.baz',
                renderer='foo',
            ))

        # create two notifications
        with freeze_time(self.to_timestamp):
            msg = self.store.save_notification_message(
                NotificationMessage(
                    msg_type=self.msg_type,
                    namespace='foo',
                    payload={
                        'subject': 'foo',
                        'body': 'bar'
                    },
                ))
            self.notification1 = publish_notification_to_user(
                self.test_user_id, msg)

        with freeze_time(self.to_timestamp):
            msg = self.store.save_notification_message(
                NotificationMessage(
                    msg_type=self.msg_type_no_renderer,
                    namespace='bar',
                    payload={
                        'subject': 'foo',
                        'body': 'bar'
                    },
                ))
            self.notification2 = publish_notification_to_user(
                self.test_user_id, msg)
示例#5
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
        )
示例#6
0
    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)
示例#7
0
    def test_json_renderer(self):
        """
        Make sure JSON renderer returns correct renderings
        """

        msg_type = NotificationType(
            name='open-edx.edx_notifications.lib.tests.test_publisher',
            renderer='edx_notifications.renderers.basic.JsonRenderer',
        )
        register_notification_type(msg_type)

        msg = NotificationMessage(namespace='test-runner',
                                  msg_type=msg_type,
                                  payload={
                                      'subject': 'test subject',
                                      'body': 'test body',
                                  })

        renderer = JsonRenderer()

        self.assertTrue(renderer.can_render_format(RENDER_FORMAT_JSON))
        self.assertIsNone(renderer.get_template_path(RENDER_FORMAT_JSON))
        self.assertEqual(
            json.loads(renderer.render(msg, RENDER_FORMAT_JSON, None)),
            msg.payload)
示例#8
0
    def to_data_object(self, options=None):  # pylint: disable=unused-argument
        """
        Generate a NotificationType data object
        """

        return NotificationType(name=self.name,
                                renderer=self.renderer,
                                renderer_context=DictField.from_json(
                                    self.renderer_context))
示例#9
0
    def restore_object(self, attrs, instance=None):
        """
        Instantiate a new object from the deserialized data
        """

        if instance is not None:
            raise NotImplementedError()

        return NotificationType(**attrs)  # pylint: disable=star-args
示例#10
0
def register_notification_types(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Register some standard NotificationTypes.
    This will be called automatically on the Notification subsystem startup (because we are
    receiving the 'perform_type_registrations' signal)
    """

    # someone replying to thread use-case
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.reply-to-thread',
            renderer='edx_notifications.openedx.forums.ReplyToThreadRenderer',
        ))

    # someone following the thread use-case
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.thread-followed',
            renderer='edx_notifications.openedx.forums.ThreadFollowedRenderer',
        ))

    # new posting in a cohorted/private discussion in the course use-case.
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.cohorted-thread-added',
            renderer=
            'edx_notifications.openedx.forums.CohortedThreadAddedRenderer',
        ))

    # new posting in a cohorted/private discussion in the course use-case.
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.cohorted-comment-added',
            renderer=
            'edx_notifications.openedx.forums.CohortedCommentAddedRenderer',
        ))

    # someone voting the thread use-case
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.post-upvoted',
            renderer='edx_notifications.openedx.forums.PostUpvotedRenderer',
        ))

    # someone voting the comment use-case
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.comment-upvoted',
            renderer='edx_notifications.openedx.forums.CommentUpvotedRenderer',
        ))

    # someone flagging a post use-case
    register_notification_type(
        NotificationType(
            name='open-edx.lms.discussions.post-flagged',
            renderer='edx_notifications.openedx.forums.PostFlaggedRenderer',
        ))
示例#11
0
 def setUp(self):
     """
     Setup the tests values.
     """
     self.provider = SQLNotificationStoreProvider()
     self.test_user_id = 1
     self.notification_type = NotificationType(
         name='foo.bar.baz',
         renderer='foo.renderer',
         renderer_context={'param1': 'value1'},
     )
示例#12
0
def perform_type_registrations_handler(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Register test notification types
    """

    logger.info('Registering NotificationTypes...')

    register_notification_type(
        NotificationType(
            name='testserver.type1',
            renderer='edx_notifications.renderers.basic.BasicSubjectBodyRenderer',
        )
    )

    register_notification_type(
        NotificationType(
            name='testserver.msg-with-resolved-click-link',
            renderer='edx_notifications.renderers.basic.BasicSubjectBodyRenderer',
        )
    )
示例#13
0
    def test_get_provider(self):
        """
        Makes sure we get an instance of the registered store provider
        """

        provider = get_notification_channel(self.test_user_id, self.test_msg_type)

        self.assertIsNotNone(provider)
        self.assertTrue(isinstance(provider, BaseDurableNotificationChannel))

        self.assertEqual(provider.name, 'channel6')
        self.assertEqual(provider.display_name, 'channel_name6')
        self.assertEqual(provider.display_description, 'channel_description6')

        # now verify that the wildcard hierarchy rules
        # work, by making a msg_type name which will match one of
        # the intermediate items in the hierarchy

        provider = get_notification_channel(
            self.test_user_id,
            NotificationType(
                name='edx_notifications.channels.tests.another_one',
                renderer='foo.renderer',
            )
        )

        self.assertEqual(provider.name, 'channel3')
        self.assertEqual(provider.display_name, 'channel_name3')
        self.assertEqual(provider.display_description, 'channel_description3')

        provider = get_notification_channel(
            self.test_user_id,
            NotificationType(
                name='edx_notifications.channels.diff_subpath.diff_leaf',
                renderer='foo.renderer',
            )
        )

        self.assertEqual(provider.name, 'channel2')
        self.assertEqual(provider.display_name, 'channel_name2')
        self.assertEqual(provider.display_description, 'channel_description2')
示例#14
0
    def setUp(self):
        """
        Harnessing
        """
        reset_notification_channels()
        self.test_user_id = 1001  # an arbitrary user_id
        self.test_msg_type = NotificationType(
            name='edx_notifications.channels.tests.test_channel.channeltests.foo',
            renderer='foo.renderer',
        )

        self.addCleanup(reset_notification_channels)
示例#15
0
    def setUp(self):
        """
        Build out test harnessing
        """

        self.msg_type = NotificationType(
            name='open-edx.edx_notifications.lib.tests.test_publisher',
            renderer='edx_notifications.renderers.basic.BasicSubjectBodyRenderer',
        )
        register_notification_type(self.msg_type)

        super(ConsumerAPITests, self).setUp()
示例#16
0
    def setUp(self):
        """
        Initialize some data
        """

        clear_renderers()

        self.test_user_id = 1001  # some bogus user identifier
        self.msg_type = NotificationType(
            name='open-edx.edx_notifications.lib.tests.test_publisher',
            renderer='edx_notifications.renderers.basic.BasicSubjectBodyRenderer',
        )
        register_notification_type(self.msg_type)
示例#17
0
def register_notification_types(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Register some standard NotificationTypes.
    This will be called automatically on the Notification subsystem startup (because we are
    receiving the 'perform_type_registrations' signal)
    """

    register_notification_type(
        NotificationType(
            name='open-edx.mobileapps.notifications',
            renderer=
            'edx_notifications.renderers.basic.JsonRenderer'  # using this for tests to pass.
        ))
示例#18
0
    def _setup_user_notifications(self):
        """
        Helper to build out some
        """

        msg_type = self._save_notification_type()

        # set up some notifications

        msg1 = self.provider.save_notification_message(NotificationMessage(
            namespace='namespace1',
            msg_type=msg_type,
            payload={
                'foo': 'bar',
                'one': 1,
                'none': None,
                'datetime': datetime.utcnow(),
                'iso8601-fakeout': '--T::',  # something to throw off the iso8601 parser heuristic
            }
        ))

        map1 = self.provider.save_user_notification(UserNotification(
            user_id=self.test_user_id,
            msg=msg1
        ))

        msg_type2 = self.provider.save_notification_type(
            NotificationType(
                name='foo.bar.another',
                renderer='foo.renderer',
            )
        )

        msg2 = self.provider.save_notification_message(NotificationMessage(
            namespace='namespace2',
            msg_type=msg_type2,
            payload={
                'foo': 'baz',
                'one': 1,
                'none': None,
                'datetime': datetime.utcnow(),
                'iso8601-fakeout': '--T::',  # something to throw off the iso8601 parser heuristic
            }
        ))

        map2 = self.provider.save_user_notification(UserNotification(
            user_id=self.test_user_id,
            msg=msg2
        ))

        return map1, msg1, map2, msg2
示例#19
0
    def _save_notification_type(self):
        """
        Helper to set up a notification_type
        """

        notification_type = NotificationType(
            name='foo.bar.baz',
            renderer='foo.renderer',
            renderer_context={'param1': 'value1'},
        )

        result = self.provider.save_notification_type(notification_type)

        return result
def register_notification_types(sender, **kwargs):  # pylint: disable=unused-argument
    """
    Register some standard NotificationTypes.
    This will be called automatically on the Notification subsystem startup (because we are
    receiving the 'perform_type_registrations' signal)
    """

    # updates/announcements in the course use-case.
    register_notification_type(
        NotificationType(
            name='open-edx.studio.announcements.new-announcement',
            renderer=
            'edx_notifications.openedx.course_announcements.NewCourseAnnouncementRenderer',
        ))
示例#21
0
 def setUp(self):
     """
     Sets up test environments
     """
     startup.initialize()
     self.msg_type = NotificationType(
         name='open-edx.studio.announcements.new-announcement',
         renderer='edx_notifications.openedx.course_announcements.NewCourseAnnouncementRenderer'
     )
     register_notification_type(self.msg_type)
     self.msg = NotificationMessage(
         namespace='foo/bar/baz',
         msg_type=self.msg_type,
         payload=CANNED_TEST_PAYLOAD['open-edx.studio.announcements.new-announcement']
     )
示例#22
0
    def test_from_data_object(self):
        """
        Make sure we can hydrate a SQLNotificationMessage from a NotificationMessage
        """

        msg_type = NotificationType(
            name='foo.bar.baz',
            renderer='foo.renderer',
        )

        msg = NotificationMessage(id=2, msg_type=msg_type)

        orm_obj = SQLNotificationMessage.from_data_object(msg)

        self.assertEqual(orm_obj.id, msg.id)
示例#23
0
    def test_message_serialization(self):
        """
        Test serialization/deserialization of a sample Notification Message
        """

        msg = NotificationMessage(
            id=1001,
            msg_type=NotificationType(
                name='edx_notifications.sample',
                renderer='foo.renderer',
            ),
            namespace='my-namespace',
            payload={
                'name1': 'val1',
                'name2': datetime.utcnow(),
            },
            deliver_no_earlier_than=datetime.utcnow(),
            created=datetime.utcnow(),
        )

        serializer = NotificationMessageSerializer(msg)
        json = JSONRenderer().render(serializer.data)

        # no deserialize the string and compare resulting objects
        stream = BytesIO(json)
        data = JSONParser().parse(stream)

        deserializer = NotificationMessageSerializer(data=data)
        self.assertTrue(deserializer.is_valid())

        # compare the original data object to our deserialized version
        # and make sure they are the same
        msg_output = deserializer.object
        self.assertEqual(msg, msg_output)
        self.assertEqual(msg.msg_type, msg_output.msg_type)  # pylint: disable=maybe-no-member

        # now intentionally try to break it
        data['namespace'] = 'busted'
        data['msg_type']['name'] = 'not-same'

        deserializer = NotificationMessageSerializer(data=data)
        self.assertTrue(deserializer.is_valid())

        # compare the original data object to our deserialized version
        # and make sure they are not considered the same
        msg_output = deserializer.object
        self.assertNotEqual(msg, msg_output)
        self.assertNotEqual(msg.msg_type, msg_output.msg_type)  # pylint: disable=maybe-no-member
示例#24
0
    def test_underscore(self):
        """
        Tests on the UnderscoreStaticFileRenderer
        """

        renderer = TestUnderscoreStaticFileRenderer(
            'basic_subject_body.underscore')

        self.assertTrue(renderer.can_render_format(RENDER_FORMAT_HTML))

        msg_type = NotificationType(
            name='open-edx.edx_notifications.lib.tests.test_publisher',
            renderer=
            'edx_notifications.renderers.basic.BasicSubjectBodyRenderer',
        )
        register_notification_type(msg_type)

        self.assertIsNotNone(get_renderer_for_type(msg_type))
        msg = NotificationMessage(namespace='test-runner',
                                  msg_type=msg_type,
                                  payload={
                                      'subject': 'test subject',
                                      'body': 'test body',
                                  },
                                  created=datetime.datetime.now(pytz.UTC))

        renderer.get_template_path(RENDER_FORMAT_HTML)

        with self.assertRaises(NotImplementedError):
            renderer.get_template_path(RENDER_FORMAT_SMS)

        with self.assertRaises(NotImplementedError):
            renderer.render(msg, RENDER_FORMAT_SMS, None)

        html = renderer.render(msg, RENDER_FORMAT_HTML, None)

        with self.assertRaises(NotImplementedError):
            renderer.get_template_path(RENDER_FORMAT_SMS)

        self.assertIn('test subject', html)
        self.assertIn('test body', html)
        self.assertIn("<div class='xns-title'>", html)
        self.assertIn("<div class='xns-body'>", html)

        with self.assertRaises(Exception):
            bad_renderer = TestUnderscoreStaticFileRenderer('foo.underscore')
            bad_renderer.render(msg, RENDER_FORMAT_HTML, None)
示例#25
0
    def test_update_notification_type(self):
        """
        Assert that we cannot change a notification type
        """

        notification_type = NotificationType(
            name='foo.bar.baz',
            renderer='foo.renderer',
        )

        with self.assertNumQueries(3):
            self.provider.save_notification_type(notification_type)

        # This should be fine saving again, since nothing is changing

        with self.assertNumQueries(3):
            self.provider.save_notification_type(notification_type)
示例#26
0
    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
                    }
                }
            })
示例#27
0
    def test_null_channel(self):
        """
        Makes sure that the NullNotificationChannel doesn't do anythign what so ever
        """

        test_msg_type = NotificationType(
            name='edx_notifications.channels.tests.test_channel.channeltests.null',
            renderer='foo.renderer',
        )

        provider = get_notification_channel(self.test_user_id, test_msg_type)

        self.assertIsNotNone(provider)
        self.assertTrue(isinstance(provider, NullNotificationChannel))

        self.assertIsNone(provider.dispatch_notification_to_user(None, None))
        self.assertEqual(provider.bulk_dispatch_notification(None, None), 0)

        self.assertIsNone(provider.resolve_msg_link(None, None, None))
示例#28
0
    def setUp(self):
        """
        Test setup
        """

        startup.initialize(register_system_types=False)

        self.msg_type = NotificationType(
            name='open-edx.edx_notifications.lib.tests.test_publisher',
            renderer='edx_notifications.renderers.basic.JsonRenderer',
        )
        register_notification_type(self.msg_type)

        self.msg = NotificationMessage(namespace='test-runner',
                                       msg_type=self.msg_type,
                                       payload={
                                           'foo': 'bar',
                                           'one': 'two'
                                       })
def get_notification_type(message_type):
    return NotificationType(name=message_type,
                            renderer='',
                            renderer_context={})
示例#30
0
    def publish_notification(cls,
                             namespace,
                             msg_type_name,
                             payload,
                             parse_channel_ids,
                             send_at=None,
                             timer_name=None):
        """
        Helper class method to hide some of the inner workings of this channel
        This will work with immediate or timer based publishing.

        'namespace' is an instance of NotificationMessage

        'msg_type' is the type name of the NotificationMessage

        'payload' is the raw data dictionary to send over the mobile clients

        'parse_channel_ids' is a list of Parse channel_ids, which are subscription lists,
        not to be confused with edx-notification's NotificationChannels - an unfortunate
        semantic collision.

        'send_at' is a datetime when this notification should be sent. Note that firing of notifications
        is approximate, so it will not fire BEFORE send_at, but there might be a lag, depending
        on how frequent timer polling is configured in a runtime instance.

        'timer_name' can be used in conjunction with 'send_at'. This is to allow for a fixed
        timer identifier in case the timed notification needs to be updated (or deleted)
        """

        try:
            msg_type = get_notification_type(msg_type_name)
        except ItemNotFoundError:
            msg_type = NotificationType(
                name=msg_type_name,
                renderer='edx_notifications.renderers.basic.JsonRenderer')
            register_notification_type(msg_type)

        msg = NotificationMessage(namespace=namespace,
                                  msg_type=msg_type,
                                  payload=payload)

        if not send_at:
            # send immediately
            publish_notification_to_user(
                user_id=_PARSE_SERVICE_USER_ID,
                msg=msg,
                # we want to make sure we always call this channel provider
                preferred_channel=_PARSE_CHANNEL_NAME,
                channel_context={
                    # tunnel through the parse_channel_id through the
                    # channel context
                    'parse_channel_ids': parse_channel_ids,
                })
        else:
            # time-based sending, use a TimedNotification
            publish_timed_notification(
                msg=msg,
                send_at=send_at,
                scope_name='user',
                scope_context={'user_id': _PARSE_SERVICE_USER_ID},
                timer_name=timer_name,
                timer_context={
                    # we want to make sure we always call this channel provider
                    'preferred_channel': _PARSE_CHANNEL_NAME,
                    'channel_context': {
                        # tunnel through the parse_channel_id through
                        # through the channel context
                        'parse_channel_ids': parse_channel_ids,
                    }
                })