def run(self):
     to_context = sites.get_app_context_for_namespace(self._namespace)
     course = courses.Course(None, app_context=to_context)
     from_context = sites.get_app_context_for_namespace(self._from_namespace)
     start_status = self.load()
     errors = []
     course.import_from(from_context, errors)
     if errors:
         for error in errors:
             logging.error(error)
         raise RuntimeError(
             "Import course from %s to %s job encountered errors; see "
             "App Engine logs for details." % (self._from_namespace, self._namespace)
         )
     elif self._already_finished(start_status.sequence_num):
         # Importing a course takes a good long time -- over 60s
         # for a large course on an F1 instance.  Entirely concievable
         # that an import may have been canceled while import_from()
         # was working.
         raise RuntimeError(
             "Import course from %s to %s job was canceled or "
             "a subsequent run has already completed; not saving "
             "this work." % (self._from_namespace, self._namespace)
         )
     else:
         course.save()
    def test_put_with_permission(self):
        # Verify original order before changing things.
        with common_utils.Namespace(self.NAMESPACE):
            ctx = sites.get_app_context_for_namespace(self.NAMESPACE)
            course = courses.Course(None, app_context=ctx)
            units = course.get_units()
            self.assertEquals(3, len(units))
            self.assertEquals(self.unit.unit_id, units[0].unit_id)
            self.assertEquals(self.assessment.unit_id, units[1].unit_id)
            self.assertEquals(self.link.unit_id, units[2].unit_id)

        self._add_reorder_permission()
        self._put({'outline': [
            {'id': self.link.unit_id, 'title': '', 'lessons': []},
            {'id': self.unit.unit_id, 'title': '', 'lessons': []},
            {'id': self.assessment.unit_id, 'title': '', 'lessons': []},
            ]})

        with common_utils.Namespace(self.NAMESPACE):
            ctx = sites.get_app_context_for_namespace(self.NAMESPACE)
            course = courses.Course(None, app_context=ctx)
            units = course.get_units()
            self.assertEquals(3, len(units))
            self.assertEquals(self.link.unit_id, units[0].unit_id)
            self.assertEquals(self.unit.unit_id, units[1].unit_id)
            self.assertEquals(self.assessment.unit_id, units[2].unit_id)
 def run(self):
     to_context = sites.get_app_context_for_namespace(self._namespace)
     course = courses.Course(None, app_context=to_context)
     from_context = sites.get_app_context_for_namespace(
         self._from_namespace)
     start_status = self.load()
     errors = []
     course.import_from(from_context, errors)
     if errors:
         for error in errors:
             logging.error(error)
         raise RuntimeError(
             'Import course from %s to %s job encountered errors; see '
             'App Engine logs for details.' %
             (self._from_namespace, self._namespace))
     elif self._already_finished(start_status.sequence_num):
         # Importing a course takes a good long time -- over 60s
         # for a large course on an F1 instance.  Entirely concievable
         # that an import may have been canceled while import_from()
         # was working.
         raise RuntimeError(
             'Import course from %s to %s job was canceled or '
             'a subsequent run has already completed; not saving '
             'this work.' % (self._from_namespace, self._namespace))
     else:
         course.save()
    def test_editable_perms(self):
        # Verify writablility and effect of write of property.
        # Verify that only writable fields get written
        with actions.OverriddenSchemaPermission(
            'fake_unit_perm', constants.SCOPE_UNIT,
            self.USER_EMAIL, editable_perms=['description']):

            content = self._get(self.unit_url, self.unit.unit_id)
            self.assertIn('description', content)
            self.assertEquals(1, len(content))

            self._put(self.unit_url, self.unit.unit_id, {
                'description': 'foo',
                'title': 'FOO',
                })
            with common_utils.Namespace(self.NAMESPACE):
                ctx = sites.get_app_context_for_namespace(self.NAMESPACE)
                course = courses.Course(None, app_context=ctx)
                unit = course.find_unit_by_id(self.unit.unit_id)
                self.assertEquals(unit.description, 'foo')
                self.assertEquals(unit.title, 'New Unit')

        with actions.OverriddenSchemaPermission(
            'fake_unit_perm', constants.SCOPE_ASSESSMENT,
            self.USER_EMAIL, editable_perms=['assessment/description']):

            content = self._get(self.assessment_url, self.assessment.unit_id)
            self.assertIn('assessment', content)
            self.assertIn('description', content['assessment'])
            self.assertEquals(1, len(content))

            self._put(self.assessment_url, self.assessment.unit_id,
                      {'assessment': {'description': 'bar', 'title': 'BAR'}})
            with common_utils.Namespace(self.NAMESPACE):
                ctx = sites.get_app_context_for_namespace(self.NAMESPACE)
                course = courses.Course(None, app_context=ctx)
                assessment = course.find_unit_by_id(self.assessment.unit_id)
                self.assertEquals(assessment.description, 'bar')
                self.assertEquals(assessment.title, 'New Assessment')

        with actions.OverriddenSchemaPermission(
            'fake_unit_perm', constants.SCOPE_LINK,
            self.USER_EMAIL, editable_perms=['description']):

            content = self._get(self.link_url, self.link.unit_id)
            self.assertIn('description', content)
            self.assertEquals(1, len(content))

            self._put(self.link_url, self.link.unit_id, {
                'description': 'baz',
                'title': 'BAZ',
                })
            with common_utils.Namespace(self.NAMESPACE):
                ctx = sites.get_app_context_for_namespace(self.NAMESPACE)
                course = courses.Course(None, app_context=ctx)
                link = course.find_unit_by_id(self.link.unit_id)
                self.assertEquals(link.description, 'baz')
                self.assertEquals(link.title, 'New Link')
