def test_welcome_page(self):
     with actions.OverriddenConfig(sites.GCB_COURSES_CONFIG.name, ''):
         response = self.get('/admin/welcome')
         self.assertEquals(200, response.status_int)
         self.assertIn('Start Using Course Builder', response.body)
         self.assertIn(
             'I agree that Google may collect information about this',
             response.body)
         self.assertIn(
             'name="%s"' %
             course_creation.USAGE_REPORTING_CONSENT_CHECKBOX_NAME,
             response.body)
Ejemplo n.º 2
0
        def add_course_and_register_student(admin_email):
            google_app_context = actions.simple_add_course(
                course_name, admin_email, course_title)
            actions.update_course_config(
                course_name,
                {'course': {'now_available': True, 'browsable': True,},})
            actions.register(self, 'John Smith', course_name)

            with actions.OverriddenConfig(config.REPORT_ALLOWED.name, True):
                usage_reporting.StartReportingJobs._for_testing_only_get()
            self.execute_all_deferred_tasks(
                models.StudentLifecycleObserver.QUEUE_NAME)
            self.execute_all_deferred_tasks()
    def test_announcement_translation_caching(self):
        LOCALE = 'de'
        with actions.OverriddenConfig(models.CAN_USE_MEMCACHE.name, True):
            with actions.OverriddenEnvironment({
                    'i18n': {
                        'course:locale': 'en_US',
                        'extra_locales': [{
                            'locale': LOCALE,
                            'availability': 'true'
                        }]
                    }
            }):

                key = self._add_announcement()
                data = {
                    'key': key,
                    'date': utc.to_text(seconds=0),
                    'html': 'Unsafe for operation',
                    'title': 'Attention',
                    'is_draft': False,
                }
                self._put_announcement(data)
                self._put_translation(data, LOCALE, 'Achtung', 'Gefahrlich!')

                actions.login('*****@*****.**')
                actions.register(self, 'John Doe')
                self._set_prefs_locale(None)
                self._verify_announcements([data['title']], [data['html']])
                self._set_prefs_locale(LOCALE)
                self._verify_announcements(['Achtung'], ['Gefahrlich!'])

                # Verify that we have data added to the cache.
                cached = models.MemcacheManager.get(
                    announcements.AnnouncementEntity._cache_key(LOCALE))
                self.assertIsNotNone(cached)

                # Modify the translated version.
                actions.login(self.ADMIN_EMAIL)
                self._put_translation(data, LOCALE, 'Foo', 'Bar')

                # Verify that the cache has been purged
                cached = models.MemcacheManager.get(
                    announcements.AnnouncementEntity._cache_key(LOCALE))
                self.assertIsNone(cached)

                # And that the changed translations show up on the page.
                actions.login('*****@*****.**')
                self._verify_announcements(['Foo'], ['Bar'])
    def test_change_base_announcment_updates_i18n_progress(self):
        LOCALE = 'de'
        with actions.OverriddenConfig(models.CAN_USE_MEMCACHE.name, True):
            with actions.OverriddenEnvironment({
                    'course': {
                        'locale': 'en_US',
                    },
                    'extra_locales': [{
                        'locale': LOCALE,
                        'availability': 'true'
                    }]
            }):

                key = self._add_announcement()
                data = {
                    'key': key,
                    'date': utc.to_text(seconds=0),
                    'html': 'Unsafe for operation',
                    'title': 'Attention',
                    'is_draft': False,
                }
                self._put_announcement(data)
                self._put_translation(data, LOCALE, 'Achtung', 'Gefahrlich!')

                # Verify that having saved the translation, we are in progress
                # state DONE.
                resource_key = str(
                    resource.Key(
                        announcements.ResourceHandlerAnnouncement.TYPE,
                        db.Key(encoded=data['key']).id()))
                progress = i18n_dashboard.I18nProgressDAO.load(resource_key)
                self.assertEquals(progress.get_progress(LOCALE),
                                  i18n_dashboard.I18nProgressDTO.DONE)

                # Modify the announcement in the base language.
                data['title'] = 'Informational'
                data['html'] = 'Now safe for operation again'
                self._put_announcement(data)
                self.execute_all_deferred_tasks()

                # Verify that saving the base version of the announcement
                # moves the progress state back.
                progress = i18n_dashboard.I18nProgressDAO.load(resource_key)
                self.assertEquals(progress.get_progress(LOCALE),
                                  i18n_dashboard.I18nProgressDTO.IN_PROGRESS)
    def test_search_index_translated_announcements(self):
        LOCALE = 'de'
        with actions.OverriddenConfig(models.CAN_USE_MEMCACHE.name, True):
            with actions.OverriddenEnvironment({
                    'course': {
                        'locale': 'en_US',
                    },
                    'extra_locales': [{
                        'locale': LOCALE,
                        'availability': 'true'
                    }]
            }):

                key = self._add_announcement()
                data = {
                    'key': key,
                    'date': utc.to_text(seconds=0),
                    'html': 'Unsafe for operation',
                    'title': 'Attention',
                    'is_draft': False,
                }
                self._put_announcement(data)
                self._put_translation(data, LOCALE, 'Achtung', 'Gefahrlich!')

                response = self.post(
                    self.base + '/dashboard?action=index_course', {
                        'xsrf_token':
                        crypto.XsrfTokenManager.create_xsrf_token(
                            'index_course')
                    })
                self.assertEquals(302, response.status_int)
                self.execute_all_deferred_tasks()

                actions.login('*****@*****.**')
                actions.register(self, 'John Doe')
                self._set_prefs_locale(LOCALE)

                response = self.get('search?query=Achtung')
                soup = self.parse_html_string_to_soup(response.body)
                snippets = soup.select('.gcb-search-result-snippet')
                self.assertEquals(snippets[0].text.strip(), 'Gefahrlich!...')
    def test_announcement_caching(self):

        with actions.OverriddenConfig(models.CAN_USE_MEMCACHE.name, True):

            # Get the fact that there are no announcements into the cache.
            self._verify_announcements(
                [], ['Currently, there are no announcements.'])

            # Add an announcement
            key = self._add_announcement()
            data = {
                'key': key,
                'date': utc.to_text(seconds=0),
                'html': 'Twas brillig, and the slithy toves',
                'title': 'Jabberwocky',
                'is_draft': True,
            }
            self._put_announcement(data)

            # Admin sees announcement on course page.
            self._verify_announcements([data['title'] + ' (Private)'],
                                       [data['html']])

            # Capture cache content for later.
            cache_content = models.MemcacheManager.get(
                announcements.AnnouncementEntity._MEMCACHE_KEY)

            # Delete announcement.
            self._delete_announcement(key)

            # Check that we see no announcements.
            self._verify_announcements(
                [], ['Currently, there are no announcements.'])

            # Put cache content back and verify we see cache content on page.
            models.MemcacheManager.set(
                announcements.AnnouncementEntity._MEMCACHE_KEY, cache_content)
            self._verify_announcements([data['title'] + ' (Private)'],
                                       [data['html']])
    def test_end_to_end(self):
        """Actually enroll and unenroll students; verify reporting counts."""

        COURSE_NAME_BASE = 'test'
        NUM_COURSES = 2
        NUM_STUDENTS = 3
        THE_TIMESTAMP = 1427245200

        for course_num in range(NUM_COURSES):
            course_name = '%s_%d' % (COURSE_NAME_BASE, course_num)
            actions.simple_add_course(course_name, ADMIN_EMAIL, course_name)
            actions.update_course_config(course_name, {
                'course': {
                    'now_available': True,
                    'browsable': True,
                },
            })
            for student_num in range(NUM_STUDENTS):
                name = '%s_%d_%d' % (COURSE_NAME_BASE, course_num, student_num)
                actions.login(name + '@foo.com')
                actions.register(self, name, course_name)
                if student_num == 0:
                    actions.unregister(self, course_name)
                actions.logout()

        # Expect no messages yet; haven't run job.
        self.assertEquals([], MockSender.get_sent())

        # Run all counting jobs.
        with actions.OverriddenConfig(config.REPORT_ALLOWED.name, True):
            usage_reporting.StartReportingJobs._for_testing_only_get()
        self.execute_all_deferred_tasks(
            models.StudentLifecycleObserver.QUEUE_NAME)
        self.execute_all_deferred_tasks()

        # Verify counts.  (Ignore dates, these are fickle and subject to
        # weirdness on hour boundaries.  Also ignore course/instance IDs;
        # they are non-random and thus all the same.)
        num_enrolled_msgs = 0
        num_unenrolled_msgs = 0
        num_student_count_msgs = 0
        for message in MockSender.get_sent():
            if (message[messaging.Message._METRIC] ==
                    messaging.Message.METRIC_STUDENT_COUNT):
                num_student_count_msgs += 1
                self.assertEquals(NUM_STUDENTS,
                                  message[messaging.Message._VALUE])
            elif (message[messaging.Message._METRIC] ==
                  messaging.Message.METRIC_ENROLLED):
                num_enrolled_msgs += 1
                self.assertEquals(NUM_STUDENTS,
                                  message[messaging.Message._VALUE])
            elif (message[messaging.Message._METRIC] ==
                  messaging.Message.METRIC_UNENROLLED):
                num_unenrolled_msgs += 1
                self.assertEquals(1, message[messaging.Message._VALUE])

        self.assertEquals(NUM_COURSES, num_enrolled_msgs)
        self.assertEquals(NUM_COURSES, num_unenrolled_msgs)
        self.assertEquals(NUM_COURSES, num_student_count_msgs)
        sites.reset_courses()
