Example #1
0
    def test_malformed_requests(self):
        response = self.put(ADMIN_SETTINGS_URL, {})
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
        self.assertEquals('Missing "request" parameter.', payload['message'])

        response = self.put(ADMIN_SETTINGS_URL, {'request': 'asdfasdf'})
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
        self.assertEquals('Malformed "request" parameter.', payload['message'])

        response = self.put(
            ADMIN_SETTINGS_URL, {
                'request':
                transforms.dumps({'xsrf_token': cgi.escape(self.xsrf_token)})
            })
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
        self.assertEquals('Request missing "key" parameter.',
                          payload['message'])

        response = self.put(
            ADMIN_SETTINGS_URL, {
                'request':
                transforms.dumps({
                    'xsrf_token': cgi.escape(self.xsrf_token),
                    'key': 'base:after_body_tag_begins'
                })
            })
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
        self.assertEquals('Request missing "payload" parameter.',
                          payload['message'])

        response = self.put(
            ADMIN_SETTINGS_URL, {
                'request':
                transforms.dumps({
                    'xsrf_token': cgi.escape(self.xsrf_token),
                    'key': 'base:after_body_tag_begins',
                    'payload': 'asdfsdfasdf'
                })
            })
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
        self.assertEquals('Malformed "payload" parameter.', payload['message'])

        response = self.put(
            ADMIN_SETTINGS_URL, {
                'request':
                transforms.dumps({
                    'xsrf_token': cgi.escape(self.xsrf_token),
                    'key': 'base:after_body_tag_begins',
                    'payload': '{}'
                })
            })
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
        self.assertEquals('Payload missing "hook_content" parameter.',
                          payload['message'])
Example #2
0
    def test_update_wont_clobber_status(self):
        # This fixture should already have a sync time
        with utils.Namespace(self.app_context.namespace):
            dto = drive_models.DriveSyncDAO.load('6')
            self.assertIsNotNone(dto.last_synced)

        # update existing record
        self.assertRestStatus(self.put('rest/modules/drive/item', {
            'request': transforms.dumps({
                'xsrf_token':
                    crypto.XsrfTokenManager.create_xsrf_token(
                        'drive-item-rest'),
                'key': '6',
                'payload': transforms.dumps({
                    'sync_interval': 'hour',
                    'version': '1.0',
                    'availability': 'public',
                }),
            }),
        }), 200)

        # The sync time should still exist
        with utils.Namespace(self.app_context.namespace):
            dto = drive_models.DriveSyncDAO.load('6')
            self.assertIsNotNone(dto.last_synced)
Example #3
0
def _attach_filter_data(handler, element):
    course = courses.Course(handler)
    unit_list = []
    assessment_list = []
    for unit in course.get_units():
        if verify.UNIT_TYPE_UNIT == unit.type:
            unit_list.append((unit.unit_id, unit.title))
        if unit.is_assessment():
            assessment_list.append((unit.unit_id, unit.title))

    lessons_map = {}
    for (unit_id, unused_title) in unit_list:
        lessons_map[unit_id] = [
            (l.lesson_id, l.title) for l in course.get_lessons(unit_id)]

    element.add_attribute(
        data_units=transforms.dumps(unit_list + assessment_list),
        data_lessons_map=transforms.dumps(lessons_map),
        data_questions=transforms.dumps(
            [(question.id, question.description) for question in sorted(
                models.QuestionDAO.get_all(), key=lambda q: q.description)]
        ),
        data_groups=transforms.dumps(
            [(group.id, group.description) for group in sorted(
                models.QuestionGroupDAO.get_all(), key=lambda g: g.description)]
        ),
        data_types=transforms.dumps([
            (models.QuestionDTO.MULTIPLE_CHOICE, 'Multiple Choice'),
            (models.QuestionDTO.SHORT_ANSWER, 'Short Answer')])
    )
 def validate(self, value):
     value = super(_SerializedProperty, self).validate(value)
     try:
         transforms.dumps(value)
     except TypeError, e:
         raise db.BadValueError(
             '%s is not JSON-serializable; error was "%s"' % (value, e))
Example #5
0
def _attach_filter_data(handler, element):
    course = courses.Course(handler)
    unit_list = []
    assessment_list = []
    for unit in course.get_units():
        if verify.UNIT_TYPE_UNIT == unit.type:
            unit_list.append((unit.unit_id, unit.title))
        if unit.is_assessment():
            assessment_list.append((unit.unit_id, unit.title))

    lessons_map = {}
    for (unit_id, unused_title) in unit_list:
        lessons_map[unit_id] = [
            (l.lesson_id, l.title) for l in course.get_lessons(unit_id)]

    element.add_attribute(
        data_units=transforms.dumps(unit_list + assessment_list),
        data_lessons_map=transforms.dumps(lessons_map),
        data_questions=transforms.dumps(
            [(question.id, question.description) for question in sorted(
                models.QuestionDAO.get_all(), key=lambda q: q.description)]
        ),
        data_groups=transforms.dumps(
            [(group.id, group.description) for group in sorted(
                models.QuestionGroupDAO.get_all(), key=lambda g: g.description)]
        ),
        data_types=transforms.dumps([
            (models.QuestionDTO.MULTIPLE_CHOICE, 'Multiple Choice'),
            (models.QuestionDTO.SHORT_ANSWER, 'Short Answer')])
    )
Example #6
0
    def post_data(self,
                  key=None,
                  rating_int=None,
                  additional_comments=None,
                  xsrf_token=None):

        if key is None:
            key = self.key

        if xsrf_token is None:
            xsrf_token = utils.XsrfTokenManager.create_xsrf_token('rating')

        request = {
            'xsrf_token':
            xsrf_token,
            'payload':
            transforms.dumps({
                'key': key,
                'rating': rating_int,
                'additional_comments': additional_comments
            })
        }
        return transforms.loads(
            self.post('rest/modules/rating?%s', {
                'request': transforms.dumps(request)
            }).body)
 def test_adding_empty_question_group(self):
     QG_URL = '/%s%s' % (self.COURSE_NAME,
                         question_group_editor.QuestionGroupRESTHandler.URI)
     xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
         question_group_editor.QuestionGroupRESTHandler.XSRF_TOKEN)
     description = 'Question Group'
     version = (
         question_group_editor.QuestionGroupRESTHandler.SCHEMA_VERSIONS[0])
     payload = {
         'description': description,
         'version': version,
         'introduction': '',
         'items': []
     }
     response = self.put(
         QG_URL, {
             'request':
             transforms.dumps({
                 'xsrf_token': cgi.escape(xsrf_token),
                 'payload': transforms.dumps(payload)
             })
         })
     self.assertEquals(response.status_int, 200)
     payload = transforms.loads(response.body)
     self.assertEquals(payload['status'], 200)
     self.assertEquals(payload['message'], 'Saved.')
     question_groups_table = self._soup_table()
     self.assertEquals(
         question_groups_table.select('.description-cell a')
         [0].text.strip(), description)