Example #5
0
    def map(entity):
        if entity.completed_count == 0:
            return

        # Get the scoring method
        namespace = namespace_manager.get_namespace()
        app_context = sites.get_app_context_for_namespace(namespace)
        course = courses.Course.get(app_context)
        unit = course.find_unit_by_id(entity.unit_id)
        content = question.SubjectiveAssignmentRESTHandler.get_content(
            course, unit)
        method = content.get('scoring_method')

        # Get the manual evaluation steps
        steps = staff.ManualEvaluationStep.all().filter(
            'manual_evaluation_summary_key =', entity.key()).filter(
                'state =',
                staff.REVIEW_STATE_COMPLETED).filter('removed =', False)

        # Calculate final score
        final_score = manage.Manager.calculate_final_score(steps, method)
        if final_score is None:
            return
        student = models.Student.get(entity.reviewee_key)
        utils.set_score(student, str(entity.unit_id), final_score)
        student.put()
    def run(self):
        now = utc.now_as_datetime()
        namespace = namespace_manager.get_namespace()
        app_context = sites.get_app_context_for_namespace(namespace)
        course = courses.Course.get(app_context)
        env = app_context.get_environ()

        tct = triggers.ContentTrigger
        content_acts = tct.act_on_settings(course, env, now)

        tmt = triggers.MilestoneTrigger
        course_acts = tmt.act_on_settings(course, env, now)

        save_settings = content_acts.num_consumed or course_acts.num_consumed
        if save_settings:
            # At least one of the settings['publish'] triggers was consumed
            # or discarded, so save changes to triggers into the settings.
            settings_saved = course.save_settings(env)
        else:
            settings_saved = False

        save_course = content_acts.num_changed or course_acts.num_changed
        if save_course:
            course.save()

        tct.log_acted_on(
            namespace, content_acts, save_course, settings_saved)
        tmt.log_acted_on(
            namespace, course_acts, save_course, settings_saved)

        common_utils.run_hooks(self.RUN_HOOKS.itervalues(), course)
Example #7
0
    def map(entity):

        namespace = namespace_manager.get_namespace()
        app_context = sites.get_app_context_for_namespace(namespace)
        course = courses.Course.get(app_context)
        unit = course.find_unit_by_id(entity.unit_id)
        if not unit:
            logging.error("Did not find unit for " + entity.key().name())
            return

        if unit.custom_unit_type != (
                question.SubjectiveAssignmentBaseHandler.UNIT_TYPE_ID):
            return

        # Try getting Manual evaluation summary for this
        submission_key = entity.key()
        summary_key_name = staff.ManualEvaluationSummary.key_name(
            submission_key)
        summary = staff.ManualEvaluationSummary.get_by_key_name(
            summary_key_name)
        if not summary:
            # Create the ManualEvaluationSummary object
            student = models.Student.get_student_by_user_id(
                entity.reviewee_key.name())
            manage.Manager.submit_for_evaluation(course, unit, student)
