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))
def should_start_jobs(): now_timestamp = utc.hour_start(utc.now_as_timestamp()) status = StartAvailabilityJobsStatus.get_singleton() last_run = utc.hour_start( utc.datetime_to_timestamp(status.last_run)) if now_timestamp > last_run: status.last_run = utc.timestamp_to_datetime(now_timestamp) StartAvailabilityJobsStatus.update_singleton(status) return True return False
def get_course_enrolled(enrolled_dto, course_name): if enrolled_dto.is_empty: # 'count' property is not present, so exit early. return CourseEnrolled(0, NONE_ENROLLED, _NONE_RECENT_FMT.format(course_name)) count = enrolled_dto.get() lm_dt = utc.timestamp_to_datetime(enrolled_dto.last_modified) lm_text = utc.to_text(dt=lm_dt, fmt=utc.ISO_8601_UTC_HUMAN_FMT) most_recent_enroll = _MOST_RECENT_FMT.format(lm_text, course_name) return CourseEnrolled(count, count, most_recent_enroll)
def get_course_enrolled(enrolled_dto, course_name): if enrolled_dto.is_empty: # 'count' property is not present, so exit early. return CourseEnrolled( 0, NONE_ENROLLED, _NONE_RECENT_FMT.format(course_name)) count = enrolled_dto.get() lm_dt = utc.timestamp_to_datetime(enrolled_dto.last_modified) lm_text = utc.to_text(dt=lm_dt, fmt=utc.ISO_8601_UTC_HUMAN_FMT) most_recent_enroll = _MOST_RECENT_FMT.format(lm_text, course_name) return CourseEnrolled(count, count, most_recent_enroll)
def _test_add_newer_and_older_news_item(self, dao_class): now_ts = utc.now_as_timestamp() older = news.NewsItem('test:key', 'test:url', when=utc.timestamp_to_datetime(now_ts)) newer = news.NewsItem('test:key', 'test:url', when=utc.timestamp_to_datetime(now_ts + 1)) dao_class.add_news_item(older) self.assertEquals([older], dao_class.get_news_items()) # Newer items added with no-overwrite flag do not displace older item. dao_class.add_news_item(newer, overwrite_existing=False) self.assertEquals([older], dao_class.get_news_items()) # Newer items displace older items with the same key. dao_class.add_news_item(newer) self.assertEquals([newer], dao_class.get_news_items()) # But older items w/ same key do not displace newer ones. dao_class.add_news_item(older) self.assertEquals([newer], dao_class.get_news_items())
def reduce(cls, key, values): total = sum(int(value) for value in values) ns_name = namespace_manager.get_namespace() if key == TotalEnrollmentEntity.COUNTING: TotalEnrollmentDAO.set(ns_name, total) yield key, total else: # key is actually a daily 'adds' counter bin seconds since epoch. bin_seconds_since_epoch = long(key) today = utc.day_start(utc.now_as_timestamp()) # Avoid race conditions by not updating today's daily bin (which # is being updated by student lifecycle events). if bin_seconds_since_epoch != today: date_time = utc.timestamp_to_datetime(bin_seconds_since_epoch) EnrollmentsAddedDAO.set(ns_name, date_time, total)
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_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 get(self): eta_timestamp = utc.hour_end(utc.now_as_timestamp()) + 1 eta = utc.timestamp_to_datetime(eta_timestamp) deferred.defer(self.maybe_start_jobs, _eta=eta) logging.info( 'StartAvailabilityJobs - scheduling deferred task at %s', eta)
def get(self): eta_timestamp = utc.hour_end(utc.now_as_timestamp()) + 1 eta = utc.timestamp_to_datetime(eta_timestamp) deferred.defer(self.maybe_start_jobs, _eta=eta) logging.info('StartAvailabilityJobs - scheduling deferred task at %s', eta)