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')
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)
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)
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
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)
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)
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)
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
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)
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
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
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)
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)
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')
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')
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')
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
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
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())
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')
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())
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())
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')
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())
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)
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)
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)
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)
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)))
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)