Example #8
0
def get_environ2():
    """Returns currently defined course settings as a dictionary."""
    gDefier_yaml = None
    gDefier_yaml_dict = None
    
    ns = ApplicationContext.get_namespace_name_for_request()
    app_context = sites.get_app_context_for_namespace(ns)

    course_data_filename = sites.abspath(app_context.get_home_folder(), DFR_CONFIG_FILENAME)

    if app_context.fs.isfile(course_data_filename):
        gDefier_yaml = app_context.fs.open(course_data_filename)
    if not gDefier_yaml:
        return deep_dict_merge(gDefier_model.DEFAULT_COURSE_GDEFIER_DICT,
                               [])
    try:
        gDefier_yaml_dict = yaml.safe_load(
            gDefier_yaml.read().decode('utf-8'))
    except Exception as e:  # pylint: disable-msg=broad-except
        logging.info(
            'Error: gDefier.yaml file at %s not accessible, '
            'loading defaults. %s', course_data_filename, e)

    if not gDefier_yaml_dict:
        return deep_dict_merge(gDefier_model.DEFAULT_COURSE_GDEFIER_DICT,
                               [])
    return deep_dict_merge(
        gDefier_yaml_dict, gDefier_model.DEFAULT_COURSE_GDEFIER_DICT)
    def run(self):
        """Index the course."""
        namespace = namespace_manager.get_namespace()
        logging.info('Running indexing job for namespace %s. Incremental: %s',
                     namespace_manager.get_namespace(), self.incremental)
        app_context = sites.get_app_context_for_namespace(namespace)

        # Make a request URL to make sites.get_course_for_current_request work
        sites.set_path_info(app_context.slug)

        indexing_stats = {
            'deleted_docs': 0,
            'num_indexed_docs': 0,
            'doc_types': collections.Counter(),
            'indexing_time_secs': 0,
            'locales': []
        }
        for locale in app_context.get_allowed_locales():
            stats = clear_index(namespace, locale)
            indexing_stats['deleted_docs'] += stats['deleted_docs']
        for locale in app_context.get_allowed_locales():
            app_context.set_current_locale(locale)
            course = courses.Course(None, app_context=app_context)
            stats = index_all_docs(course, self.incremental)
            indexing_stats['num_indexed_docs'] += stats['num_indexed_docs']
            indexing_stats['doc_types'] += stats['doc_types']
            indexing_stats['indexing_time_secs'] += stats['indexing_time_secs']
            indexing_stats['locales'].append(locale)
        return indexing_stats
Example #10
0
 def run(self):
     """Clear the index."""
     namespace = namespace_manager.get_namespace()
     logging.info('Running clearing job for namespace %s.', namespace)
     app_context = sites.get_app_context_for_namespace(namespace)
     course = courses.Course(None, app_context=app_context)
     return clear_index(course)
Example #11
0
    def run(self):
        now = utc.now_as_datetime()
        namespace = namespace_manager.get_namespace()
        app_context = sites.get_app_context_for_namespace(namespace)
        course = courses.Course.get(app_context)
        env = app_context.get_environ()

        tct = triggers.ContentTrigger
        content_acts = tct.act_on_settings(course, env, now)

        tmt = triggers.MilestoneTrigger
        course_acts = tmt.act_on_settings(course, env, now)

        save_settings = content_acts.num_consumed or course_acts.num_consumed
        if save_settings:
            # At least one of the settings['publish'] triggers was consumed
            # or discarded, so save changes to triggers into the settings.
            settings_saved = course.save_settings(env)
        else:
            settings_saved = False

        save_course = content_acts.num_changed or course_acts.num_changed
        if save_course:
            course.save()

        tct.log_acted_on(namespace, content_acts, save_course, settings_saved)
        tmt.log_acted_on(namespace, course_acts, save_course, settings_saved)

        common_utils.run_hooks(self.RUN_HOOKS.itervalues(), course)
Example #12
0
 def run(self):
     """Clear the index."""
     namespace = namespace_manager.get_namespace()
     logging.info('Running clearing job for namespace %s.', namespace)
     app_context = sites.get_app_context_for_namespace(namespace)
     course = courses.Course(None, app_context=app_context)
     return clear_index(course)