Example #8
0
 def test_adding_empty_question_group(self):
     QG_URL = '/%s%s' % (self.COURSE_NAME, QuestionGroupRESTHandler.URI)
     xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
         QuestionGroupRESTHandler.XSRF_TOKEN)
     description = 'Question Group'
     payload = {
         'description': description,
         'version': QuestionGroupRESTHandler.SCHEMA_VERSIONS[0],
         'introduction': '',
         'items': []
     }
     response = self.put(
         QG_URL, {
             'request':
             transforms.dumps({
                 'xsrf_token': cgi.escape(xsrf_token),
                 'payload': transforms.dumps(payload)
             })
         })
     self.assertEquals(response.status_int, 200)
     payload = transforms.loads(response.body)
     self.assertEquals(payload['status'], 200)
     self.assertEquals(payload['message'], 'Saved.')
     asset_tables = self._load_tables()
     self.assertEquals(asset_tables[1].find('./tbody/tr/td/a').tail,
                       description)
    def setUp(self):
        super(RolesTest, self).setUp()

        actions.login(COURSE_ADMIN_EMAIL, is_admin=True)
        payload_dict = {
            'name': COURSE_NAME,
            'title': 'Roles Test',
            'admin_email': COURSE_ADMIN_EMAIL}
        request = {
            'payload': transforms.dumps(payload_dict),
            'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                'add-course-put')}
        response = self.testapp.put('/rest/courses/item?%s' % urllib.urlencode(
            {'request': transforms.dumps(request)}), {})
        self.assertEquals(response.status_int, 200)
        sites.setup_courses('course:/%s::ns_%s, course:/:/' % (
                COURSE_NAME, COURSE_NAME))
        actions.logout()

        config.Registry.test_overrides[roles.GCB_ADMIN_LIST.name] = (
            '[%s]' % SITE_ADMIN_EMAIL)

        # pylint: disable-msg=protected-access
        self.old_registered_permission = roles.Roles._REGISTERED_PERMISSIONS
        roles.Roles._REGISTERED_PERMISSIONS = {}

        config.Registry.test_overrides[models.CAN_USE_MEMCACHE.name] = True
Example #10
0
    def fill_values(app_context, template_values, job):
        """Returns Jinja markup for question stats analytics."""
        stats_calculated = False
        stats = None
        course = courses.Course(None, app_context=app_context)
        unit_id_to_title = dict()
        for unit in course.get_units():
            if not unit.is_custom_unit():
                continue
            if unit.custom_unit_type != base.ProgAssignment.UNIT_TYPE_ID:
                continue
            unit_id_to_title[str(unit.unit_id)] = '%s (%d)' % (
                unit.title, unit.unit_id)

        def ordering(a1, a2):
            return cmp(a1['unit_id'], a2['unit_id'])

        if job and job.status_code == jobs.STATUS_CODE_COMPLETED:
            o = jobs.MapReduceJob.get_results(job)
            if o:
                stats = list(o)
                stats.sort(ordering)
                stats_calculated = True
        template_values.update({
            'test_stats': transforms.dumps(stats),
            'unit_title': transforms.dumps(unit_id_to_title),
            'stats_calculated': stats_calculated,
            })
 def validate(self, value):
     value = super(_SerializedProperty, self).validate(value)
     try:
         transforms.dumps(value)
     except TypeError, e:
         raise db.BadValueError(
             '%s is not JSON-serializable; error was "%s"' % (value, e))
 def test_adding_empty_question_group(self):
     QG_URL = '/%s%s' % (
         self.COURSE_NAME,
         question_group_editor.QuestionGroupRESTHandler.URI)
     xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
         question_group_editor.QuestionGroupRESTHandler.XSRF_TOKEN)
     description = 'Question Group'
     version = (
         question_group_editor.QuestionGroupRESTHandler.SCHEMA_VERSIONS[0])
     payload = {
         'description': description,
         'version': version,
         'introduction': '',
         'items': []
     }
     response = self.put(QG_URL, {'request': transforms.dumps({
         'xsrf_token': cgi.escape(xsrf_token),
         'payload': transforms.dumps(payload)})})
     self.assertEquals(response.status_int, 200)
     payload = transforms.loads(response.body)
     self.assertEquals(payload['status'], 200)
     self.assertEquals(payload['message'], 'Saved.')
     question_groups_table = self._soup_table()
     self.assertEquals(
         question_groups_table.select('.description-cell a')[0].text.strip(),
         description)
Example #13
0
    def test_add_file_in_subdir(self):

        # Upload file via REST POST
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
            filer.TextAssetRESTHandler.XSRF_TOKEN_NAME)
        key = 'assets/lib/my_project/foo.js'
        contents = 'alert("Hello, world");'
        response = self.put(
            TEXT_ASSET_URL, {
                'request':
                transforms.dumps(
                    {
                        'xsrf_token': cgi.escape(xsrf_token),
                        'key': key,
                        'payload': transforms.dumps({'contents': contents})
                    })
            })
        payload = transforms.loads(response.body)
        self.assertEquals(200, payload['status'])

        # Verify that content is available via REST GET.
        response = self.get(TEXT_ASSET_URL + '?key=%s' % cgi.escape(key))
        payload = transforms.loads(response.body)
        self.assertEquals(200, payload['status'])
        payload = transforms.loads(payload['payload'])
        self.assertEquals(contents, payload['contents'])

        # Verify that file uploaded to subdir is available via HTTP server
        response = self.get('/%s/%s' % (COURSE_NAME, key))
        self.assertEquals(contents, response.body)
Example #14
0
    def setUp(self):
        super(RolesTest, self).setUp()

        actions.login(COURSE_ADMIN_EMAIL, is_admin=True)
        payload_dict = {
            'name': COURSE_NAME,
            'title': 'Roles Test',
            'admin_email': COURSE_ADMIN_EMAIL
        }
        request = {
            'payload':
            transforms.dumps(payload_dict),
            'xsrf_token':
            crypto.XsrfTokenManager.create_xsrf_token('add-course-put')
        }
        response = self.testapp.put(
            '/rest/courses/item?%s' %
            urllib.urlencode({'request': transforms.dumps(request)}), {})
        self.assertEquals(response.status_int, 200)
        sites.setup_courses('course:/%s::ns_%s, course:/:/' %
                            (COURSE_NAME, COURSE_NAME))
        actions.logout()

        config.Registry.test_overrides[roles.GCB_ADMIN_LIST.name] = (
            '[%s]' % SITE_ADMIN_EMAIL)

        # pylint: disable-msg=protected-access
        self.old_registered_permission = roles.Roles._REGISTERED_PERMISSIONS
        roles.Roles._REGISTERED_PERMISSIONS = {}

        config.Registry.test_overrides[models.CAN_USE_MEMCACHE.name] = True
Example #15
0
    def setUp(self):
        super(WhitelistTest, self).setUp()

        config.Registry.test_overrides[
            course_explorer.GCB_ENABLE_COURSE_EXPLORER_PAGE.name] = True

        actions.login(ADMIN_EMAIL, is_admin=True)
        payload_dict = {
            'name': COURSE_NAME,
            'title': 'Whitelist Test',
            'admin_email': ADMIN_EMAIL
        }
        request = {
            'payload':
            transforms.dumps(payload_dict),
            'xsrf_token':
            crypto.XsrfTokenManager.create_xsrf_token('add-course-put')
        }
        response = self.testapp.put(
            '/rest/courses/item?%s' %
            urllib.urlencode({'request': transforms.dumps(request)}), {})
        self.assertEquals(response.status_int, 200)
        sites.setup_courses('course:/%s::ns_%s, course:/:/' %
                            (COURSE_NAME, COURSE_NAME))
        actions.logout()
    def test_set_hook_content(self):
        html_text = "<table><tbody><tr><th>;&lt;&gt;</th></tr></tbody></table>"

        response = self.put(
            ADMIN_SETTINGS_URL,
            {
                "request": transforms.dumps(
                    {
                        "xsrf_token": cgi.escape(self.xsrf_token),
                        "key": "base.after_body_tag_begins",
                        "payload": transforms.dumps({"hook_content": html_text}),
                    }
                )
            },
        )
        self.assertEquals(200, response.status_int)
        response = transforms.loads(response.body)
        self.assertEquals(200, response["status"])
        self.assertEquals("Saved.", response["message"])

        # And verify that the changed text appears on course pages.
        # NOTE that text is as-is; no escaping of special HTML
        # characters should have been done.
        response = self.get(BASE_URL)
        self.assertIn(html_text, response.body)
