def post(self): # Sort questions into a dictionary based on their unit number questions_by_usage_id = event_transforms.get_questions_by_usage_id( self.app_context) sorted_questions_by_unit = self._rearrange_dict_by_field( questions_by_usage_id, 'unit') # Only use Students we generated. students = common_utils.iter_all(models.Student.all().filter( 'email >', 'gen_sample_student_').filter('email <', 'gen_sample_student`')) source = 'submit-assessment' for student in students: user = users.User(email=student.email, _user_id=student.user_id) assessment_data = self._generate_answers(student, sorted_questions_by_unit) for data in assessment_data: EventEntity.record( source, user, transforms.dumps({ 'values': data, 'location': 'AnswerHandler' })) self.redirect(self.request.referer)
def visit_page(self, user, pageURL): source = 'enter-page' data = {} data['user_agent'] = ('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit' '/537.36 (KHTML, like Gecko) Chrome' '/51.0.2704.106 Safari/537.36') data['loc'] = {'page_locale': 'en_US', 'locale': 'en_US', 'region':'null', 'language': 'en-US,en;q=0.8', 'country': 'ZZ', 'city': 'null'} data['location'] = pageURL data_str = transforms.dumps(data) EventEntity.record(source, user, data_str)
def post_save_settings(self): user = self.personalize_page_and_get_enrolled() if not user: return form = self.SettingsForm(self.request.POST) try: report = PartReport.get_by_id(int(form.report_id.data)) except ValueError: report = None if not report: self.abort(404, "That evidence report was not found.") if not self.can_edit(user, report): self.abort(403, "You can't edit that user's report.") if report.assessment_scores: display_field_params = exam_display_choices( report.assessment_scores[0]) form.exam_display.choices = display_field_params['choices'] form.exam_display.default = display_field_params['default'] else: del form.exam_display if not form.validate(): self.redirect('/') return report.units_are_public = form.units_are_public.data report.review_is_public = form.review_is_public.data if report.assessment_scores: report.exam_display = form.exam_display.data report.put() EventEntity.record( 'set-evidence-settings', users.get_current_user(), transforms.dumps({ 'part': report.part, 'slug': report.slug, 'review_is_public': report.review_is_public, 'public': report.units_are_public, 'exam_display': report.exam_display, 'email': user.key().name() })) self.template_value['navbar'] = {} self.template_value['content'] = '''<div class="gcb-aside">OK, saved settings.<br> <a href="/student/home">Back to your account page...</a></div>''' self.render('bare.html')
def run(self): query = EventEntity.all() query.filter('source', 'unenrolled') query.order('-recorded_on') for survey in query.run(): yield transforms.loads(survey.data)
def run(self): """Computes submitted question answers statistics.""" question_stats = self.MultipleChoiceQuestionAggregator(self._course) mapper = models_utils.QueryMapper( EventEntity.all(), batch_size=500, report_every=1000) mapper.run(question_stats.visit) return (question_stats.id_to_questions_dict, question_stats.id_to_assessments_dict)
def visit_page(self, user, pageURL): source = 'enter-page' data = {} data['user_agent'] = ('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit' '/537.36 (KHTML, like Gecko) Chrome' '/51.0.2704.106 Safari/537.36') data['loc'] = { 'page_locale': 'en_US', 'locale': 'en_US', 'region': 'null', 'language': 'en-US,en;q=0.8', 'country': 'ZZ', 'city': 'null' } data['location'] = pageURL data_str = transforms.dumps(data) EventEntity.record(source, user, data_str)
def post(self): """Handles POST requests.""" student = self.personalize_page_and_get_enrolled() if not student: return if not self.assert_xsrf_token_or_fail(self.request, 'student-unenroll'): return form = self.SurveyForm(self.request.POST) if not form.validate(): self.render_form(student, form) return info = { 'email': student.key().name(), 'wikis_posted': student.wikis_posted, } info.update(form.data) # form is good EventEntity.record( 'unenrolled', users.get_current_user(), transforms.dumps(info)) mail.send_mail('*****@*****.**', '*****@*****.**', 'User %s unenrolled' % info['email'], 'Their data:\n%s' % transforms.dumps(info, indent=2)) Student.set_enrollment_status_for_current(False) mailchimp.unsubscribe('pre-reg', student.key().name()) mailchimp.unsubscribe('confirmed', student.key().name()) mailchimp.unsubscribe('for-credit', student.key().name()) mailchimp.subscribe('unenrolled', student.key().name(), student.name) self.template_value['navbar'] = {'registration': True} self.render('unenroll_confirmation.html')
def post(self): # Sort questions into a dictionary based on their unit number questions_by_usage_id = event_transforms.get_questions_by_usage_id( self.app_context) sorted_questions_by_unit = self._rearrange_dict_by_field( questions_by_usage_id, 'unit') # Only use Students we generated. students = common_utils.iter_all(models.Student.all().filter( 'email >', 'gen_sample_student_').filter( 'email <', 'gen_sample_student`')) source = 'submit-assessment' for student in students: user = users.User(email=student.email, _user_id=student.user_id) assessment_data = self._generate_answers(student, sorted_questions_by_unit) for data in assessment_data: EventEntity.record(source, user, transforms.dumps({ 'values': data, 'location': 'AnswerHandler'})) self.redirect(self.request.referer)
def run(self): # find the student's user_id.. student = Student.get_enrolled_student_by_email(self.student_email) if not student: raise ValueError('That student was not found!') user_id = student.user_id query = EventEntity.all() query.filter('user_id', str(user_id)) query.filter('source', 'edit-wiki-page') query.order('-recorded_on') edits = query.run(limit=2000) for edit in edits: fields = transforms.loads(edit.data) fields['recorded_on'] = edit.recorded_on yield fields
def get_activity_scores(cls, student_user_ids, course, force_refresh=True): """Retrieve activity data for student using EventEntity. For each student, launch a Query of EventEntities to retrieve student scores. The Query is launched as a map-reduce background process that will return up to 500 results, reporting back every second. It reports back by calling the map_fn callback, which in turn calls parse_activity scores. As soon as the Query is launched (in the background) the foreground process calls build_missing_scores() to construct a student_answer.dict that will be updated as score data for that student is received. Events properties include a userid (a number) and a source (e.g., tag-assessement), a recorded-on date (timestamp) and data (a dictionary). Here's a typeical data dict: {"loc": {"city": "mililani", "language": "en-US,en;q=0.8", "locale": "en_US", "country": "US", "region": "hi", "long": -158.01528099999999, "lat": 21.451331, "page_locale": "en_US"}, "instanceid": "yOkVTqWogdaF", "quid": "5733935958982656", "score": 1, "location": "https://mobilecsp-201608.appspot.com/mobilecsp/unit?unit=1&lesson=45", "answer": [0, 1, 2, 4], "type": "McQuestion", "user_agent": "Mozilla/5.0 ..."} Note that it includes the unit_id and lesson_id as part of the Url """ # Instantiate parser object cached_date = datetime.datetime.now() activityParser = ActivityScoreParser() if force_refresh: activityParser.params = activityParser.build_additional_mapper_params( course.app_context) # Launch a background Query for each student's activity data. This is expensive. for user_id in student_user_ids: # if GLOBAL_DEBUG: logging.debug('***RAM*** launching a query for student ' + str(user_id)) mapper = models_utils.QueryMapper( EventEntity.all().filter('user_id in', [user_id]) \ .filter('recorded_on >= ', cls.CUTOFF_DATE), \ batch_size=1000, report_every=1000) # Callback function -- e.g., 45-50 callbacks per query def map_fn(activity_attempt): # if GLOBAL_DEBUG: # logging.debug('***RAM*** map_fn ' + str(activity_attempt)) activityParser.parse_activity_scores(activity_attempt) mapper.run(map_fn) # In the foreground create the student_answer_dict, which is stored at: # activity_scores[student][unit][lesson][sequence] where sequence is # the question's sequential position within the lesson. # So each question in the lesson will have a question_answer_dict. activityParser.build_missing_scores() #Lets cache results for each student for user_id in student_user_ids: cached_student_data = {} cached_student_data['date'] = cached_date student = Student.get_by_user_id(user_id) cached_student_data[ 'scores'] = activityParser.activity_scores.get( student.email, {}) cached_student_data[ 'attempts'] = activityParser.num_attempts_dict.get( student.email, {}) MemcacheManager.set( cls._memcache_key_for_student(student.email), cached_student_data) else: uncached_students = [] for student_id in student_user_ids: if student_id != '': student = Student.get_by_user_id(student_id) temp_email = student.email temp_mem = cls._memcache_key_for_student(temp_email) scores_for_student = MemcacheManager.get(temp_mem) if scores_for_student: cached_date = scores_for_student['date'] activityParser.activity_scores[ student_id] = scores_for_student['scores'] activityParser.num_attempts_dict[ student_id] = scores_for_student['scores'] else: uncached_students.append(student_id) if len(uncached_students) > 0: if cached_date == None or datetime.datetime.now( ) < cached_date: cached_date = datetime.datetime.now() activityParser.params = activityParser.build_additional_mapper_params( course.app_context) for user_id in uncached_students: mapper = models_utils.QueryMapper( EventEntity.all().filter('user_id in', [user_id]) \ .filter('recorded_on >= ', cls.CUTOFF_DATE), \ batch_size=1000, report_every=1000) def map_fn(activity_attempt): activityParser.parse_activity_scores(activity_attempt) mapper.run(map_fn) activityParser.build_missing_scores() #Lets cache results for each student for user_id in uncached_students: cached_student_data = {} cached_student_data['date'] = cached_date student = Student.get_by_user_id(user_id) cached_student_data[ 'scores'] = activityParser.activity_scores.get( student.email, {}) MemcacheManager.set( cls._memcache_key_for_student(student.email), cached_student_data) score_data = {} score_data['date'] = cached_date score_data['scores'] = activityParser.activity_scores score_data['attempts'] = activityParser.num_attempts_dict if GLOBAL_DEBUG: logging.debug('***RAM*** get_activity_scores returning scores: ' + str(score_data['scores'])) return score_data
def get_activity_scores(cls, student_user_ids, course, force_refresh = True): """Retrieve activity data for student using EventEntity. For each student, launch a Query of EventEntities to retrieve student scores. The Query is launched as a map-reduce background process that will return up to 500 results, reporting back every second. It reports back by calling the map_fn callback, which in turn calls parse_activity scores. As soon as the Query is launched (in the background) the foreground process calls build_missing_scores() to construct a student_answer.dict that will be updated as score data for that student is received. Events properties include a userid (a number) and a source (e.g., tag-assessement), a recorded-on date (timestamp) and data (a dictionary). Here's a typeical data dict: {"loc": {"city": "mililani", "language": "en-US,en;q=0.8", "locale": "en_US", "country": "US", "region": "hi", "long": -158.01528099999999, "lat": 21.451331, "page_locale": "en_US"}, "instanceid": "yOkVTqWogdaF", "quid": "5733935958982656", "score": 1, "location": "https://mobilecsp-201608.appspot.com/mobilecsp/unit?unit=1&lesson=45", "answer": [0, 1, 2, 4], "type": "McQuestion", "user_agent": "Mozilla/5.0 ..."} Note that it includes the unit_id and lesson_id as part of the Url """ # Instantiate parser object cached_date = datetime.datetime.now() activityParser = ActivityScoreParser() if force_refresh: activityParser.params = activityParser.build_additional_mapper_params(course.app_context) # Launch a background Query for each student's activity data. This is expensive. for user_id in student_user_ids: # if GLOBAL_DEBUG: # logging.debug('***RAM*** launching a query for student ' + str(user_id)) mapper = models_utils.QueryMapper( EventEntity.all().filter('user_id in', [user_id]) \ .filter('recorded_on >= ', cls.CUTOFF_DATE), \ batch_size=1000, report_every=1000) # Callback function -- e.g., 45-50 callbacks per query def map_fn(activity_attempt): # if GLOBAL_DEBUG: # logging.debug('***RAM*** map_fn ' + str(activity_attempt)) activityParser.parse_activity_scores(activity_attempt) mapper.run(map_fn) # In the foreground create the student_answer_dict, which is stored at: # activity_scores[student][unit][lesson][sequence] where sequence is # the question's sequential position within the lesson. # So each question in the lesson will have a question_answer_dict. activityParser.build_missing_scores() #Lets cache results for each student for user_id in student_user_ids: cached_student_data = {} cached_student_data['date'] = cached_date student = Student.get_by_user_id(user_id) cached_student_data['scores'] = activityParser.activity_scores.get(student.email, {}) cached_student_data['attempts'] = activityParser.num_attempts_dict.get(student.email, {}) MemcacheManager.set(cls._memcache_key_for_student(student.email),cached_student_data) else: uncached_students = [] for student_id in student_user_ids: if student_id != '': student = Student.get_by_user_id(student_id) temp_email = student.email temp_mem = cls._memcache_key_for_student(temp_email) scores_for_student = MemcacheManager.get(temp_mem) if scores_for_student: cached_date = scores_for_student['date'] activityParser.activity_scores[student_id] = scores_for_student['scores'] activityParser.num_attempts_dict[student_id] = scores_for_student['scores'] else: uncached_students.append(student_id) if len(uncached_students) > 0: if cached_date == None or datetime.datetime.now() < cached_date: cached_date = datetime.datetime.now() activityParser.params = activityParser.build_additional_mapper_params(course.app_context) for user_id in uncached_students: mapper = models_utils.QueryMapper( EventEntity.all().filter('user_id in', [user_id]) \ .filter('recorded_on >= ', cls.CUTOFF_DATE), \ batch_size=1000, report_every=1000) def map_fn(activity_attempt): activityParser.parse_activity_scores(activity_attempt) mapper.run(map_fn) activityParser.build_missing_scores() #Lets cache results for each student for user_id in uncached_students: cached_student_data = {} cached_student_data['date'] = cached_date student = Student.get_by_user_id(user_id) cached_student_data['scores'] = activityParser.activity_scores.get(student.email, {}) MemcacheManager.set(cls._memcache_key_for_student(student.email),cached_student_data) score_data = {} score_data['date'] = cached_date score_data['scores'] = activityParser.activity_scores score_data['attempts'] = activityParser.num_attempts_dict if GLOBAL_DEBUG: logging.debug('***RAM*** get_activity_scores returning scores: ' + str(score_data['scores'])) return score_data
def get_activity_scores(cls, student_user_ids, course, force_refresh = False): """Retrieve activity data for student using EventEntity""" #instantiate parser object cached_date = datetime.datetime.now() activityParser = ActivityScoreParser() if force_refresh: activityParser.params = activityParser.build_additional_mapper_params(course.app_context) for user_id in student_user_ids: mapper = models_utils.QueryMapper( EventEntity.all().filter('user_id in', [user_id]), batch_size=500, report_every=1000) def map_fn(activity_attempt): activityParser.parse_activity_scores(activity_attempt) mapper.run(map_fn) activityParser.build_missing_scores() #Lets cache results for each student for user_id in student_user_ids: cached_student_data = {} cached_student_data['date'] = cached_date cached_student_data['scores'] = activityParser.activity_scores.get(Student.get_student_by_user_id( user_id).email, {}) MemcacheManager.set(cls._memcache_key_for_student(Student.get_student_by_user_id(user_id).email), cached_student_data) else: uncached_students = [] for student_id in student_user_ids: scores_for_student = MemcacheManager.get(cls._memcache_key_for_student(Student.get_student_by_user_id( student_id).email)) if scores_for_student: cached_date = scores_for_student['date'] activityParser.activity_scores[student_id] = scores_for_student['scores'] else: uncached_students.append(student_id) if len(uncached_students) > 0: if cached_date == None or datetime.datetime.now() < cached_date: cached_date = datetime.datetime.now() activityParser.params = activityParser.build_additional_mapper_params(course.app_context) for user_id in uncached_students: mapper = models_utils.QueryMapper( EventEntity.all().filter('user_id in', [user_id]), batch_size=500, report_every=1000) def map_fn(activity_attempt): activityParser.parse_activity_scores(activity_attempt) mapper.run(map_fn) activityParser.build_missing_scores() #Lets cache results for each student for user_id in uncached_students: cached_student_data = {} cached_student_data['date'] = cached_date cached_student_data['scores'] = activityParser.activity_scores.get(Student.get_student_by_user_id( user_id).email, {}) MemcacheManager.set(cls._memcache_key_for_student(Student.get_student_by_user_id(user_id).email), cached_student_data) score_data = {} score_data['date'] = cached_date score_data['scores'] = activityParser.activity_scores return score_data