Example #13
0
    def map(entity):
        mapper_params = context.get().mapreduce_spec.mapper.params
        namespace = mapper_params['course']
        unit_id = mapper_params['unit_id']
        content = mapper_params['content']
        settings = mapper_params['settings']

        app_context = sites.get_app_context_for_namespace(namespace)
        course = courses.Course(None, app_context=app_context)
        unit = course.find_unit_by_id(str(unit_id))

        submitted_contents = student_work.Submission.get_contents(
            unit.unit_id, entity.get_key())
        if not submitted_contents:
            return
        submission = transforms.loads(submitted_contents)
        if not submission:
            return
        lang = submission.keys()[0]
        code = submission[lang]['code']
        filename = submission[lang]['filename']

        evaluator_id = content.get('evaluator', 'mooshak')
        evaluator_class = evaluator.ProgramEvaluatorRegistory.get(evaluator_id)
        if not evaluator_class:
            return

        old_score = course.get_score(entity, unit.unit_id)
        prog_evaluator = evaluator_class(course, settings, unit, content)
        prog_evaluator.evaluate(entity, False, lang, filename, code)
        new_score = course.get_score(entity, unit.unit_id)
        yield (str(old_score), new_score)
    def run(self):
        """Index the course."""
        namespace = namespace_manager.get_namespace()
        logging.info('Running indexing job for namespace %s. Incremental: %s',
                     namespace_manager.get_namespace(), self.incremental)
        app_context = sites.get_app_context_for_namespace(namespace)

        # Make a request URL to make sites.get_course_for_current_request work
        sites.set_path_info(app_context.slug)

        indexing_stats = {
            'deleted_docs': 0,
            'num_indexed_docs': 0,
            'doc_types': collections.Counter(),
            'indexing_time_secs': 0,
            'locales': []
        }
        for locale in app_context.get_allowed_locales():
            stats = clear_index(namespace, locale)
            indexing_stats['deleted_docs'] += stats['deleted_docs']
        for locale in app_context.get_allowed_locales():
            app_context.set_current_locale(locale)
            course = courses.Course(None, app_context=app_context)
            stats = index_all_docs(course, self.incremental)
            indexing_stats['num_indexed_docs'] += stats['num_indexed_docs']
            indexing_stats['doc_types'] += stats['doc_types']
            indexing_stats['indexing_time_secs'] += stats['indexing_time_secs']
            indexing_stats['locales'].append(locale)
        return indexing_stats
Example #15
0
    def map(entity):
        mapper_params = context.get().mapreduce_spec.mapper.params
        namespace = mapper_params['course']
        unit_id = mapper_params['unit_id']
        ignore_order = mapper_params['ignore_order']

        app_context = sites.get_app_context_for_namespace(namespace)
        course = courses.Course(None, app_context=app_context)
        unit = course.find_unit_by_id(str(unit_id))

        if verify.UNIT_TYPE_ASSESSMENT == unit.type:
            grader = unit.workflow.get_grader()
            if grader == courses.AUTO_GRADER:
                pass
            else:
                return
        else:
            return
        enable_negative_marking = unit.enable_negative_marking

        submission = student_work.Submission.get_contents(
            unit.unit_id, entity.get_key())

        if not submission:
            return

        old_score = course.get_score(entity, unit.unit_id)
        new_score = scorer.score_assessment(submission,
                                            unit.html_content,
                                            enable_negative_marking,
                                            ignore_order=ignore_order)
        utils.set_score(entity, unit.unit_id, new_score)
        entity.put()
        yield (str(old_score), new_score)
Example #16
0
def assign_course_staff(entity):
    """
    Function to assign a submission to a course staff. The entity can be
    either of type ManualEvaluationSummary or of type ManualEvaluationStep
    since both of them have the fields required here.
    """
    unit_id = entity.unit_id
    submission_key = entity.submission_key
    students = entities.get([entity.reviewee_key])
    if not students:
        return False
    student = students[0]

    namespace = namespace_manager.get_namespace()
    if namespace:
        app_context = sites.get_app_context_for_namespace(namespace)
        if app_context:
            course = courses.Course.get(app_context)
            if course:
                unit = course.find_unit_by_id(unit_id)
                if unit and submission_key and student:
                    manage.Manager.find_and_add_evaluator(
                        course, unit, submission_key, student)
                    return True
    logging.error('Could not load unit for entity ' + entity.key().name())
    return False
Example #17
0
    def run(self):
        """Index the course."""
        namespace = namespace_manager.get_namespace()
        logging.info(
            "Running indexing job for namespace %s. Incremental: %s",
            namespace_manager.get_namespace(),
            self.incremental,
        )
        app_context = sites.get_app_context_for_namespace(namespace)

        # Make a request URL to make sites.get_course_for_current_request work
        sites.set_path_info(app_context.slug)

        indexing_stats = {
            "num_indexed_docs": 0,
            "doc_types": collections.Counter(),
            "indexing_time_secs": 0,
            "locales": [],
        }
        for locale in app_context.get_allowed_locales():
            app_context.set_current_locale(locale)
            course = courses.Course(None, app_context=app_context)
            stats = index_all_docs(course, self.incremental)
            indexing_stats["num_indexed_docs"] += stats["num_indexed_docs"]
            indexing_stats["doc_types"] += stats["doc_types"]
            indexing_stats["indexing_time_secs"] += stats["indexing_time_secs"]
            indexing_stats["locales"].append(locale)

        return indexing_stats
Example #18
0
 def run(self):
     """Index the course."""
     namespace = namespace_manager.get_namespace()
     logging.info('Running indexing job for namespace %s. Incremental: %s',
                  namespace_manager.get_namespace(), self.incremental)
     app_context = sites.get_app_context_for_namespace(namespace)
     course = courses.Course(None, app_context=app_context)
     return index_all_docs(course, self.incremental)