def add_header_diagrams(handler, app_context, unit, lesson, student):
    # Make sure that checkbox in Skills dashboard section is checked
    env = courses.Course.get_environ(app_context)
    if SETTINGS_SCHEMA_SECTION_NAME not in env:
        return None
    if not env[SETTINGS_SCHEMA_SECTION_NAME].get(SETTING_LOCAL_GRAPH_ENABLED):
        return None

    if isinstance(student, models.TransientStudent):
        my_skill_map = skill_map.SkillMap.load(handler.get_course())
    else:
        my_skill_map = skill_map.SkillMap.load(handler.get_course(),
                                               user_id=student.user_id)
    skills = my_skill_map.get_skills_for_lesson(lesson.lesson_id)
    skills_set = set(skills)  # We convert this to a set for O(1) lookup time.

    course = handler.get_course()
    nodes = [
        get_node_data(course, my_skill_map, skill, student) for skill in skills
    ]
    edges = []
    for node in nodes:
        node['highlight'] = True

    for index in xrange(len(skills)):
        skill = skill_map.filter_visible_lessons(handler, student,
                                                 skills[index])

        prerequisites = skill.prerequisites
        for prereq_skill in prerequisites:
            if prereq_skill not in skills_set:
                # Add 0-based link index. The source is the node that's about to
                # be placed at the end, and the target is the one at the current
                # index.
                edges.append({'source': len(nodes), 'target': index})
                nodes.append(
                    get_node_data(course, my_skill_map, prereq_skill, student))

        successors = my_skill_map.successors(skill)
        for succ_skill in successors:
            if succ_skill not in skills_set:
                # Add 0-based link index. The source is the node at the current
                # index, and the target is the one that's about to be placed at
                # the end.
                edges.append({'source': index, 'target': len(nodes)})
                nodes.append(
                    get_node_data(course, my_skill_map, succ_skill, student))

    template_values = {
        'nodes': transforms.dumps(nodes),
        'edges': transforms.dumps(edges)
    }

    title = 'Skill graph'
    content = jinja2.Markup(
        handler.get_template('unit_header.html',
                             [TEMPLATES_DIR]).render(template_values))

    return {'title': title, 'content': content}
    def fill_values(app_context, template_values, job):
        accumulated_question_answers, accumulated_assessment_answers = (
            transforms.loads(job.output))

        template_values['accumulated_question_answers'] = transforms.dumps(
            accumulated_question_answers)
        template_values['accumulated_assessment_answers'] = transforms.dumps(
            accumulated_assessment_answers)
    def fill_values(app_context, template_values, job):
        accumulated_question_answers, accumulated_assessment_answers = (
            transforms.loads(job.output))

        template_values['accumulated_question_answers'] = transforms.dumps(
            accumulated_question_answers)
        template_values['accumulated_assessment_answers'] = transforms.dumps(
            accumulated_assessment_answers)
Example #20
0
    def _fill_completed_values(self, job, template_values):
        accumulated_question_answers, accumulated_assessment_answers = (
            transforms.loads(job.output))

        template_values['accumulated_question_answers'] = transforms.dumps(
            accumulated_question_answers)
        template_values['accumulated_assessment_answers'] = transforms.dumps(
            accumulated_assessment_answers)
Example #21
0
    def post(self):
        name = COURSE_EXPLORER_SETTINGS.name
        request = transforms.loads(self.request.get('request'))

        if not self.assert_xsrf_token_or_fail(request, self.ACTION, {}):
            return

        if not roles.Roles.is_course_admin(self.app_context):
            transforms.send_json_response(self, 401, 'Access denied.', {})
            return

        raw_data = transforms.loads(request.get('payload'))
        raw_data.pop('logo', None)
        try:
            data = transforms.json_to_dict(
                raw_data,
                schema_provider(None).get_json_schema_dict())
        except (TypeError, ValueError) as err:
            self.validation_error(err.replace('\n', ' '))
            return

        logo = self.request.POST.get('logo')
        logo_uploaded = isinstance(logo, cgi.FieldStorage)
        if logo_uploaded:
            data['logo_bytes_base64'] = base64.b64encode(logo.file.read())
            data['logo_mime_type'] = logo.type

        with common_utils.Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):
            entity = config.ConfigPropertyEntity.get_by_key_name(name)

            if entity is None:
                entity = config.ConfigPropertyEntity(key_name=name)
                old_value = None
            else:
                old_value = entity.value

            # Don't delete the logo.
            if not logo_uploaded and old_value:
                old_dict = transforms.loads(old_value)
                if ('logo_bytes_base64' in old_dict
                        and 'logo_mime_type' in old_dict):
                    data['logo_bytes_base64'] = old_dict['logo_bytes_base64']
                    data['logo_mime_type'] = old_dict['logo_mime_type']

            entity.value = transforms.dumps(data)
            entity.is_draft = False
            entity.put()

            # is this necessary?
            models.EventEntity.record(
                'put-property', users.get_current_user(),
                transforms.dumps({
                    'name': name,
                    'before': str(old_value),
                    'after': str(entity.value)
                }))

        transforms.send_file_upload_response(self, 200, 'Saved.')
    def fill_values(app_context, template_values, job):
        # pylint: disable=unpacking-non-sequence
        accumulated_question_answers, accumulated_assessment_answers = (
            transforms.loads(job.output))

        template_values['accumulated_question_answers'] = transforms.dumps(
            accumulated_question_answers)
        template_values['accumulated_assessment_answers'] = transforms.dumps(
            accumulated_assessment_answers)
