def test_announcement_news(self):
        actions.login('*****@*****.**')
        actions.register(self, 'John Doe')
        time.sleep(1)
        locale = 'de'
        announcement = self._add_announcement_and_translation(
            locale, is_draft=True)
        sent_data = {
            'key': str(announcement.key()),
            'title': 'Test Announcement',
            'date': utc.to_text(seconds=utc.now_as_timestamp()),
            'is_draft': False,
        }
        actions.login(self.ADMIN_EMAIL)
        response = self._put_announcement(sent_data)
        actions.login('*****@*****.**')

        # Verify announcement news item using news API directly
        news_items = news.CourseNewsDao.get_news_items()
        self.assertEquals(1, len(news_items))
        item = news_items[0]
        now_timestamp = utc.now_as_timestamp()
        self.assertEquals(
            announcements.AnnouncementsStudentHandler.URL.lstrip('/'), item.url)
        self.assertEquals(
            str(announcements.TranslatableResourceAnnouncement.key_for_entity(
                announcement)),
            item.resource_key)
        self.assertAlmostEqual(
            now_timestamp, utc.datetime_to_timestamp(item.when), delta=10)

        # Verify announcement news item looking at HTTP response to /course
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem(
                'Test Announcement',
                announcements.AnnouncementsStudentHandler.URL.lstrip('/'),
                True)],
            news_tests_lib.extract_news_items_from_soup(soup))

        # Verify announcement news item translated title.
        self._set_prefs_locale(locale)
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem(
                'TEST ANNOUNCEMENT',
                announcements.AnnouncementsStudentHandler.URL.lstrip('/'),
                True)],
            news_tests_lib.extract_news_items_from_soup(soup))

        # Delete the announcement; news item should also go away.
        actions.login(self.ADMIN_EMAIL)
        self._delete_announcement(str(announcement.key()))
        actions.login('*****@*****.**')
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals([], news_tests_lib.extract_news_items_from_soup(soup))
    def test_news_label_filtering(self):
        actions.login(self.STUDENT_EMAIL)
        actions.register(self, 'John Smith')

        label_foo = models.LabelDAO.save(models.LabelDTO(
            None, {'title': 'Foo',
                   'descripton': 'foo',
                   'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK}))
        label_bar = models.LabelDAO.save(models.LabelDTO(
            None, {'title': 'Bar',
                   'descripton': 'bar',
                   'type': models.LabelDTO.LABEL_TYPE_COURSE_TRACK}))

        now_ts = utc.now_as_timestamp() + 3  # Avoid filtering in-past items
        news.CourseNewsDao.add_news_item(news.NewsItem(
            'test:no_labels', 'url_no_labels',
            when=utc.timestamp_to_datetime(now_ts)))
        news.CourseNewsDao.add_news_item(news.NewsItem(
            'test:with_labels', 'url_with_labels',
            labels=common_utils.list_to_text([label_foo]),
            when=utc.timestamp_to_datetime(now_ts - 1)))

        # Student starts life with no labels, so should match both items.
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem(
                'Test Item no_labels', 'url_no_labels', True),
             news_tests_lib.NewsItem(
                 'Test Item with_labels', 'url_with_labels', True)],
            news_tests_lib.extract_news_items_from_soup(soup))

        # Apply non-matching label to Student; should not see labeled news.
        models.Student.set_labels_for_current(
            common_utils.list_to_text([label_bar]))
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem(
                'Test Item no_labels', 'url_no_labels', True)],
            news_tests_lib.extract_news_items_from_soup(soup))

        # Apply matching label to Student; should again see labeled news.
        models.Student.set_labels_for_current(
            common_utils.list_to_text([label_foo, label_bar]))
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem(
                'Test Item no_labels', 'url_no_labels', True),
             news_tests_lib.NewsItem(
                 'Test Item with_labels', 'url_with_labels', True)],
            news_tests_lib.extract_news_items_from_soup(soup))
    def test_get_news_some_old_some_new(self):
        user = actions.login(self.STUDENT_EMAIL)
        actions.register(self, 'John Smith')

        # Newsworthy thing happened beyond newsworthy time limit,
        then_ts = utc.now_as_timestamp() - news.NEWSWORTHINESS_SECONDS - 1
        then = utc.timestamp_to_datetime(then_ts)
        self._set_student_enroll_date(user, then)
        news_item = news.NewsItem('test:one', 'url_one', then)
        news.CourseNewsDao.add_news_item(news_item)
        news_item = news.NewsItem('test:two', 'url_two', then)
        news.CourseNewsDao.add_news_item(news_item)
        # But student has seen the thing, so it's marked as non-new.
        news.StudentNewsDao.mark_item_seen('test:one')

        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(['has_new_news'],
                          self._get_news_title_styles(soup))
        self.assertEquals(
            [
                news_tests_lib.NewsItem('Test Item two', 'url_two', True),
                news_tests_lib.NewsItem('Test Item one', 'url_one', False),
            ],
            news_tests_lib.extract_news_items_from_soup(soup))