Example #19
0
 def run(self):
     """Index the course."""
     namespace = namespace_manager.get_namespace()
     logging.info('Running indexing job for namespace %s. Incremental: %s',
                  namespace_manager.get_namespace(), self.incremental)
     app_context = sites.get_app_context_for_namespace(namespace)
     course = courses.Course(None, app_context=app_context)
     return index_all_docs(course, self.incremental)
Example #20
0
 def get(self):
     namespace = self.request.get('namespace')
     if namespace:
         app_context = sites.get_app_context_for_namespace(namespace)
         if app_context:
             job = FixNumAssigned(app_context)
             job.submit()
             self.response.write('OK\n')
             return
     self.response.write('Failed\n')
Example #21
0
 def get(self):
     namespace = self.request.get('namespace')
     if namespace:
         app_context = sites.get_app_context_for_namespace(namespace)
         if app_context:
             job = FixMissingManualEvaluationSummary(app_context)
             job.submit()
             self.response.write('OK\n')
             return
     self.response.write('Failed\n')
Example #22
0
 def get(self):
     namespace = self.request.get('namespace')
     if namespace:
         app_context = sites.get_app_context_for_namespace(namespace)
         if app_context:
             job = CalculateFinalScore(app_context)
             job.submit()
             self.response.write('OK\n')
             return
     self.response.write('Failed\n')
Example #23
0
    def run(self):
        """Clear the index."""
        namespace = namespace_manager.get_namespace()
        logging.info('Running clearing job for namespace %s.', namespace)
        app_context = sites.get_app_context_for_namespace(namespace)

        clear_stats = {'deleted_docs': 0, 'locales': []}
        for locale in app_context.get_allowed_locales():
            stats = clear_index(namespace, locale)
            clear_stats['deleted_docs'] += stats['deleted_docs']
            clear_stats['locales'].append(locale)

        return clear_stats
Example #24
0
    def run(self):
        """Clear the index."""
        namespace = namespace_manager.get_namespace()
        logging.info("Running clearing job for namespace %s.", namespace)
        app_context = sites.get_app_context_for_namespace(namespace)

        clear_stats = {"deleted_docs": 0, "locales": []}
        for locale in app_context.get_allowed_locales():
            stats = clear_index(namespace, locale)
            clear_stats["deleted_docs"] += stats["deleted_docs"]
            clear_stats["locales"].append(locale)

        return clear_stats
Example #25
0
    def _child_courses_dispatch(cls, handler, child_course_namespaces):
        # First, resolve the target course. The parent has >= 1 candidate
        # children. A candidate course is a match for dispatch if both the
        # course is currently available, and the current user is on the
        # whitelist.
        #
        # If we find a namespace we cannot resolve into a course, child_courses
        # is misconfigured by the admin. We log and 500.
        #
        # If we find any number of matches other than 1, the system is
        # misconfigured by the admin *for a particular user*. In that case, we
        # show the user an error message and encourage them to report the
        # problem to the admin.
        #
        # If we resolve into exactly one course, we apply ENROLLMENT_POLICY to
        # that course and proceed with the redirect flow, passing the slug of
        # the matched course along to get_redirect_url() for handling in
        # concrete AbstractEmbed implementations.
        all_contexts = []
        for namespace in child_course_namespaces:
            child_app_context = sites.get_app_context_for_namespace(namespace)
            if not child_app_context:
                _LOG.error(
                    '%s contains namespace with no associated course: %s',
                    _CHILD_COURSES_NAME, namespace)
                handler.error(500)
                return

            all_contexts.append(child_app_context)

        matches = []
        for app_context in all_contexts:
            course = courses.Course.get(app_context)
            if course.can_enroll_current_user():
                matches.append(course.app_context)

        num_matches = len(matches)
        if num_matches != 1:
            _LOG.error('Must have exactly 1 enrollment target; got %s',
                       num_matches)
            handler.redirect(_ENROLL_ERROR_URL, normalize=False)
            return

        child_app_context = matches[0]
        with common_utils.Namespace(child_app_context.get_namespace_name()):
            cls.ENROLLMENT_POLICY.apply(handler)

        return cls._redirect(handler,
                             normalize=False,
                             target_slug=child_app_context.get_slug())
    def _child_courses_dispatch(cls, handler, child_course_namespaces):
        # First, resolve the target course. The parent has >= 1 candidate
        # children. A candidate course is a match for dispatch if both the
        # course is currently available, and the current user is on the
        # whitelist.
        #
        # If we find a namespace we cannot resolve into a course, child_courses
        # is misconfigured by the admin. We log and 500.
        #
        # If we find any number of matches other than 1, the system is
        # misconfigured by the admin *for a particular user*. In that case, we
        # show the user an error message and encourage them to report the
        # problem to the admin.
        #
        # If we resolve into exactly one course, we apply ENROLLMENT_POLICY to
        # that course and proceed with the redirect flow, passing the slug of
        # the matched course along to get_redirect_url() for handling in
        # concrete AbstractEmbed implementations.
        all_contexts = []
        for namespace in child_course_namespaces:
            child_app_context = sites.get_app_context_for_namespace(namespace)
            if not child_app_context:
                _LOG.error(
                    '%s contains namespace with no associated course: %s',
                    _CHILD_COURSES_NAME, namespace)
                handler.error(500)
                return

            all_contexts.append(child_app_context)

        matches = []
        for app_context in all_contexts:
            course = courses.Course.get(app_context)
            if course.can_enroll_current_user():
                matches.append(course.app_context)

        num_matches = len(matches)
        if num_matches != 1:
            _LOG.error(
                'Must have exactly 1 enrollment target; got %s', num_matches)
            handler.redirect(_ENROLL_ERROR_URL, normalize=False)
            return

        child_app_context = matches[0]
        with common_utils.Namespace(child_app_context.get_namespace_name()):
            cls.ENROLLMENT_POLICY.apply(handler)

        return cls._redirect(
            handler, normalize=False, target_slug=child_app_context.get_slug())