Example #23
0
    def post(self):
        name = COURSE_EXPLORER_SETTINGS.name
        request = transforms.loads(self.request.get('request'))

        if not self.assert_xsrf_token_or_fail(
                request, self.ACTION, {}):
            return

        if not roles.Roles.is_course_admin(self.app_context):
            transforms.send_json_response(
                self, 401, 'Access denied.', {})
            return

        raw_data = transforms.loads(request.get('payload'))
        raw_data.pop('logo', None)
        try:
            data = transforms.json_to_dict(
                raw_data, schema_provider(None).get_json_schema_dict())
        except (TypeError, ValueError) as err:
            self.validation_error(err.replace('\n', ' '))
            return

        logo = self.request.POST.get('logo')
        logo_uploaded = isinstance(logo, cgi.FieldStorage)
        if logo_uploaded:
            data['logo_bytes_base64'] = base64.b64encode(logo.file.read())
            data['logo_mime_type'] = logo.type

        with common_utils.Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):
            entity = config.ConfigPropertyEntity.get_by_key_name(name)

            if entity is None:
                entity = config.ConfigPropertyEntity(key_name=name)
                old_value = None
            else:
                old_value = entity.value

            # Don't delete the logo.
            if not logo_uploaded and old_value:
                old_dict = transforms.loads(old_value)
                if (
                        'logo_bytes_base64' in old_dict and
                        'logo_mime_type' in old_dict):
                    data['logo_bytes_base64'] = old_dict['logo_bytes_base64']
                    data['logo_mime_type'] = old_dict['logo_mime_type']

            entity.value = transforms.dumps(data)
            entity.is_draft = False
            entity.put()

            # is this necessary?
            models.EventEntity.record(
                'put-property', users.get_current_user(), transforms.dumps({
                    'name': name,
                    'before': str(old_value), 'after': str(entity.value)}))

        transforms.send_file_upload_response(self, 200, 'Saved.')
    def fill_values(app_context, template_values, job):
        # pylint: disable=unpacking-non-sequence
        accumulated_question_answers, accumulated_assessment_answers = (
            transforms.loads(job.output))

        template_values['accumulated_question_answers'] = transforms.dumps(
            accumulated_question_answers)
        template_values['accumulated_assessment_answers'] = transforms.dumps(
            accumulated_assessment_answers)
Example #25
0
    def get_markup(self, job):
        """Returns Jinja markup for question stats analytics."""

        errors = []
        stats_calculated = False
        update_message = safe_dom.Text('')

        accumulated_question_answers = None
        accumulated_assessment_answers = None

        if not job:
            update_message = safe_dom.Text(
                'Multiple-choice question statistics have not been calculated '
                'yet.')
        else:
            if job.status_code == jobs.STATUS_CODE_COMPLETED:
                accumulated_question_answers, accumulated_assessment_answers = (
                    transforms.loads(job.output))
                stats_calculated = True
                update_message = safe_dom.Text(
                    """
                    Multiple-choice question statistics were last updated at
                    %s in about %s second(s).""" %
                    (job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT),
                     job.execution_time_sec))
            elif job.status_code == jobs.STATUS_CODE_FAILED:
                update_message = safe_dom.NodeList().append(
                    safe_dom.Text("""
                        There was an error updating multiple-choice question
                        statistics. Here is the message:""")).append(
                        safe_dom.Element('br')).append(
                            safe_dom.Element('blockquote').add_child(
                                safe_dom.Element('pre').add_text('\n%s' %
                                                                 job.output)))
            else:
                update_message = safe_dom.Text(
                    """
                    Multiple-choice question statistics update started at %s
                    and is running now. Please come back shortly.""" %
                    (job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT)))

        return jinja2.utils.Markup(
            self.get_template(
                'question_stats.html', [os.path.dirname(__file__)]).render(
                    {
                        'errors':
                        errors,
                        'accumulated_question_answers':
                        transforms.dumps(accumulated_question_answers),
                        'accumulated_assessment_answers':
                        transforms.dumps(accumulated_assessment_answers),
                        'stats_calculated':
                        stats_calculated,
                        'update_message':
                        update_message,
                    },
                    autoescape=True))
    def test_malformed_requests(self):
        response = self.put(ADMIN_SETTINGS_URL, {})
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload["status"])
        self.assertEquals('Missing "request" parameter.', payload["message"])

        response = self.put(ADMIN_SETTINGS_URL, {"request": "asdfasdf"})
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload["status"])
        self.assertEquals('Malformed "request" parameter.', payload["message"])

        response = self.put(
            ADMIN_SETTINGS_URL, {"request": transforms.dumps({"xsrf_token": cgi.escape(self.xsrf_token)})}
        )
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload["status"])
        self.assertEquals('Request missing "key" parameter.', payload["message"])

        response = self.put(
            ADMIN_SETTINGS_URL,
            {
                "request": transforms.dumps(
                    {"xsrf_token": cgi.escape(self.xsrf_token), "key": "base:after_body_tag_begins"}
                )
            },
        )
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload["status"])
        self.assertEquals('Request missing "payload" parameter.', payload["message"])

        response = self.put(
            ADMIN_SETTINGS_URL,
            {
                "request": transforms.dumps(
                    {
                        "xsrf_token": cgi.escape(self.xsrf_token),
                        "key": "base:after_body_tag_begins",
                        "payload": "asdfsdfasdf",
                    }
                )
            },
        )
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload["status"])
        self.assertEquals('Malformed "payload" parameter.', payload["message"])

        response = self.put(
            ADMIN_SETTINGS_URL,
            {
                "request": transforms.dumps(
                    {"xsrf_token": cgi.escape(self.xsrf_token), "key": "base:after_body_tag_begins", "payload": "{}"}
                )
            },
        )
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload["status"])
        self.assertEquals('Payload missing "hook_content" parameter.', payload["message"])
def add_header_diagrams(handler, app_context, unit, lesson, student):
    # Make sure that checkbox in Skills dashboard section is checked
    env = courses.Course.get_environ(app_context)
    if SETTINGS_SCHEMA_SECTION_NAME not in env:
        return None
    if not env[SETTINGS_SCHEMA_SECTION_NAME].get(SETTING_LOCAL_GRAPH_ENABLED):
        return None

    if isinstance(student, models.TransientStudent):
        my_skill_map = skill_map.SkillMap.load(handler.get_course())
    else:
        my_skill_map = skill_map.SkillMap.load(
            handler.get_course(), user_id=student.user_id)
    skills = my_skill_map.get_skills_for_lesson(lesson.lesson_id)
    skills_set = set(skills) # We convert this to a set for O(1) lookup time.

    course = handler.get_course()
    nodes = [get_node_data(course, my_skill_map, skill, student)
             for skill in skills]
    edges = []
    for node in nodes:
        node['highlight'] = True

    for index in xrange(len(skills)):
        skill = skill_map.filter_visible_lessons(handler, student,
                                                 skills[index])

        prerequisites = skill.prerequisites
        for prereq_skill in prerequisites:
            if prereq_skill not in skills_set:
                # Add 0-based link index. The source is the node that's about to
                # be placed at the end, and the target is the one at the current
                # index.
                edges.append({'source': len(nodes), 'target': index})
                nodes.append(get_node_data(course, my_skill_map, prereq_skill,
                                           student))

        successors = my_skill_map.successors(skill)
        for succ_skill in successors:
            if succ_skill not in skills_set:
                # Add 0-based link index. The source is the node at the current
                # index, and the target is the one that's about to be placed at
                # the end.
                edges.append({'source': index, 'target': len(nodes)})
                nodes.append(get_node_data(course, my_skill_map, succ_skill,
                                           student))

    template_values = {'nodes': transforms.dumps(nodes),
                       'edges': transforms.dumps(edges)}

    title = 'Skill graph'
    content = jinja2.Markup(
    handler.get_template('unit_header.html', [TEMPLATES_DIR]
        ).render(template_values))

    return {'title': title, 'content': content}
 def test_nested_json_flattens_correctly(self):
     dict1 = dict(aaa=111)
     dict2 = dict(aa=11, bb=22, cc=transforms.dumps(dict1))
     dict3 = dict(a=transforms.dumps(dict2), b=2)
     json = transforms.loads(transforms.dumps(dict3))
     flattened_json = mapreduce.CsvGenerator._flatten_json(json)
     result_json = transforms.loads(
         transforms.dumps(
             {'a_aa': '11', 'a_bb': '22', 'b': '2', 'a_cc_aaa': '111'}))
     self.assertEquals(result_json, flattened_json)
 def post_settings(self, payload, upload_files=None):
     response = self.post('rest/explorer-settings', {
         'request': transforms.dumps({
             'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                 'explorer-settings-rest'),
             'payload': transforms.dumps(payload),
         })
     }, upload_files=upload_files)
     self.assertEqual(response.status_code, 200)
     return response
