def student_view(self, context=None): """ The primary view of the PeerInstructionXBlock, shown to students when viewing courses. """ # convert key into integers as json.dump and json.load convert integer dictionary key into string self.sys_selected_answers = {int(k): v for k, v in self.sys_selected_answers.items()} # generate a random seed for student student_item = self.get_student_item_dict() random.seed(student_item['student_id']) answers = self.get_answers_for_student() html = "" html += self.resource_string("static/html/ubcpi.html") frag = Fragment(html) frag.add_css(self.resource_string("static/css/ubcpi.css")) frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.js") frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-messages.js") frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-sanitize.js") frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-cookies.js") frag.add_javascript_url("//cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js") frag.add_javascript(self.resource_string("static/js/src/d3-pibar.js")) frag.add_javascript(self.resource_string("static/js/src/ubcpi.js")) frag.add_javascript(self.resource_string("static/js/src/ubcpi-answer-result-directive.js")) frag.add_javascript(self.resource_string("static/js/src/ubcpi-barchart-directive.js")) # convert image URLs question = deepcopy(self.question_text) question.update({'image_url': self.get_asset_url(question.get('image_url'))}) options = deepcopy(self.options) for option in options: if option.get('image_url'): option.update({'image_url': self.get_asset_url(option.get('image_url'))}) js_vals = { 'answer_original': answers.get_vote(0), 'rationale_original': answers.get_rationale(0), 'answer_revised': answers.get_vote(1), 'rationale_revised': answers.get_rationale(1), 'display_name': self.display_name, 'question_text': question, 'options': options, 'rationale_size': self.rationale_size, 'all_status': {'NEW': STATUS_NEW, 'ANSWERED': STATUS_ANSWERED, 'REVISED': STATUS_REVISED}, } if answers.has_revision(0) and not answers.has_revision(1): js_vals['other_answers'] = get_other_answers( self.sys_selected_answers, self.seeds, self.get_student_item_dict, self.algo, self.options) # reveal the correct answer in the end if answers.has_revision(1): js_vals['correct_answer'] = self.correct_answer js_vals['correct_rationale'] = self.correct_rationale # Pass the answer to out Javascript frag.initialize_js('PeerInstructionXBlock', js_vals) return frag
def get_persisted_data(self): """ Formats a usable dict based on what data the user has persisted Adds the other answers and correct answer/rationale when needed """ answers = self.get_answers_for_student() ret = { "answer_original": answers.get_vote(0), "rationale_original": answers.get_rationale(0), "answer_revised": answers.get_vote(1), "rationale_revised": answers.get_rationale(1), } if answers.has_revision(0) and not answers.has_revision(1): ret['other_answers'] = get_other_answers( self.sys_selected_answers, self.seeds, self.get_student_item_dict, self.algo, self.options) # reveal the correct answer in the end if answers.has_revision(1): ret['correct_answer'] = self.correct_answer ret['correct_rationale'] = self.correct_rationale return ret
def get_persisted_data(self, other_answers): """ Formats a usable dict based on what data the user has persisted Adds the other answers and correct answer/rationale when needed """ answers = self.get_answers_for_student() pool_count = get_other_answers_count(self.sys_selected_answers, self.seeds, self.get_student_item_dict) ret = { "answer_original": answers.get_vote(0), "rationale_original": answers.get_rationale(0), "answer_revised": answers.get_vote(1), "rationale_revised": answers.get_rationale(1), } if answers.has_revision(0) and not answers.has_revision(1): # If no persisted peer answers, generate new ones. # Could happen if a student completed Step 1 before ubcpi upgraded to persist peer answers. if not other_answers: ret['other_answers'] = get_other_answers( self.sys_selected_answers, self.seeds, self.get_student_item_dict, self.algo, self.options) else: ret['other_answers'] = other_answers ret['alt_answers_available'] = {} # count how many answers we are showing for each option showing_count = {} for ans in ret['other_answers'].get('answers', []): if ans.get('option', None) is not None: showing_count[ans['option']] = showing_count.get(ans['option'], 0) + 1 for key in pool_count: ret['alt_answers_available'][key] = True if pool_count[key] > showing_count.get(key, 0) else False # reveal the correct answer in the end if answers.has_revision(1): ret['correct_answer'] = self.correct_answer ret['correct_rationale'] = self.correct_rationale return ret
def submit_answer(self, data, suffix=''): """ Answer submission handler to process the student answers """ # convert key into integers as json.dump and json.load convert integer dictionary key into string self.sys_selected_answers = {int(k): v for k, v in self.sys_selected_answers.items()} self.record_response(data['q'], data['rationale'], data['status']) answers = self.get_answers_for_student() ret = { "answer_original": answers.get_vote(0), "rationale_original": answers.get_rationale(0), "answer_revised": answers.get_vote(1), "rationale_revised": answers.get_rationale(1), } if answers.has_revision(0) and not answers.has_revision(1): ret['other_answers'] = get_other_answers( self.sys_selected_answers, self.seeds, self.get_student_item_dict, self.algo, self.options) # reveal the correct answer in the end if answers.has_revision(1): ret['correct_answer'] = self.correct_answer ret['correct_rationale'] = self.correct_rationale return ret
def record_response(self, answer, rationale, status): """ Store response from student to the backend Args: answer (int): the option index that student responded rationale (str): the rationale text status (int): the progress status for this student. Possible values are: STATUS_NEW, STATUS_ANSWERED, STATUS_REVISED Raises: PermissionDenied: if we got an invalid status """ answers = self.get_answers_for_student() stats = self.get_current_stats() truncated_rationale, was_truncated = truncate_rationale(rationale) corr_ans_text = '' if self.correct_answer == len(self.options): # handle scenario with no correct answer corr_ans_text = 'n/a' else: corr_ans_text = self.options[self.correct_answer].get('text'), event_dict = { 'answer': answer, 'answer_text': self.options[answer].get('text'), 'rationale': truncated_rationale, 'correct_answer': self.correct_answer, 'correct_answer_text': corr_ans_text, 'correct_rationale': self.correct_rationale, 'truncated': was_truncated } if not answers.has_revision(0) and status == STATUS_NEW: student_item = self.get_student_item_dict() sas_api.add_answer_for_student(student_item, answer, rationale) num_resp = stats['original'].setdefault(answer, 0) stats['original'][answer] = num_resp + 1 offer_answer( self.sys_selected_answers, answer, rationale, student_item['student_id'], self.algo, self.options) self.other_answers_shown = get_other_answers( self.sys_selected_answers, self.seeds, self.get_student_item_dict, self.algo, self.options) event_dict['other_student_responses'] = self.other_answers_shown self.publish_event_from_dict( self.event_namespace + '.original_submitted', event_dict ) return event_dict['other_student_responses'] elif answers.has_revision(0) and not answers.has_revision(1) and status == STATUS_ANSWERED: sas_api.add_answer_for_student(self.get_student_item_dict(), answer, rationale) num_resp = stats['revised'].setdefault(answer, 0) stats['revised'][answer] = num_resp + 1 # Fetch the grade grade = self.get_grade() # Send the grade self.runtime.publish(self, 'grade', {'value': grade, 'max_value': 1}) self.publish_event_from_dict( self.event_namespace + '.revised_submitted', event_dict ) else: raise PermissionDenied
def student_view(self, context=None): """ The primary view of the PeerInstructionXBlock, shown to students when viewing courses. """ # convert key into integers as json.dump and json.load convert integer dictionary key into string self.sys_selected_answers = {int(k): v for k, v in self.sys_selected_answers.items()} # generate a random seed for student student_item = self.get_student_item_dict() random.seed(student_item['student_id']) answers = self.get_answers_for_student() html = "" html += self.resource_string("static/html/ubcpi.html") frag = Fragment(html) frag.add_css(self.resource_string("static/css/ubcpi.css")) frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.js") frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-messages.js") frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-sanitize.js") frag.add_javascript_url("//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-cookies.js") frag.add_javascript_url("//cdnjs.cloudflare.com/ajax/libs/angular-gettext/2.3.8/angular-gettext.min.js") frag.add_javascript_url("//cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js") frag.add_javascript(self.resource_string("static/js/src/d3-pibar.js")) frag.add_javascript(self.resource_string("static/js/src/ubcpi.js")) frag.add_javascript(self.resource_string("static/js/src/ubcpi-answer-result-directive.js")) frag.add_javascript(self.resource_string("static/js/src/ubcpi-barchart-directive.js")) frag.add_javascript(self.resource_string("static/js/src/translations.js")) # convert image URLs question = deepcopy(self.question_text) question.update({'image_url': self.get_asset_url(question.get('image_url'))}) options = deepcopy(self.options) for option in options: if option.get('image_url'): option.update({'image_url': self.get_asset_url(option.get('image_url'))}) js_vals = { 'answer_original': answers.get_vote(0), 'rationale_original': answers.get_rationale(0), 'answer_revised': answers.get_vote(1), 'rationale_revised': answers.get_rationale(1), 'display_name': self.ugettext(self.display_name), 'question_text': question, 'weight': self.weight, 'options': options, 'rationale_size': self.rationale_size, 'user_role': self.get_user_role(), 'all_status': {'NEW': STATUS_NEW, 'ANSWERED': STATUS_ANSWERED, 'REVISED': STATUS_REVISED}, 'lang': translation.get_language(), } if answers.has_revision(0) and not answers.has_revision(1): js_vals['other_answers'] = get_other_answers( self.sys_selected_answers, self.seeds, self.get_student_item_dict, self.algo, self.options) # reveal the correct answer in the end if answers.has_revision(1): js_vals['correct_answer'] = self.correct_answer js_vals['correct_rationale'] = self.correct_rationale # Pass the answer to out Javascript frag.initialize_js('PeerInstructionXBlock', js_vals) self.publish_event_from_dict(self.event_namespace + '.accessed', {}) return frag