Example #27
0
 def get(self):
     namespace = self.request.get('namespace')
     unit_id = self.request.get('unit')
     if namespace and unit_id:
         app_context = sites.get_app_context_for_namespace(namespace)
         if app_context:
             course = courses.Course(None, app_context=app_context)
             if course:
                 unit = course.find_unit_by_id(str(unit_id))
                 if unit:
                     job = ReevaluateSubmission(app_context, unit_id)
                     job.submit()
                     self.response.write('OK\n')
                     return
     self.response.write('Failed\n')
Example #28
0
    def test_availability_title(self):
        def get_availability_text():
            response = self.get('/modules/admin')
            dom = self.parse_html_string_to_soup(response.body)
            link = dom.select('#availability_ns_' + self.COURSE_NAME)[0]
            return re.sub(r'\s+', ' ', link.text).strip()

        actions.login(self.ADMIN_EMAIL, is_admin=True)
        for policy, settings in courses.COURSE_AVAILABILITY_POLICIES.items():
            # Fetch the instance of the app_context from the per-process
            # cache so that that's the instance that clears its internal
            # cache of settings when we modify the course availability.
            app_context = sites.get_app_context_for_namespace(self.NAMESPACE)
            courses.Course.get(app_context).set_course_availability(policy)
            self.assertEqual(settings['title'], get_availability_text())
Example #29
0
    def test_availability_title(self):
        def get_availability_text():
            response = self.get('/modules/admin')
            dom = self.parse_html_string_to_soup(response.body)
            link = dom.select('#availability_ns_' + self.COURSE_NAME)[0]
            return re.sub(r'\s+', ' ', link.text).strip()

        actions.login(self.ADMIN_EMAIL, is_admin=True)
        for policy, settings in courses.COURSE_AVAILABILITY_POLICIES.items():
            # Fetch the instance of the app_context from the per-process
            # cache so that that's the instance that clears its internal
            # cache of settings when we modify the course availability.
            app_context = sites.get_app_context_for_namespace(self.NAMESPACE)
            courses.Course.get(app_context).set_course_availability(policy)
            self.assertEqual(settings['title'], get_availability_text())
Example #30
0
 def get(self):
     """Endpoint to reassign all submissions assigned to ex-course staff"""
     namespace = self.request.get('namespace')
     if namespace:
         app_context = sites.get_app_context_for_namespace(namespace)
         if app_context:
             course_staff_ids = None
             with Namespace(namespace):
                 staff_list = course_staff.CourseStaff.all().fetch(None)
                 course_staff_ids = [s.user_id for s in staff_list]
             job = ReassignSubmissionByExcludingCourseStaff(
                 app_context,
                 exclude_course_staff_user_ids=course_staff_ids)
             job.submit()
             self.response.write('OK\n')
             return
     self.response.write('Failed\n')