Example #30
0
    def test_admin_post_change_report_allowed(self):
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
            'config_override')
        response = self.post(
            '/admin?action=config_override&name=%s' %
            config.REPORT_ALLOWED.name,
            {'xsrf_token': xsrf_token})
        response = self.get('/rest/config/item?key=%s' %
                            config.REPORT_ALLOWED.name)
        payload = {
            'name': config.REPORT_ALLOWED.name,
            'value': True,
            'is_draft': False,
            }
        message = {
            'key': config.REPORT_ALLOWED.name,
            'payload': transforms.dumps(payload),
            'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                'config-property-put'),
            }
        response = self.put('/rest/config/item',
                            {'request': transforms.dumps(message)})
        self.assertEqual(200, response.status_int)

        payload = {
            'name': config.REPORT_ALLOWED.name,
            'value': False,
            'is_draft': False,
            }
        message = {
            'key': config.REPORT_ALLOWED.name,
            'payload': transforms.dumps(payload),
            'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                'config-property-put'),
            }
        response = self.put('/rest/config/item',
                            {'request': transforms.dumps(message)})
        self.assertEqual(200, response.status_int)

        expected = [{
            messaging.Message._INSTALLATION: FAKE_INSTALLATION_ID,
            messaging.Message._TIMESTAMP: FAKE_TIMESTAMP,
            messaging.Message._VERSION: os.environ['GCB_PRODUCT_VERSION'],
            messaging.Message._METRIC: messaging.Message.METRIC_REPORT_ALLOWED,
            messaging.Message._VALUE: True,
            messaging.Message._SOURCE: messaging.Message.ADMIN_SOURCE,
        }, {
            messaging.Message._INSTALLATION: FAKE_INSTALLATION_ID,
            messaging.Message._TIMESTAMP: FAKE_TIMESTAMP,
            messaging.Message._VERSION: os.environ['GCB_PRODUCT_VERSION'],
            messaging.Message._METRIC: messaging.Message.METRIC_REPORT_ALLOWED,
            messaging.Message._VALUE: False,
            messaging.Message._SOURCE: messaging.Message.ADMIN_SOURCE,
        }]
        self.assertEquals(expected, MockSender.get_sent())
    def test_admin_post_change_report_allowed(self):
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
            'config_override')
        response = self.post(
            '/admin?action=config_override&name=%s' %
            config.REPORT_ALLOWED.name,
            {'xsrf_token': xsrf_token})
        response = self.get('/rest/config/item?key=%s' %
                            config.REPORT_ALLOWED.name)
        payload = {
            'name': config.REPORT_ALLOWED.name,
            'value': True,
            'is_draft': False,
            }
        message = {
            'key': config.REPORT_ALLOWED.name,
            'payload': transforms.dumps(payload),
            'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                'config-property-put'),
            }
        response = self.put('/rest/config/item',
                            {'request': transforms.dumps(message)})
        self.assertEqual(200, response.status_int)

        payload = {
            'name': config.REPORT_ALLOWED.name,
            'value': False,
            'is_draft': False,
            }
        message = {
            'key': config.REPORT_ALLOWED.name,
            'payload': transforms.dumps(payload),
            'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                'config-property-put'),
            }
        response = self.put('/rest/config/item',
                            {'request': transforms.dumps(message)})
        self.assertEqual(200, response.status_int)

        expected = [{
            messaging.Message._INSTALLATION: FAKE_INSTALLATION_ID,
            messaging.Message._TIMESTAMP: FAKE_TIMESTAMP,
            messaging.Message._VERSION: os.environ['GCB_PRODUCT_VERSION'],
            messaging.Message._METRIC: messaging.Message.METRIC_REPORT_ALLOWED,
            messaging.Message._VALUE: True,
            messaging.Message._SOURCE: messaging.Message.ADMIN_SOURCE,
        }, {
            messaging.Message._INSTALLATION: FAKE_INSTALLATION_ID,
            messaging.Message._TIMESTAMP: FAKE_TIMESTAMP,
            messaging.Message._VERSION: os.environ['GCB_PRODUCT_VERSION'],
            messaging.Message._METRIC: messaging.Message.METRIC_REPORT_ALLOWED,
            messaging.Message._VALUE: False,
            messaging.Message._SOURCE: messaging.Message.ADMIN_SOURCE,
        }]
        self.assertEquals(expected, MockSender.get_sent())
 def test_hook_rest_edit_removes_from_old_location(self):
     actions.update_course_config(COURSE_NAME,
                                  {'html_hooks': {'foo': {'bar': 'zab'}}})
     actions.update_course_config(COURSE_NAME,
                                  {'foo': {'bar': 'baz'}})
     response = self.put(ADMIN_SETTINGS_URL, {'request': transforms.dumps({
             'xsrf_token': cgi.escape(self.xsrf_token),
             'key': 'foo.bar',
             'payload': transforms.dumps({'hook_content': 'BAZ'})})})
     env = self.course.get_environ(self.app_context)
     self.assertNotIn('bar', env['foo'])
     self.assertEquals('BAZ', env['html_hooks']['foo']['bar'])
Example #33
0
 def serialize(self):
     adict = dict()
     adict['status'] = self.status
     adict['reason'] = self.reason
     adict['compilation_errors'] = transforms.dumps(self.compilation_errors)
     adict['num_test_evaluated'] = self.num_test_evaluated
     adict['num_test_passed'] = self.num_test_passed
     adict['summary'] = self.summary
     adict['score'] = self.score
     adict['test_case_results'] = [
         a.to_dict() for a in self.test_case_results]
     return transforms.dumps(adict)
Example #34
0
    def _post(self, xsrf_token=None, payload=None):
        request = {}
        if xsrf_token is None:
            xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(oeditor.EditorPrefsRestHandler.XSRF_TOKEN)
        request["xsrf_token"] = xsrf_token

        if payload is None:
            payload = {"location": self.location, "key": self.key, "state": self.EDITOR_STATE}
        request["payload"] = transforms.dumps(payload)

        data = {"request": transforms.dumps(request)}
        return self.post("oeditor/rest/editor_prefs", data, expect_errors=True)
Example #35
0
 def test_hook_rest_edit_removes_from_old_location(self):
     actions.update_course_config(COURSE_NAME,
                                  {'html_hooks': {'foo': {'bar': 'zab'}}})
     actions.update_course_config(COURSE_NAME,
                                  {'foo': {'bar': 'baz'}})
     response = self.put(ADMIN_SETTINGS_URL, {'request': transforms.dumps({
             'xsrf_token': cgi.escape(self.xsrf_token),
             'key': 'foo.bar',
             'payload': transforms.dumps({'hook_content': 'BAZ'})})})
     env = self.course.get_environ(self.app_context)
     self.assertNotIn('bar', env['foo'])
     self.assertEquals('BAZ', env['html_hooks']['foo']['bar'])
