def subsection_grade_calculated(subsection_grade): """ Emits an edx.grades.subsection.grade_calculated event with data from the passed subsection_grade. """ event_name = SUBSECTION_GRADE_CALCULATED context = contexts.course_context_from_course_id(subsection_grade.course_id) # TODO (AN-6134): remove this context manager with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': unicode(subsection_grade.user_id), 'course_id': unicode(subsection_grade.course_id), 'block_id': unicode(subsection_grade.usage_key), 'course_version': unicode(subsection_grade.course_version), 'weighted_total_earned': subsection_grade.earned_all, 'weighted_total_possible': subsection_grade.possible_all, 'weighted_graded_earned': subsection_grade.earned_graded, 'weighted_graded_possible': subsection_grade.possible_graded, 'first_attempted': unicode(subsection_grade.first_attempted), 'subtree_edited_timestamp': unicode(subsection_grade.subtree_edited_timestamp), 'event_transaction_id': unicode(get_event_transaction_id()), 'event_transaction_type': unicode(get_event_transaction_type()), 'visible_blocks_hash': unicode(subsection_grade.visible_blocks_id), } )
def _emit_grade_calculated_event(grade): """ Emits an edx.grades.subsection.grade_calculated event with data from the passed grade. """ # TODO: remove this context manager after completion of AN-6134 event_name = u'edx.grades.subsection.grade_calculated' context = contexts.course_context_from_course_id(grade.course_id) with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': unicode(grade.user_id), 'course_id': unicode(grade.course_id), 'block_id': unicode(grade.usage_key), 'course_version': unicode(grade.course_version), 'weighted_total_earned': grade.earned_all, 'weighted_total_possible': grade.possible_all, 'weighted_graded_earned': grade.earned_graded, 'weighted_graded_possible': grade.possible_graded, 'first_attempted': unicode(grade.first_attempted), 'subtree_edited_timestamp': unicode(grade.subtree_edited_timestamp), 'event_transaction_id': unicode(get_event_transaction_id()), 'event_transaction_type': unicode(get_event_transaction_type()), 'visible_blocks_hash': unicode(grade.visible_blocks_id), } )
def subsection_grade_calculated(subsection_grade): """ Emits an edx.grades.subsection.grade_calculated event with data from the passed subsection_grade. """ event_name = SUBSECTION_GRADE_CALCULATED context = contexts.course_context_from_course_id(subsection_grade.course_id) # TODO (AN-6134): remove this context manager with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': six.text_type(subsection_grade.user_id), 'course_id': six.text_type(subsection_grade.course_id), 'block_id': six.text_type(subsection_grade.usage_key), 'course_version': six.text_type(subsection_grade.course_version), 'weighted_total_earned': subsection_grade.earned_all, 'weighted_total_possible': subsection_grade.possible_all, 'weighted_graded_earned': subsection_grade.earned_graded, 'weighted_graded_possible': subsection_grade.possible_graded, 'first_attempted': six.text_type(subsection_grade.first_attempted), 'subtree_edited_timestamp': six.text_type(subsection_grade.subtree_edited_timestamp), 'event_transaction_id': six.text_type(get_event_transaction_id()), 'event_transaction_type': six.text_type(get_event_transaction_type()), 'visible_blocks_hash': six.text_type(subsection_grade.visible_blocks_id), } )
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert (isinstance(self.course_id, CourseKey)) data = { 'user_id': self.user.id, 'course_id': self.course_id.to_deprecated_string(), 'mode': self.mode, } with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) if settings.FEATURES.get( 'SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY: analytics.track( self.user_id, event_name, { 'category': 'conversion', 'label': self.course_id.to_deprecated_string(), 'org': self.course_id.org, 'course': self.course_id.course, 'run': self.course_id.run, 'mode': self.mode, }) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception( 'Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
def publish(block, event_type, event): """A function that allows XModules to publish events.""" if event_type == 'grade' and not is_masquerading_as_specific_student( user, course_id): SCORE_PUBLISHED.send( sender=None, block=block, user=user, raw_earned=event['value'], raw_possible=event['max_value'], only_if_higher=event.get('only_if_higher'), ) else: context = contexts.course_context_from_course_id(course_id) if block.runtime.user_id: context['user_id'] = block.runtime.user_id context['asides'] = {} for aside in block.runtime.get_asides(block): if hasattr(aside, 'get_event_context'): aside_event_info = aside.get_event_context( event_type, event) if aside_event_info is not None: context['asides'][ aside.scope_ids.block_type] = aside_event_info with tracker.get_tracker().context(event_type, context): track_function(event_type, event)
def _emit_grade_calculated_event(grade): """ Emits an edx.grades.course.grade_calculated event with data from the passed grade. """ # TODO: remove this context manager after completion of AN-6134 event_name = u'edx.grades.course.grade_calculated' context = contexts.course_context_from_course_id(grade.course_id) with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': unicode(grade.user_id), 'course_id': unicode(grade.course_id), 'course_version': unicode(grade.course_version), 'percent_grade': grade.percent_grade, 'letter_grade': unicode(grade.letter_grade), 'course_edited_timestamp': unicode(grade.course_edited_timestamp), 'event_transaction_id': unicode(get_event_transaction_id()), 'event_transaction_type': unicode(get_event_transaction_type()), 'grading_policy_hash': unicode(grade.grading_policy_hash), })
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert isinstance(self.course_id, CourseKey) data = {"user_id": self.user.id, "course_id": self.course_id.to_deprecated_string(), "mode": self.mode} with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) if settings.FEATURES.get("SEGMENT_IO_LMS") and settings.SEGMENT_IO_LMS_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.track( self.user_id, event_name, { "category": "conversion", "label": self.course_id.to_deprecated_string(), "org": self.course_id.org, "course": self.course_id.course, "run": self.course_id.run, "mode": self.mode, }, context={"Google Analytics": {"clientId": tracking_context.get("client_id")}}, ) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception( "Unable to emit event %s for user %s and course %s", event_name, self.user.username, self.course_id )
def course_grade_calculated(course_grade): """ Emits an edx.grades.course.grade_calculated event with data from the passed course_grade. """ event_name = COURSE_GRADE_CALCULATED context = contexts.course_context_from_course_id(course_grade.course_id) # TODO (AN-6134): remove this context manager with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': unicode(course_grade.user_id), 'course_id': unicode(course_grade.course_id), 'course_version': unicode(course_grade.course_version), 'percent_grade': course_grade.percent_grade, 'letter_grade': unicode(course_grade.letter_grade), 'course_edited_timestamp': unicode(course_grade.course_edited_timestamp), 'event_transaction_id': unicode(get_event_transaction_id()), 'event_transaction_type': unicode(get_event_transaction_type()), 'grading_policy_hash': unicode(course_grade.grading_policy_hash), })
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert(isinstance(self.course_id, CourseKey)) data = { 'user_id': self.user.id, 'course_id': self.course_id.to_deprecated_string(), 'mode': self.mode, } with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.track(self.user_id, event_name, { 'category': 'conversion', 'label': self.course_id.to_deprecated_string(), 'org': self.course_id.org, 'course': self.course_id.course, 'run': self.course_id.run, 'mode': self.mode, }, context={ 'Google Analytics': { 'clientId': tracking_context.get('client_id') } }) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
def emit_team_event(event_name, course_key, event_data): """ Emit team events with the correct course id context. """ context = contexts.course_context_from_course_id(course_key) with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, event_data)
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) data = {"user_id": self.user.id, "course_id": self.course_id, "mode": self.mode} with tracker.get_tracker().context(event_name, context): server_track(crum.get_current_request(), event_name, data) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception( "Unable to emit event %s for user %s and course %s", event_name, self.user.username, self.course_id )
def publish_event(event_name, result, **kwargs): """ Helper function to publish an event for analytics purposes """ event_data = { "location": unicode(location), "previous_count": previous_count, "result": result, "max_count": max_count, } event_data.update(kwargs) context = contexts.course_context_from_course_id(location.course_key) if user_id: context['user_id'] = user_id full_event_name = "edx.librarycontentblock.content.{}".format(event_name) with tracker.get_tracker().context(full_event_name, context): tracker.emit(full_event_name, event_data)
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert isinstance(self.course_id, SlashSeparatedCourseKey) data = {"user_id": self.user.id, "course_id": self.course_id.to_deprecated_string(), "mode": self.mode} with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception( "Unable to emit event %s for user %s and course %s", event_name, self.user.username, self.course_id )
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) data = { 'user_id': self.user.id, 'course_id': self.course_id, 'mode': self.mode, } with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
def publish(block, event_type, event): """ A function that allows XModules to publish events. """ handle_event = get_event_handler(event_type) if handle_event and not is_masquerading_as_specific_student(user, course_id): handle_event(block, event) else: context = contexts.course_context_from_course_id(course_id) if block.runtime.user_id: context['user_id'] = block.runtime.user_id context['asides'] = {} for aside in block.runtime.get_asides(block): if hasattr(aside, 'get_event_context'): aside_event_info = aside.get_event_context(event_type, event) if aside_event_info is not None: context['asides'][aside.scope_ids.block_type] = aside_event_info with tracker.get_tracker().context(event_type, context): track_function(event_type, event)
def publish(block, event_type, event): """A function that allows XModules to publish events.""" if event_type == 'grade': handle_grade_event(block, event_type, event) elif event_type == 'progress': # expose another special case event type which gets sent # into the CourseCompletions models handle_progress_event(block, event_type, event) else: context = contexts.course_context_from_course_id(course_id) if block.runtime.user_id: context['user_id'] = block.runtime.user_id context['asides'] = {} for aside in block.runtime.get_asides(block): if hasattr(aside, 'get_event_context'): aside_event_info = aside.get_event_context(event_type, event) if aside_event_info is not None: context['asides'][aside.scope_ids.block_type] = aside_event_info with tracker.get_tracker().context(event_type, context): track_function(event_type, event)
def _emit_grade_calculated_event(grade): """ Emits an edx.grades.course.grade_calculated event with data from the passed grade. """ # TODO: remove this context manager after completion of AN-6134 event_name = u'edx.grades.course.grade_calculated' context = contexts.course_context_from_course_id(grade.course_id) with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': unicode(grade.user_id), 'course_id': unicode(grade.course_id), 'course_version': unicode(grade.course_version), 'percent_grade': grade.percent_grade, 'letter_grade': unicode(grade.letter_grade), 'course_edited_timestamp': unicode(grade.course_edited_timestamp), 'event_transaction_id': unicode(get_event_transaction_id()), 'event_transaction_type': unicode(get_event_transaction_type()), 'grading_policy_hash': unicode(grade.grading_policy_hash), } )
def publish(block, event_type, event): """A function that allows XModules to publish events.""" if event_type == 'grade' and not is_masquerading_as_specific_student(user, course_id): SCORE_PUBLISHED.send( sender=None, block=block, user=user, raw_earned=event['value'], raw_possible=event['max_value'], only_if_higher=event.get('only_if_higher'), ) else: context = contexts.course_context_from_course_id(course_id) if block.runtime.user_id: context['user_id'] = block.runtime.user_id context['asides'] = {} for aside in block.runtime.get_asides(block): if hasattr(aside, 'get_event_context'): aside_event_info = aside.get_event_context(event_type, event) if aside_event_info is not None: context['asides'][aside.scope_ids.block_type] = aside_event_info with tracker.get_tracker().context(event_type, context): track_function(event_type, event)
def course_grade_calculated(course_grade): """ Emits an edx.grades.course.grade_calculated event with data from the passed course_grade. """ event_name = COURSE_GRADE_CALCULATED context = contexts.course_context_from_course_id(course_grade.course_id) # TODO (AN-6134): remove this context manager with tracker.get_tracker().context(event_name, context): tracker.emit( event_name, { 'user_id': unicode(course_grade.user_id), 'course_id': unicode(course_grade.course_id), 'course_version': unicode(course_grade.course_version), 'percent_grade': course_grade.percent_grade, 'letter_grade': unicode(course_grade.letter_grade), 'course_edited_timestamp': unicode(course_grade.course_edited_timestamp), 'event_transaction_id': unicode(get_event_transaction_id()), 'event_transaction_type': unicode(get_event_transaction_type()), 'grading_policy_hash': unicode(course_grade.grading_policy_hash), } )
def rescore_problem_module_state(xmodule_instance_args, module_descriptor, student_module, task_input): ''' Takes an XModule descriptor and a corresponding StudentModule object, and performs rescoring on the student's problem submission. Throws exceptions if the rescoring is fatal and should be aborted if in a loop. In particular, raises UpdateProblemModuleStateError if module fails to instantiate, or if the module doesn't support rescoring. Returns True if problem was successfully rescored for the given student, and False if problem encountered some kind of error in rescoring. ''' # unpack the StudentModule: course_id = student_module.course_id student = student_module.student usage_key = student_module.module_state_key with modulestore().bulk_operations(course_id): course = get_course_by_id(course_id) # TODO: Here is a call site where we could pass in a loaded course. I # think we certainly need it since grading is happening here, and field # overrides would be important in handling that correctly instance = _get_module_instance_for_task(course_id, student, module_descriptor, xmodule_instance_args, grade_bucket_type='rescore', course=course) if instance is None: # Either permissions just changed, or someone is trying to be clever # and load something they shouldn't have access to. msg = "No module {loc} for student {student}--access denied?".format( loc=usage_key, student=student) TASK_LOG.warning(msg) return UPDATE_STATUS_FAILED # TODO: (TNL-6594) Remove this switch once rescore_problem support # once CAPA uses ScorableXBlockMixin. for method in ['rescore', 'rescore_problem']: rescore_method = getattr(instance, method, None) if rescore_method is not None: break else: # for-else: Neither method exists on the block. # This should not happen, since it should be already checked in the # caller, but check here to be sure. msg = "Specified problem does not support rescoring." raise UpdateProblemModuleStateError(msg) # TODO: Remove the first part of this if-else with TNL-6594 # We check here to see if the problem has any submissions. If it does not, we don't want to rescore it if hasattr(instance, "done"): if not instance.done: return UPDATE_STATUS_SKIPPED elif not instance.has_submitted_answer(): return UPDATE_STATUS_SKIPPED # Set the tracking info before this call, because it makes downstream # calls that create events. We retrieve and store the id here because # the request cache will be erased during downstream calls. event_transaction_id = create_new_event_transaction_id() set_event_transaction_type(GRADES_RESCORE_EVENT_TYPE) result = rescore_method(only_if_higher=task_input['only_if_higher']) instance.save() if result is None or result.get(u'success') in { u'correct', u'incorrect' }: TASK_LOG.debug( u"successfully processed rescore call for course %(course)s, problem %(loc)s " u"and student %(student)s", dict(course=course_id, loc=usage_key, student=student)) if result is not None: # Only for CAPA. This will get moved to the grade handler. new_weighted_earned, new_weighted_possible = weighted_score( result['new_raw_earned'] if result else None, result['new_raw_possible'] if result else None, module_descriptor.weight, ) # TODO: remove this context manager after completion of AN-6134 context = course_context_from_course_id(course_id) with tracker.get_tracker().context(GRADES_RESCORE_EVENT_TYPE, context): tracker.emit( unicode(GRADES_RESCORE_EVENT_TYPE), { 'course_id': unicode(course_id), 'user_id': unicode(student.id), 'problem_id': unicode(usage_key), 'new_weighted_earned': new_weighted_earned, 'new_weighted_possible': new_weighted_possible, 'only_if_higher': task_input['only_if_higher'], 'instructor_id': unicode(xmodule_instance_args['request_info'] ['user_id']), 'event_transaction_id': unicode(event_transaction_id), 'event_transaction_type': unicode(GRADES_RESCORE_EVENT_TYPE), }) return UPDATE_STATUS_SUCCEEDED else: TASK_LOG.warning( u"error processing rescore call for course %(course)s, problem %(loc)s " u"and student %(student)s: %(msg)s", dict(msg=result.get('success', result), course=course_id, loc=usage_key, student=student)) return UPDATE_STATUS_FAILED