Example #31
0
def reshare_submission_with_evaluator(step):
    """Function to share the step's submission contents with the course staff"""

    unit_id = step.unit_id
    namespace = namespace_manager.get_namespace()
    if namespace:
        app_context = sites.get_app_context_for_namespace(namespace)
        if app_context:
            course = courses.Course.get(app_context)
            if course:
                unit = course.find_unit_by_id(unit_id)
                if unit:
                    content = (
                        question.SubjectiveAssignmentBaseHandler.get_content(
                            course, unit))
                    if question.SubjectiveAssignmentBaseHandler.BLOB != (
                            content.get(
                                question.SubjectiveAssignmentBaseHandler.
                                OPT_QUESTION_TYPE)):
                        # Not a drive type submission, skip.
                        return

                    if transforms.loads(step.drive_permission_list):
                        # Permission list already present, skip.
                        return

                    evaluator = course_staff.CourseStaff.get_by_key_name(
                        step.evaluator)
                    submission_key = step.submission_key
                    submission_contents = (
                        manage.Manager.get_submission_contents_dict(
                            submission_key))

                    if submission_contents and evaluator:
                        drive_permission_list_dump = transforms.dumps(
                            manage.Manager.share_submission_with_evaluator(
                                submission_contents, evaluator.email))

                        step.drive_permission_list = drive_permission_list_dump
                        entities.put([step])
                        return
                    logging.error('Invalid evaluator or submission for step ' +
                                  step.key().name())
                    return
    logging.error('Could not load unit for step ' + step.key())
Example #32
0
    def main(self):
        # By the time main() is invoked, arguments are parsed and available as
        # self.args. If you need more complicated argument validation than
        # argparse gives you, do it here:
        if self.args.batch_size < 1:
            sys.exit('--batch size must be positive')
        if not os.path.isdir(self.args.path):
            sys.exit('Cannot download to %s; Its not a directory' %
                     self.args.path)

        # Arguments passed to etl.py are also parsed and available as
        # self.etl_args. Here we use them to figure out the requested course's
        # namespace.
        namespace = etl_lib.get_context(
            self.etl_args.course_url_prefix).get_namespace_name()

        # Because our models are namespaced, we need to change to the requested
        # course's namespace before doing datastore reads or we won't find its
        # data. Get the current namespace so we can change back when we're done.
        old_namespace = namespace_manager.get_namespace()
        try:
            namespace_manager.set_namespace(namespace)

            app_context = sites.get_app_context_for_namespace(namespace)
            course = courses.Course(None, app_context=app_context)
            if not course:
                return

            units = course.get_units()
            for unit in units:
                if unit.type != 'PA':
                    continue
                content = prog_assignment.ProgAssignmentBaseHandler.get_content(
                    course, unit)
                f = open(
                    self.args.path + '/' + namespace + '-problem-' +
                    str(unit.unit_id), 'w')
                f.write(transforms.dumps(content))

        finally:
            # The current namespace is global state. We must change it back to
            # the old value no matter what to prevent corrupting datastore
            # operations that run after us.
            namespace_manager.set_namespace(old_namespace)
Example #33
0
    def put(self):
        """Handles HTTP PUT verb."""
        request = transforms.loads(self.request.get('request'))
        if not self.assert_xsrf_token_or_fail(request, 'add-course-put', {}):
            return

        if not CoursesPropertyRights.can_add():
            transforms.send_json_response(self, 401, 'Access denied.')
            return

        payload = request.get('payload')
        json_object = transforms.loads(payload)
        name = json_object.get('name')
        title = json_object.get('title')
        admin_email = json_object.get('admin_email')

        # Add the new course entry.
        errors = []
        entry = sites.add_new_course_entry(name, title, admin_email, errors)
        if not entry:
            errors.append('Error adding a new course entry.')
        if errors:
            transforms.send_json_response(self, 412, '\n'.join(errors))
            return

        # We can't expect our new configuration being immediately available due
        # to datastore queries consistency limitations. So we will instantiate
        # our new course here and not use the normal sites.get_all_courses().
        if sites.USE_COURSE_LIST:
            app_context = sites.get_app_context_for_namespace('ns_%s' % name)
        else:
            app_context = sites.get_all_courses(entry)[0]

        # Update course with a new title and admin email.
        new_course = courses.Course(None, app_context=app_context)
        if not new_course.init_new_course_settings(title, admin_email):
            transforms.send_json_response(
                self, 412,
                'Added new course entry, but failed to update title and/or '
                'admin email. The course.yaml file already exists and must be '
                'updated manually.')
            return

        transforms.send_json_response(self, 200, 'Added.', {'entry': entry})
def _count_add(unused_id, utc_date_time):
    """Called back from student lifecycle queue when student (re-)enrolls.

    This callback only increments 'total' and 'adds' counters that already
    exist in the Datastore.
    """
    namespace_name = namespace_manager.get_namespace()
    total_dto = TotalEnrollmentDAO.load_or_default(namespace_name)

    if not total_dto.is_empty:
        TotalEnrollmentDAO.inc(namespace_name)
    elif total_dto.is_missing:
        init_missing_total(
            total_dto, sites.get_app_context_for_namespace(namespace_name))

    # Update today's 'adds' no matter what, because the ComputeCounts
    # MapReduceJob avoids the current day bin, specifically to avoid races
    # with this callback.
    EnrollmentsAddedDAO.inc(namespace_name, utc_date_time)