Example #36
0
    def get_markup(self, job):
        """Returns Jinja markup for question stats analytics."""

        errors = []
        stats_calculated = False
        update_message = safe_dom.Text('')

        accumulated_question_answers = None
        accumulated_assessment_answers = None

        if not job:
            update_message = safe_dom.Text(
                'Multiple-choice question statistics have not been calculated '
                'yet.')
        else:
            if job.status_code == jobs.STATUS_CODE_COMPLETED:
                accumulated_question_answers, accumulated_assessment_answers = (
                    transforms.loads(job.output))
                stats_calculated = True
                update_message = safe_dom.Text("""
                    Multiple-choice question statistics were last updated at
                    %s in about %s second(s).""" % (
                        job.updated_on.strftime(
                            HUMAN_READABLE_TIME_FORMAT),
                        job.execution_time_sec))
            elif job.status_code == jobs.STATUS_CODE_FAILED:
                update_message = safe_dom.NodeList().append(
                    safe_dom.Text("""
                        There was an error updating multiple-choice question
                        statistics. Here is the message:""")
                ).append(
                    safe_dom.Element('br')
                ).append(
                    safe_dom.Element('blockquote').add_child(
                        safe_dom.Element('pre').add_text('\n%s' % job.output)))
            else:
                update_message = safe_dom.Text("""
                    Multiple-choice question statistics update started at %s
                    and is running now. Please come back shortly.""" % (
                        job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT)))

        return jinja2.utils.Markup(self.get_template(
            'question_stats.html', [os.path.dirname(__file__)]
        ).render({
            'errors': errors,
            'accumulated_question_answers': transforms.dumps(
                accumulated_question_answers),
            'accumulated_assessment_answers': transforms.dumps(
                accumulated_assessment_answers),
            'stats_calculated': stats_calculated,
            'update_message': update_message,
        }, autoescape=True))
 def _put_translation(self, data, locale, title, html):
     resource_key = str(i18n_dashboard.ResourceBundleKey(
         announcements.ResourceHandlerAnnouncement.TYPE,
         db.Key(encoded=data['key']).id(), locale))
     xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
         i18n_dashboard.TranslationConsoleRestHandler.XSRF_TOKEN_NAME)
     request = {
         'key': resource_key,
         'xsrf_token': xsrf_token,
         'validate': False,
         'payload': transforms.dumps({
             'title': 'Announcements',
             'key': resource_key,
             'source_locale': 'en_US',
             'target_locale': locale,
             'sections': [
                 {
                     'name': 'title',
                     'label': 'Title',
                     'type': 'string',
                     'source_value': '',
                     'data': [{
                         'source_value': data['title'],
                         'target_value': title,
                         'verb': 1,  # verb NEW
                         'old_source_value': '',
                         'changed': True
                     }]
                 },
                 {
                     'name': 'html',
                     'label': 'Body',
                     'type': 'html',
                     'source_value': '',
                     'data': [{
                         'source_value': data['html'],
                         'target_value': html,
                         'verb': 1,  # verb NEW
                         'old_source_value': '',
                         'changed': True
                     }]
                 }
             ]
         })
     }
     response = self.put(
         self.base +
         i18n_dashboard.TranslationConsoleRestHandler.URL.lstrip(),
         {'request': transforms.dumps(request)})
     self.assertEquals(200, response.status_int)
     response = transforms.loads(response.body)
     self.assertEquals(200, response['status'])
 def _initiate_import(self):
     # GET and then POST to the clone-a-course REST handler.
     response = transforms.loads(self.get(self.import_start_url).body)
     payload = transforms.loads(response['payload'])
     content = transforms.dumps({
         'course': payload['course'],
         })
     request = transforms.dumps({
         'xsrf_token': response['xsrf_token'],
         'payload': content,
         })
     response = self.put(self.import_start_url, {'request': request})
     self.assertEquals(transforms.loads(response.body)['status'], 200)
Example #39
0
    def get_data(self, key=None, xsrf_token=None):
        if key is None:
            key = self.key
        if xsrf_token is None:
            xsrf_token = utils.XsrfTokenManager.create_xsrf_token('rating')

        request = {
            'xsrf_token': xsrf_token,
            'payload': transforms.dumps({'key': key})
        }
        return transforms.loads(
            self.get('rest/modules/rating?%s' % urllib.urlencode(
                {'request': transforms.dumps(request)})).body)
    def test_add_file_in_unsupported_dir(self):

        # Upload file via REST POST
        xsrf_token = crypto.XsrfTokenManager.create_xsrf_token(
            filer.TextAssetRESTHandler.XSRF_TOKEN_NAME)
        key = 'assets/unsupported/foo.js'
        contents = 'alert("Hello, world");'
        response = self.put(TEXT_ASSET_URL, {'request': transforms.dumps({
            'xsrf_token': cgi.escape(xsrf_token),
            'key': key,
            'payload': transforms.dumps({'contents': contents})})})
        payload = transforms.loads(response.body)
        self.assertEquals(400, payload['status'])
Example #41
0
    def get_data(self, key=None, xsrf_token=None):
        if key is None:
            key = self.key
        if xsrf_token is None:
            xsrf_token = utils.XsrfTokenManager.create_xsrf_token('rating')

        request = {
            'xsrf_token': xsrf_token,
            'payload': transforms.dumps({'key': key})
        }
        return transforms.loads(
            self.get('rest/modules/rating?%s' % urllib.urlencode(
                {'request': transforms.dumps(request)})).body)
Example #42
0
    def update_test_case_stats(cls, student, unit, is_public, stats):
        out = dict()
        for index, stat in enumerate(stats):
            out[index] = (stat.passed, stat.reason)

        entity = ProgrammingTestCasesEntity.get(student, unit.unit_id)
        if entity is None:
            entity = ProgrammingTestCasesEntity.create(student, unit.unit_id)
        if is_public:
            entity.public_test_case_data = transforms.dumps(out)
        else:
            entity.private_test_case_data = transforms.dumps(out)
        entity.put()
    def test_add_new_hook_to_page(self):
        hook_name = "html.my_new_hook"
        html_text = "<table><tbody><tr><th>;&lt;&gt;</th></tr></tbody></table>"
        key = "views/base.html"
        url = "%s?key=%s" % (TEXT_ASSET_URL, cgi.escape(key))

        # Get base page template.
        response = transforms.loads(self.get(url).body)
        xsrf_token = response["xsrf_token"]
        payload = transforms.loads(response["payload"])
        contents = payload["contents"]

        # Add hook specification to page content.
        contents = contents.replace(
            '<body data-gcb-page-locale="{{ page_locale }}">',
            '<body data-gcb-page-locale="{{ page_locale }}">\n' + "{{ html_hooks.insert('%s') | safe }}" % hook_name,
        )
        self.put(
            TEXT_ASSET_URL,
            {
                "request": transforms.dumps(
                    {
                        "xsrf_token": cgi.escape(xsrf_token),
                        "key": key,
                        "payload": transforms.dumps({"contents": contents}),
                    }
                )
            },
        )

        # Verify that new hook appears on page.
        response = self.get(BASE_URL)
        self.assertIn('id="%s"' % re.sub("[^a-zA-Z-]", "-", hook_name), response.body)

        # Verify that modified hook content appears on page
        response = self.put(
            ADMIN_SETTINGS_URL,
            {
                "request": transforms.dumps(
                    {
                        "xsrf_token": cgi.escape(self.xsrf_token),
                        "key": hook_name,
                        "payload": transforms.dumps({"hook_content": html_text}),
                    }
                )
            },
        )

        response = self.get(BASE_URL)
        self.assertIn(html_text, response.body)