Ejemplo n.º 8
0
    def test_multiple_courses(self):
        COURSE_TWO = 'course_two'
        COURSE_TWO_NS = 'ns_' + COURSE_TWO

        # Slight cheat: Register gitkit data remover manually, rather than
        # enabling the entire module, which disrupts normal functional test
        # user login handling
        gitkit.EmailMapping.register_for_data_removal()

        actions.simple_add_course(
            COURSE_TWO, self.ADMIN_EMAIL, 'Data Removal Test Two')
        user = actions.login(self.STUDENT_EMAIL)

        with actions.OverriddenConfig(models.CAN_SHARE_STUDENT_PROFILE.name,
                                      True):
            actions.register(self, user.email(), course=self.COURSE)
            actions.register(self, user.email(), course=COURSE_TWO)
            # Slight cheat: Rather than enabling gitkit module, just call
            # the method that will insert the EmailMapping row.
            gitkit.EmailUpdatePolicy.apply(user)

        # Global profile object(s) should now exist.
        profile = models.StudentProfileDAO.get_profile_by_user_id(
            user.user_id())
        self.assertIsNotNone(profile)
        email_policy = gitkit.EmailMapping.get_by_user_id(user.user_id())
        self.assertIsNotNone(email_policy)

        # Unregister from 'data_removal_test' course.
        self._unregister_and_request_data_removal(self.COURSE)
        self._complete_removal()

        # Student object should be gone from data_removal_test course, but
        # not from course_two.
        with common_utils.Namespace(self.NAMESPACE):
            self.assertIsNone(models.Student.get_by_user(user))
        with common_utils.Namespace(COURSE_TWO_NS):
            self.assertIsNotNone(models.Student.get_by_user(user))

        # Global profile object(s) should still exist.
        profile = models.StudentProfileDAO.get_profile_by_user_id(
            user.user_id())
        self.assertIsNotNone(profile)
        email_policy = gitkit.EmailMapping.get_by_user_id(user.user_id())
        self.assertIsNotNone(email_policy)

        # Unregister from other course.
        self._unregister_and_request_data_removal(COURSE_TWO)
        self._complete_removal()

        # Both Student objects should now be gone.
        with common_utils.Namespace(self.NAMESPACE):
            self.assertIsNone(models.Student.get_by_user(user))
        with common_utils.Namespace(COURSE_TWO_NS):
            self.assertIsNone(models.Student.get_by_user(user))

        # Global profile object(s) should also be gone.
        profile = models.StudentProfileDAO.get_profile_by_user_id(
            user.user_id())
        self.assertIsNone(profile)
        email_policy = gitkit.EmailMapping.get_by_user_id(user.user_id())
        self.assertIsNone(email_policy)