Example #35
0
def _count_add(unused_id, utc_date_time):
    """Called back from student lifecycle queue when student (re-)enrolls.

    This callback only increments 'total' and 'adds' counters that already
    exist in the Datastore.
    """
    namespace_name = namespace_manager.get_namespace()
    total_dto = TotalEnrollmentDAO.load_or_default(namespace_name)

    if not total_dto.is_empty:
        TotalEnrollmentDAO.inc(namespace_name)
    elif total_dto.is_missing:
        init_missing_total(total_dto,
                           sites.get_app_context_for_namespace(namespace_name))

    # Update today's 'adds' no matter what, because the ComputeCounts
    # MapReduceJob avoids the current day bin, specifically to avoid races
    # with this callback.
    EnrollmentsAddedDAO.inc(namespace_name, utc_date_time)
def _count_drop(unused_id, utc_date_time):
    """Called back from StudentLifecycleObserver when user is unenrolled.

    This callback only decrements 'total' and increments 'drops' counters that
    already exist in the Datastore.
    """
    namespace_name = namespace_manager.get_namespace()
    total_dto = TotalEnrollmentDAO.load_or_default(namespace_name)

    if not total_dto.is_empty:
        TotalEnrollmentDAO.inc(namespace_name, offset=-1)
    elif total_dto.is_missing:
        init_missing_total(
            total_dto, sites.get_app_context_for_namespace(namespace_name))

    # Update today's 'drops' no matter what, because the ComputeCounts
    # MapReduceJob avoids the current day bin, specifically to avoid races
    # with this callback. (Also, the ComputeCounts MapReduceJob does
    # not implement collecting drops at this time.)
    EnrollmentsDroppedDAO.inc(namespace_name, utc_date_time)
Example #37
0
def _count_drop(unused_id, utc_date_time):
    """Called back from StudentLifecycleObserver when user is unenrolled.

    This callback only decrements 'total' and increments 'drops' counters that
    already exist in the Datastore.
    """
    namespace_name = namespace_manager.get_namespace()
    total_dto = TotalEnrollmentDAO.load_or_default(namespace_name)

    if not total_dto.is_empty:
        TotalEnrollmentDAO.inc(namespace_name, offset=-1)
    elif total_dto.is_missing:
        init_missing_total(total_dto,
                           sites.get_app_context_for_namespace(namespace_name))

    # Update today's 'drops' no matter what, because the ComputeCounts
    # MapReduceJob avoids the current day bin, specifically to avoid races
    # with this callback. (Also, the ComputeCounts MapReduceJob does
    # not implement collecting drops at this time.)
    EnrollmentsDroppedDAO.inc(namespace_name, utc_date_time)
Example #38
0
    def bulk_score(cls, csv_list, errors):
        """
        Bulk score assessments by email.

        csv_list should be a dict of the following format:
        [
            [namespace1, email, assessment_id, score],
            .
            .
        ]
        """
        # Split the list by namespace
        csv_dict = dict()
        for entry in csv_list:
            if len(entry) != 4:
                if len(entry) >= 1:
                    errors.append('Invalid row %s' % ','.join(entry))
                continue

            namespace = entry[0].strip()
            if not namespace:
                errors.append('Invalid row %s' % ','.join(entry))
                continue

            score_list = csv_dict.get(namespace, [])
            score_list.append(entry[1:])
            csv_dict[namespace] = score_list

        # Call bulk score by course
        for namespace, score_list in csv_dict.iteritems():
            course_errors = []
            app_context = sites.get_app_context_for_namespace(namespace)
            if not app_context:
                errors.append('Course not found %s ' % namespace)
                continue
            course = courses.Course.get(app_context)
            with Namespace(namespace):
                cls.bulk_score_by_course(course, score_list, course_errors)
                if course_errors:
                    errors.append('Errors for course %s: %s' %
                                  (namespace, transforms.dumps(course_errors)))
Example #39
0
 def set_course_setting(self, namespace, name, value):
     app_context = sites.get_app_context_for_namespace(namespace)
     course = courses.Course.get(app_context)
     settings = course.app_context.get_environ()
     settings['course'][name] = value
     course.save_settings(settings)
 def set_course_setting(self, namespace, name, value):
     app_context = sites.get_app_context_for_namespace(namespace)
     course = courses.Course.get(app_context)
     settings = course.app_context.get_environ()
     settings["course"][name] = value
     course.save_settings(settings)