Example #44
0
 def test_nested_json_flattens_correctly(self):
     dict1 = dict(aaa=111)
     dict2 = dict(aa=11, bb=22, cc=transforms.dumps(dict1))
     dict3 = dict(a=transforms.dumps(dict2), b=2)
     json = transforms.loads(transforms.dumps(dict3))
     flattened_json = mapreduce.CSVGenerator._flatten_json(json)
     result_json = transforms.loads(
         transforms.dumps({
             'a_aa': '11',
             'a_bb': '22',
             'b': '2',
             'a_cc_aaa': '111'
         }))
     self.assertEquals(result_json, flattened_json)
Example #45
0
    def test_manipulate_non_default_item(self):
        html_text = '<table><tbody><tr><th>;&lt;&gt;</th></tr></tbody></table>'
        new_hook_name = 'html.some_new_hook'

        # Verify that content prior to setting is blank.
        url = '%s?key=%s&xsrf_token=%s' % (ADMIN_SETTINGS_URL,
                                           cgi.escape(new_hook_name),
                                           cgi.escape(self.xsrf_token))
        response = transforms.loads(self.get(url).body)
        payload = transforms.loads(response['payload'])
        self.assertIsNone(payload['hook_content'])

        # Set the content.
        response = self.put(
            ADMIN_SETTINGS_URL, {
                'request':
                transforms.dumps(
                    {
                        'xsrf_token': cgi.escape(self.xsrf_token),
                        'key': new_hook_name,
                        'payload': transforms.dumps(
                            {'hook_content': html_text})
                    })
            })
        self.assertEquals(200, response.status_int)
        response = transforms.loads(response.body)
        self.assertEquals(200, response['status'])
        self.assertEquals('Saved.', response['message'])

        # Verify that content after setting is as expected
        url = '%s?key=%s&xsrf_token=%s' % (ADMIN_SETTINGS_URL,
                                           cgi.escape(new_hook_name),
                                           cgi.escape(self.xsrf_token))
        response = transforms.loads(self.get(url).body)
        payload = transforms.loads(response['payload'])
        self.assertEquals(html_text, payload['hook_content'])

        # Delete the content.
        response = transforms.loads(self.delete(url).body)
        self.assertEquals(200, response['status'])
        self.assertEquals('Deleted.', response['message'])

        # Verify that content after setting is None.
        url = '%s?key=%s&xsrf_token=%s' % (ADMIN_SETTINGS_URL,
                                           cgi.escape(new_hook_name),
                                           cgi.escape(self.xsrf_token))
        response = transforms.loads(self.get(url).body)
        payload = transforms.loads(response['payload'])
        self.assertIsNone(payload['hook_content'])
 def test_events_handler_processes_normally_completed_items(self):
     url = '/%s/rest/events' % COURSE_NAME
     payload = transforms.dumps({
         'location': 'http://localhost:8081/%s/unit?unit=%s&lesson=%s' % (
             COURSE_NAME, self._unit_two.unit_id, self._lesson_2_2.lesson_id)
     })
     request = transforms.dumps({
         'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
             'event-post'),
         'source': 'attempt-lesson',
         'payload': payload
     })
     response = self.post(url, {'request': request})
     response = self._get_lesson(self._lesson_2_2.lesson_id)
     self._expect_payload(response, 2)
 def _put(self, payload, expect_error=False):
     params = {
         'request': transforms.dumps({
             'xsrf_token': crypto.XsrfTokenManager.create_xsrf_token(
                 unit_lesson_editor.UnitLessonTitleRESTHandler.XSRF_TOKEN),
             'payload': transforms.dumps(payload),
         })
     }
     response = self.put(self.url, params)
     self.assertEquals(200, response.status_int)
     payload = transforms.loads(response.body)
     if expect_error:
         self.assertEquals(401, payload['status'])
     else:
         self.assertEquals(200, payload['status'])
Example #48
0
    def test_add_new_hook_to_page(self):
        hook_name = 'html.my_new_hook'
        html_text = '<table><tbody><tr><th>;&lt;&gt;</th></tr></tbody></table>'
        key = 'views/base.html'
        url = '%s?key=%s' % (TEXT_ASSET_URL, cgi.escape(key))

        # Get base page template.
        response = transforms.loads(self.get(url).body)
        xsrf_token = response['xsrf_token']
        payload = transforms.loads(response['payload'])
        contents = payload['contents']

        # Add hook specification to page content.
        contents = contents.replace(
            '<body data-gcb-page-locale="{{ page_locale }}">',
            '<body data-gcb-page-locale="{{ page_locale }}">\n' +
            '{{ html_hooks.insert(\'%s\') | safe }}' % hook_name)
        self.put(
            TEXT_ASSET_URL, {
                'request':
                transforms.dumps(
                    {
                        'xsrf_token': cgi.escape(xsrf_token),
                        'key': key,
                        'payload': transforms.dumps({'contents': contents})
                    })
            })

        # Verify that new hook appears on page.
        response = self.get(BASE_URL)
        self.assertIn('id="%s"' % re.sub('[^a-zA-Z-]', '-', hook_name),
                      response.body)

        # Verify that modified hook content appears on page
        response = self.put(
            ADMIN_SETTINGS_URL, {
                'request':
                transforms.dumps(
                    {
                        'xsrf_token': cgi.escape(self.xsrf_token),
                        'key': hook_name,
                        'payload': transforms.dumps(
                            {'hook_content': html_text})
                    })
            })

        response = self.get(BASE_URL)
        self.assertIn(html_text, response.body)
    def test_not_enough_assignments_to_allocate(self):
        """Test for the case when there are too few assignments in the pool."""

        email = '*****@*****.**'
        name = 'Student 1'
        submission = transforms.dumps([
            {'index': 0, 'type': 'regex', 'value': 'S1-1', 'correct': True},
            {'index': 1, 'type': 'choices', 'value': 3, 'correct': False},
            {'index': 2, 'type': 'regex', 'value': 'is-S1', 'correct': True},
        ])
        payload = {
            'answers': submission, 'assessment_type': LEGACY_REVIEW_UNIT_ID}

        actions.login(email)
        actions.register(self, name)
        response = actions.submit_assessment(
            self, LEGACY_REVIEW_UNIT_ID, payload)

        # The student goes to the review dashboard and requests an assignment
        # to review -- but there is nothing to review.
        response = actions.request_new_review(
            self, LEGACY_REVIEW_UNIT_ID, expected_status_code=200)
        assert_does_not_contain('Assignment to review', response.body)
        assert_contains('Sorry, there are no new submissions ', response.body)
        assert_contains('disabled="true"', response.body)

        actions.logout()
    def post_config_reset(self):
        """Handles 'reset' property action."""
        name = self.request.get('name')

        # Find item in registry.
        item = None
        if name and name in config.Registry.registered.keys():
            item = config.Registry.registered[name]
        if not item:
            self.redirect('/admin?action=settings')

        # Delete if exists.
        try:
            entity = config.ConfigPropertyEntity.get_by_key_name(name)
            if entity:
                old_value = entity.value
                entity.delete()

                models.EventEntity.record(
                    'delete-property', users.get_current_user(),
                    transforms.dumps({
                        'name': name, 'value': str(old_value)}))

        except db.BadKeyError:
            pass

        self.redirect('/admin?action=settings')
    def post_config_override(self):
        """Handles 'override' property action."""
        name = self.request.get('name')

        # Find item in registry.
        item = None
        if name and name in config.Registry.registered.keys():
            item = config.Registry.registered[name]
        if not item:
            self.redirect('/admin?action=settings')

        # Add new entity if does not exist.
        try:
            entity = config.ConfigPropertyEntity.get_by_key_name(name)
        except db.BadKeyError:
            entity = None
        if not entity:
            entity = config.ConfigPropertyEntity(key_name=name)
            entity.value = str(item.value)
            entity.is_draft = True
            entity.put()

        models.EventEntity.record(
            'override-property', users.get_current_user(), transforms.dumps({
                'name': name, 'value': str(entity.value)}))

        self.redirect('/admin?%s' % urllib.urlencode(
            {'action': 'config_edit', 'name': name}))