Пример #4
0
    def test_news_notification(self):
        assessment = self.course.add_assessment()
        assessment.title = 'Assessment'
        assessment.html_content = 'assessment content'
        assessment.availability = courses.AVAILABILITY_AVAILABLE
        self.course.save()
        self.certificate_criteria.append(
            {'assessment_id': assessment.unit_id, 'pass_percent': 70.0})
        actions.submit_assessment(
            self, assessment.unit_id,
            {'answers': '', 'score': 70, 'assessment_type': assessment.unit_id},
            presubmit_checks=False)

        news_items = news.StudentNewsDao.get_news_items()
        self.assertEquals(1, len(news_items))
        item = news_items[0]
        now_ts = utc.now_as_timestamp()
        self.assertEquals(certificate.CERTIFICATE_HANDLER_PATH, item.url)
        self.assertEquals(certificate.RESOURCE_KEY, item.resource_key)
        self.assertAlmostEqual(
            now_ts, utc.datetime_to_timestamp(item.when), delta=10)

        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem(
                'Course completion certificate earned!',
                certificate.CERTIFICATE_HANDLER_PATH, True)],
            news_tests_lib.extract_news_items_from_soup(soup))
 def test_get_news_no_news(self):
     actions.login(self.STUDENT_EMAIL)
     actions.register(self, 'John Smith')
     response = self.get('course')
     soup = self.parse_html_string_to_soup(response.body)
     self.assertEquals(['has_only_old_news'],
                       self._get_news_title_styles(soup))
     self.assertEquals([], news_tests_lib.extract_news_items_from_soup(soup))
    def test_get_news_unseen(self):
        user = actions.login(self.STUDENT_EMAIL)
        actions.register(self, 'John Smith')

        # Added item is older than newsworthiness cutoff, but student has
        # not been marked as having seen it, so it's new news.
        then_ts = utc.now_as_timestamp() - news.NEWSWORTHINESS_SECONDS - 1
        then = utc.timestamp_to_datetime(then_ts)
        self._set_student_enroll_date(user, then)
        news_item = news.NewsItem('test:key', 'test:url', then)
        news.CourseNewsDao.add_news_item(news_item)

        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(['has_new_news'],
                          self._get_news_title_styles(soup))
        self.assertEquals(
            [news_tests_lib.NewsItem('Test Item key', 'test:url', True)],
            news_tests_lib.extract_news_items_from_soup(soup))
    def test_student_and_course_news(self):
        user = actions.login(self.STUDENT_EMAIL)
        actions.register(self, 'John Smith')

        then_ts = utc.now_as_timestamp() - news.NEWSWORTHINESS_SECONDS - 1
        then = utc.timestamp_to_datetime(then_ts)
        self._set_student_enroll_date(user, then)
        news_item = news.NewsItem('test:one', 'url_one', then)
        news.CourseNewsDao.add_news_item(news_item)
        news_item = news.NewsItem('test:two', 'url_two', then)
        news.StudentNewsDao.add_news_item(news_item)

        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(['has_new_news'],
                          self._get_news_title_styles(soup))
        self.assertEquals(
            [
                news_tests_lib.NewsItem('Test Item two', 'url_two', True),
                news_tests_lib.NewsItem('Test Item one', 'url_one', True),
            ],
            news_tests_lib.extract_news_items_from_soup(soup))
    def test_news_before_user_registration_is_not_news(self):
        news_item = news.NewsItem(
            'test:before', 'before_url', utc.now_as_datetime())
        news.CourseNewsDao.add_news_item(news_item)
        time.sleep(1)
        user = actions.login(self.STUDENT_EMAIL)
        actions.register(self, 'John Smith')
        now = utc.now_as_datetime()
        news_item = news.NewsItem('test:at', 'at_url', now)
        self._set_student_enroll_date(user, now)
        news.CourseNewsDao.add_news_item(news_item)
        time.sleep(1)
        news_item = news.NewsItem(
            'test:after', 'after_url', utc.now_as_datetime())
        news.CourseNewsDao.add_news_item(news_item)

        # Expect to not see news item from before student registration.
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals(
            [news_tests_lib.NewsItem('Test Item after', 'after_url', True),
             news_tests_lib.NewsItem('Test Item at', 'at_url', True)],
            news_tests_lib.extract_news_items_from_soup(soup))
    def test_old_news_excluded_by_new_news(self):
        NUM_OLD_ITEMS = news.MIN_NEWS_ITEMS_TO_DISPLAY * 2
        NUM_NEW_ITEMS = news.MIN_NEWS_ITEMS_TO_DISPLAY * 2

        user = actions.login(self.STUDENT_EMAIL)
        actions.register(self, 'John Smith')
        then_ts = (
            utc.now_as_timestamp() - news.NEWSWORTHINESS_SECONDS -
            NUM_OLD_ITEMS - 1)
        self._set_student_enroll_date(user, utc.timestamp_to_datetime(then_ts))

        # Add many old items - twice as many as we're willing to show.
        expected_old_items = []
        for i in xrange(NUM_OLD_ITEMS):
            expected_old_items.append(news_tests_lib.NewsItem(
                'Test Item %i' % i, 'u%i' % i, False))

            then = utc.timestamp_to_datetime(then_ts + i)
            item = news.NewsItem('test:%d' % i, 'u%d' % i, then)
            news.CourseNewsDao.add_news_item(item)
            news.StudentNewsDao.mark_item_seen('test:%d' % i)

        # Force everything we just did to be old news.
        try:
            save_newsworthiness_seconds = news.NEWSWORTHINESS_SECONDS
            news.NEWSWORTHINESS_SECONDS = 1
            time.sleep(2)

            # Expect that we see old items in newest-first order.
            expected_old_items.reverse()

            # Verify that we are only shown half of the old-news items before
            # we add any new ones.
            response = self.get('course')
            soup = self.parse_html_string_to_soup(response.body)
            self.assertEquals(
                expected_old_items[0:NUM_OLD_ITEMS / 2],
                news_tests_lib.extract_news_items_from_soup(soup))

            # Start adding new news items, one at a time.
            expected_new_items = []
            for i in xrange(NUM_NEW_ITEMS):
                j = NUM_OLD_ITEMS + i
                expected_new_items.append(news_tests_lib.NewsItem(
                    'Test Item %i' % j, 'u%i' % j, True))
                then = utc.timestamp_to_datetime(then_ts + j)
                item = news.NewsItem('test:%d' % j, 'u%d' % j, then)
                news.CourseNewsDao.add_news_item(item)

                # Expect to see all new items, and maybe some old items,
                # as long as the new ones are not crowding them out.
                # New items should appear strictly first.
                expected_items = list(reversed(expected_new_items))
                if i < news.MIN_NEWS_ITEMS_TO_DISPLAY:
                    expected_items += expected_old_items[
                        :news.MIN_NEWS_ITEMS_TO_DISPLAY - i - 1]

                response = self.get('course')
                soup = self.parse_html_string_to_soup(response.body)
                actual_items = news_tests_lib.extract_news_items_from_soup(soup)
                self.assertEquals(expected_items, actual_items)

        finally:
            news.NEWSWORTHINESS_SECONDS = save_newsworthiness_seconds
    def test_announcement_news(self):
        actions.login('*****@*****.**')
        actions.register(self, 'John Doe')
        time.sleep(1)
        locale = 'de'
        announcement = self._add_announcement_and_translation(locale,
                                                              is_draft=True)
        sent_data = {
            'key': str(announcement.key()),
            'title': 'Test Announcement',
            'date': utc.to_text(seconds=utc.now_as_timestamp()),
            'is_draft': False,
        }
        actions.login(self.ADMIN_EMAIL)
        response = self._put_announcement(sent_data)
        actions.login('*****@*****.**')

        # Verify announcement news item using news API directly
        news_items = news.CourseNewsDao.get_news_items()
        self.assertEquals(1, len(news_items))
        item = news_items[0]
        now_timestamp = utc.now_as_timestamp()
        self.assertEquals(
            announcements.AnnouncementsStudentHandler.URL.lstrip('/'),
            item.url)
        self.assertEquals(
            str(
                announcements.TranslatableResourceAnnouncement.key_for_entity(
                    announcement)), item.resource_key)
        self.assertAlmostEqual(now_timestamp,
                               utc.datetime_to_timestamp(item.when),
                               delta=10)

        # Verify announcement news item looking at HTTP response to /course
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals([
            news_tests_lib.NewsItem(
                'Test Announcement',
                announcements.AnnouncementsStudentHandler.URL.lstrip('/'),
                True)
        ], news_tests_lib.extract_news_items_from_soup(soup))

        # Verify announcement news item translated title.
        self._set_prefs_locale(locale)
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals([
            news_tests_lib.NewsItem(
                'TEST ANNOUNCEMENT',
                announcements.AnnouncementsStudentHandler.URL.lstrip('/'),
                True)
        ], news_tests_lib.extract_news_items_from_soup(soup))

        # Delete the announcement; news item should also go away.
        actions.login(self.ADMIN_EMAIL)
        self._delete_announcement(str(announcement.key()))
        actions.login('*****@*****.**')
        response = self.get('course')
        soup = self.parse_html_string_to_soup(response.body)
        self.assertEquals([],
                          news_tests_lib.extract_news_items_from_soup(soup))