Example #52
0
 def configure_active_view_1_5(self, unit, submission_contents):
     self.template_value['html_content'] = unit.html_content
     self.template_value['html_check_answers'] = unit.html_check_answers
     if submission_contents:
         # If a previous submission exists, reinstate it.
         self.template_value['html_saved_answers'] = transforms.dumps(
             submission_contents)
def _add_unit_and_content(unit, result):
    """Adds the score dimensions for units and its lessons and questions."""
    # The content of an assessment is indicated by a lesson_id of None.
    # Inside that lesson we can find all the questions added directly
    # to the assessment.
    unit_dict = {
        DIM_TYPE: DIM_TYPE_UNIT,  # Unit or assessment
        DIM_ID: unit["unit_id"],
        "name": unit["title"],
    }  # Name won't be saved in ClusterEntity
    result.append(unit_dict)
    unit_scored_lessons = 0
    for item in unit["contents"]:
        lesson_id = item.get("lesson_id")
        # A unit may have a pre or post assessment, in that case the item
        # has unit_id, not a lesson_id.
        included_assessment_id = item.get("unit_id")
        lesson_title = item.get("title")
        if lesson_title and lesson_id and item.get("tallied"):
            result.append({DIM_TYPE: DIM_TYPE_LESSON, DIM_ID: lesson_id, "name": lesson_title})
            unit_scored_lessons += 1
        elif included_assessment_id and lesson_title:
            result.append({DIM_TYPE: DIM_TYPE_UNIT, DIM_ID: included_assessment_id, "name": lesson_title})
            unit_scored_lessons += 1
        # If lesson is not tallied (graded) is not considered a dimension
        for question in item["questions"]:
            if included_assessment_id:
                question_id = pack_question_dimid(included_assessment_id, None, question["id"])
            else:
                question_id = pack_question_dimid(unit["unit_id"], lesson_id, question["id"])
            result.append({DIM_TYPE: DIM_TYPE_QUESTION, DIM_ID: question_id, "name": question["description"]})
    # This should affect the result list as well.
    unit_dict[DIM_EXTRA_INFO] = transforms.dumps({"unit_scored_lessons": unit_scored_lessons})
Example #54
0
    def post_config_reset(self):
        """Handles 'reset' property action."""
        name = self.request.get('name')

        # Find item in registry.
        item = None
        if name and name in config.Registry.registered.keys():
            item = config.Registry.registered[name]
        if not item:
            self.redirect('%s?tab=settings' % self.LINK_URL)

        with Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):
            # Delete if exists.
            try:
                entity = config.ConfigPropertyEntity.get_by_key_name(name)
                if entity:
                    old_value = entity.value
                    entity.delete()

                    models.EventEntity.record(
                        'delete-property', users.get_current_user(),
                        transforms.dumps({
                            'name': name,
                            'value': str(old_value)
                        }))

            except db.BadKeyError:
                pass

        self.redirect('%s?tab=settings' % self.URL)
    def test_student_cannot_see_reviews_prematurely(self):
        """Test that students cannot see others' reviews prematurely."""

        email = '*****@*****.**'
        name = 'Student 1'
        submission = transforms.dumps([
            {'index': 0, 'type': 'regex', 'value': 'S1-1', 'correct': True},
            {'index': 1, 'type': 'choices', 'value': 3, 'correct': False},
            {'index': 2, 'type': 'regex', 'value': 'is-S1', 'correct': True},
        ])
        payload = {
            'answers': submission, 'assessment_type': LEGACY_REVIEW_UNIT_ID}

        actions.login(email)
        actions.register(self, name)
        response = actions.submit_assessment(
            self, LEGACY_REVIEW_UNIT_ID, payload)

        # Student 1 cannot see the reviews for his assignment yet, because he
        # has not submitted the two required reviews.
        response = self.get('assessment?name=%s' % LEGACY_REVIEW_UNIT_ID)
        assert_equals(response.status_int, 200)
        assert_contains('Due date for this assignment', response.body)
        assert_contains(
            'After you have completed the required number of peer reviews',
            response.body)

        actions.logout()
Example #56
0
 def _collect_blobstore_paths(cls, root_key):
     paths = set()
     # pylint: disable=protected-access
     for model, field_name in ((pipeline_models._SlotRecord, 'value'),
                               (pipeline_models._PipelineRecord, 'params')):
         prev_cursor = None
         any_records = True
         while any_records:
             any_records = False
             query = (model.all().filter('root_pipeline =',
                                         root_key).with_cursor(prev_cursor))
             for record in query.run():
                 any_records = True
                 # The data parameters in SlotRecord and PipelineRecord
                 # vary widely, but all are provided via this interface as
                 # some combination of Python scalar, list, tuple, and
                 # dict.  Rather than depend on specifics of the map/reduce
                 # internals, crush the object to a string and parse that.
                 try:
                     data_object = getattr(record, field_name)
                 except TypeError:
                     data_object = None
                 if data_object:
                     text = transforms.dumps(data_object)
                     for path in re.findall(r'"(/blobstore/[^"]+)"', text):
                         paths.add(path)
             prev_cursor = query.cursor()
     return paths
 def _collect_blobstore_paths(cls, root_key):
     paths = set()
     # pylint: disable=protected-access
     for model, field_name in ((pipeline_models._SlotRecord, 'value'),
                               (pipeline_models._PipelineRecord, 'params')):
         prev_cursor = None
         any_records = True
         while any_records:
             any_records = False
             query = (model
                      .all()
                      .filter('root_pipeline =', root_key)
                      .with_cursor(prev_cursor))
             for record in query.run():
                 any_records = True
                 # The data parameters in SlotRecord and PipelineRecord
                 # vary widely, but all are provided via this interface as
                 # some combination of Python scalar, list, tuple, and
                 # dict.  Rather than depend on specifics of the map/reduce
                 # internals, crush the object to a string and parse that.
                 try:
                     data_object = getattr(record, field_name)
                 except TypeError:
                     data_object = None
                 if data_object:
                     text = transforms.dumps(data_object)
                     for path in re.findall(r'"(/blobstore/[^"]+)"', text):
                         paths.add(path)
             prev_cursor = query.cursor()
     return paths
Example #58
0
 def configure_active_review_1_4(self, unit, review_contents):
     self.template_value['assessment_script_src'] = (
         self.get_course().get_review_form_filename(unit.unit_id))
     saved_answers = (
         StudentWorkUtils.get_answer_list(review_contents)
         if review_contents else [])
     self.template_value['saved_answers'] = transforms.dumps(saved_answers)