def update_answer_form(answer, form, question=None): if answer[ 'type'] == 'answer-record-type%3Ashort-text-answer%40ODL.MIT.EDU': form.set_text(answer['responseString']) elif answer[ 'type'] == 'answer-record-type%3Alabel-ortho-faces%40ODL.MIT.EDU': if 'integerValues' in answer: form.set_face_values( front_face_value=answer['integerValues']['frontFaceValue'], side_face_value=answer['integerValues']['sideFaceValue'], top_face_value=answer['integerValues']['topFaceValue']) elif answer['type'] == 'answer-record-type%3Aeuler-rotation%40ODL.MIT.EDU': if 'integerValues' in answer: form.set_euler_angle_values( x_angle=answer['integerValues']['xAngle'], y_angle=answer['integerValues']['yAngle'], z_angle=answer['integerValues']['zAngle']) elif (answer['type'] == 'answer-record-type%3Amulti-choice-ortho%40ODL.MIT.EDU' or answer['type'] == 'answer-record-type%3Amulti-choice-edx%40ODL.MIT.EDU'): if question is None and 'choiceId' in answer: raise InvalidArgument( 'Missing question parameter for multi-choice') if not form.is_for_update(): gutils.verify_keys_present(answer, ['choiceId']) if 'choiceId' in answer: # need to find the actual choiceIds (MC3 IDs), and match the index # to the one(s) passed in as part of the answer choices = question.get_choices() if int(answer['choiceId']) > len(choices): raise KeyError('Correct answer ' + str(answer['choiceId']) + ' is not valid. ' 'Not that many choices!') elif int(answer['choiceId']) < 1: raise KeyError('Correct answer ' + str(answer['choiceId']) + ' is not valid. ' 'Must be between 1 and # of choices.') # choices are 0 indexed choice_id = choices[int(answer['choiceId']) - 1] # not sure if we need the OSID Id or string form.add_choice_id( choice_id['id'] ) # just include the MongoDB ObjectId, not the whole dict elif answer[ 'type'] == 'answer-record-type%3Afiles-submission%40ODL.MIT.EDU': # no correct answers here... return form else: raise Unsupported() return form
def post(self, request, gradebook_id=None, format=None): try: if gradebook_id is None: gutils.verify_keys_present(self.data, ['gradebookId']) gradebook_id = self.data['gradebookId'] gutils.verify_at_least_one_key_present( self.data, ['displayName', 'description']) gradebook = self.gm.get_gradebook(gutils.clean_id(gradebook_id)) form = gradebook.get_grade_system_form_for_create([]) form = gutils.set_form_basics(form, self.data) check_scores = True if 'basedOnGrades' in self.data: form.set_based_on_grades(bool(self.data['basedOnGrades'])) if self.data['basedOnGrades']: check_scores = False if check_scores: grutils.check_numeric_score_inputs(self.data) form.set_highest_numeric_score(float( self.data['highestScore'])) form.set_lowest_numeric_score(float(self.data['lowestScore'])) form.set_numeric_score_increment( float(self.data['scoreIncrement'])) grade_system = gradebook.create_grade_system(form) if not check_scores: grutils.check_grade_inputs(self.data) grutils.add_grades_to_grade_system(gradebook, grade_system, self.data) grade_system = gradebook.get_grade_system(grade_system.ident) return gutils.CreatedResponse(grade_system.object_map) except (PermissionDenied, InvalidArgument, KeyError) as ex: try: gradebook.delete_grade_system(grade_system.ident) except NameError: pass gutils.handle_exceptions(ex)
def post(self, request, gradebook_id=None, format=None): try: if gradebook_id is None: gutils.verify_keys_present(self.data, ['gradebookId']) gradebook_id = self.data['gradebookId'] gutils.verify_keys_present(self.data, ['gradeSystemId']) gradebook = self.gm.get_gradebook(gutils.clean_id(gradebook_id)) form = gradebook.get_gradebook_column_form_for_create([]) form = gutils.set_form_basics(form, self.data) form.set_grade_system(gutils.clean_id(self.data['gradeSystemId'])) column = gradebook.create_gradebook_column(form) return gutils.CreatedResponse(column.object_map) except (PermissionDenied, InvalidArgument, KeyError) as ex: gutils.handle_exceptions(ex)
def post(self, request, column_id=None, format=None): try: if column_id is None: gutils.verify_keys_present(self.data, ['gradebookColumnId']) column_id = self.data['gradebookColumnId'] gutils.verify_at_least_one_key_present( self.data, ['grade', 'score', 'ignoredForCalculations']) gutils.verify_keys_present(self.data, ['resourceId']) gradebook = grutils.get_object_gradebook(self.gm, column_id, 'gradebook_column') column = gradebook.get_gradebook_column(gutils.clean_id(column_id)) grutils.validate_score_and_grades_against_system( column.get_grade_system(), self.data) form = gradebook.get_grade_entry_form_for_create( column.ident, gutils.clean_id(self.data['resourceId']), []) form = gutils.set_form_basics(form, self.data) if 'ignoredForCalculations' in self.data: form.set_ignored_for_calculations( bool(self.data['ignoredForCalculations'])) if 'grade' in self.data: form.set_grade(gutils.clean_id(self.data['grade'])) if 'score' in self.data: form.set_score(float(self.data['score'])) entry = gradebook.create_grade_entry(form) return gutils.CreatedResponse(entry.object_map) except (PermissionDenied, InvalidArgument, IllegalState, KeyError) as ex: gutils.handle_exceptions(ex)
def post(self, request, format=None): """ Create a new bin, if authorized """ try: if 'bankId' not in self.data: gutils.verify_keys_present(self.data, ['displayName', 'description']) form = self.gm.get_gradebook_form_for_create([]) finalize_method = self.gm.create_gradebook else: gradebook = self.gm.get_gradebook(Id(self.data['bankId'])) form = self.gm.get_gradebook_form_for_update(gradebook.ident) finalize_method = self.gm.update_gradebook form = gutils.set_form_basics(form, self.data) new_gradebook = gutils.convert_dl_object(finalize_method(form)) return gutils.CreatedResponse(new_gradebook) except (PermissionDenied, InvalidArgument, NotFound, KeyError) as ex: gutils.handle_exceptions(ex)
def update_question_form(request, question, form, create=False): """ Check the create flag--if creating the question, then all 3 viewset files are needed. If not creating, can update only a single file. """ if question[ 'type'] == 'question-record-type%3Ashort-text-answer%40ODL.MIT.EDU': form.set_text(question['questionString']) elif (question['type'] == 'question-record-type%3Alabel-ortho-faces%40ODL.MIT.EDU' or question['type'] == 'question-record-type%3Aeuler-rotation%40ODL.MIT.EDU'): # need to differentiate on create here because update might not use all # the fields, whereas we need to enforce a minimum of data on create if create: if 'questionString' in question: form.set_text(question['questionString']) else: raise NullArgument('questionString') if 'firstAngle' in question: form.set_first_angle_projection(question['firstAngle']) files = request.FILES if 'manip' in files: form.set_manip(DataInputStream(files['manip'])) else: raise NullArgument('manip file') if not ('frontView' in files and 'sideView' in files and 'topView' in files): raise NullArgument( 'All three view set attribute(s) required for Ortho-3D items.' ) else: form.set_ortho_view_set( front_view=DataInputStream(files['frontView']), side_view=DataInputStream(files['sideView']), top_view=DataInputStream(files['topView'])) else: if 'questionString' in question: form.set_text(question['questionString']) if 'firstAngle' in question: form.set_first_angle_projection(question['firstAngle']) files = request.FILES if 'manip' in files: form.set_manip(DataInputStream(files['manip'])) if 'frontView' in files: form.set_ovs_view(DataInputStream(files['frontView']), 'frontView') if 'sideView' in files: form.set_ovs_view(DataInputStream(files['sideView']), 'sideView') if 'topView' in files: form.set_ovs_view(DataInputStream(files['topView']), 'topView') elif question[ 'type'] == 'question-record-type%3Amulti-choice-ortho%40ODL.MIT.EDU': # need to differentiate on create here because update might not use all # the fields, whereas we need to enforce a minimum of data on create if create: if 'questionString' in question: form.set_text(question['questionString']) else: raise NullArgument('questionString') if 'firstAngle' in question: form.set_first_angle_projection(question['firstAngle']) files = request.FILES if 'manip' in files: if 'promptName' in question: manip_name = question['promptName'] else: manip_name = 'A manipulatable' # TODO set the manip name to the question['promptName'] # and find the right choice / ovs to go with it if 'rightAnswer' in question: right_answer_sm, right_answer_lg = get_ovs_file_set( files, question['rightAnswer']) form.set_manip(DataInputStream(files['manip']), DataInputStream(right_answer_sm), DataInputStream(right_answer_lg), manip_name) else: form.set_manip(DataInputStream(files['manip']), name=manip_name) if not ('choice0small' in files and 'choice0big' in files): raise NullArgument( 'At least two choice set attribute(s) required for Ortho-3D items.' ) elif not ('choice1small' in files and 'choice1big' in files): raise NullArgument( 'At least two choice set attribute(s) required for Ortho-3D items.' ) else: choice_files = get_choice_files(files) if len(choice_files.keys()) % 2 != 0: raise NullArgument('Large and small image files') num_files = len(choice_files.keys()) / 2 for i in range(0, num_files): # this goes with the code ~20 lines above, where # the right choice files are saved with the manip... # but, regardless, make a choice for each provided # viewset. Trust the consumer to pair things up # properly. Need the choiceId to set the answer if 'rightAnswer' in question and i == int( question['rightAnswer']): # save this as a choice anyways small_file = DataInputStream( choice_files['choice' + str(i) + 'small']) big_file = DataInputStream( choice_files['choice' + str(i) + 'big']) else: small_file = DataInputStream( choice_files['choice' + str(i) + 'small']) big_file = DataInputStream( choice_files['choice' + str(i) + 'big']) if 'choiceNames' in question: name = question['choiceNames'][i] else: name = '' form.set_ortho_choice(small_asset_data=small_file, large_asset_data=big_file, name=name) else: # is a match the ortho manip, so has choice#manip and # primary object of viewset raise NullArgument('manip file') else: if 'questionString' in question: form.set_text(question['questionString']) if 'firstAngle' in question: form.set_first_angle_projection(question['firstAngle']) files = request.FILES if 'manip' in files: form.set_manip(DataInputStream(files['manip'])) # TODO: change a choice set elif question[ 'type'] == 'question-record-type%3Amulti-choice-edx%40ODL.MIT.EDU': if create: expected = ['questionString', 'choices'] gutils.verify_keys_present(question, expected) should_be_list = ['choices'] gutils.verify_min_length(question, should_be_list, 2) form.set_text(str(question['questionString'])) # files get set after the form is returned, because # need the new_item # now manage the choices for ind, choice in enumerate(question['choices']): if isinstance(choice, dict): form.add_choice( choice.get('text', ''), choice.get('name', 'Choice ' + str(int(ind) + 1))) else: form.add_choice(choice, 'Choice ' + str(int(ind) + 1)) else: if 'questionString' in question: form.set_text(str(question['questionString'])) if 'choices' in question: # delete the old choices first for current_choice in form.my_osid_object_form._my_map[ 'choices']: form.clear_choice(current_choice) # now add the new ones for ind, choice in enumerate(question['choices']): if isinstance(choice, dict): form.add_choice( choice.get('text', ''), choice.get('name', 'Choice ' + str(int(ind) + 1))) else: form.add_choice(choice, 'Choice ' + str(int(ind) + 1)) elif question[ 'type'] == 'question-record-type%3Afiles-submission%40ODL.MIT.EDU': form.set_text(str(question['questionString'])) else: raise Unsupported() return form
def create_new_item(bank, data): if ('question' in data and 'genusTypeId' in data['question'] and 'edx' in data['question']['genusTypeId']): # should have body / setup # should have list of choices # should have set of right answers # metadata (if not present, it is okay): # * max attempts # * weight # * showanswer # * rerandomize # * author username # * student display name # * author comments # * extra python script # any files? form = bank.get_item_form_for_create([EDX_ITEM_RECORD_TYPE]) form.display_name = data['displayName'] form.description = data['description'] form.set_genus_type(EDX_MULTI_CHOICE_PROBLEM_TYPE) if 'learningObjectiveIds' in data: form = set_item_learning_objectives(data, form) expected = ['question'] gutils.verify_keys_present(data, expected) expected = ['questionString'] gutils.verify_keys_present(data['question'], expected) form.add_text(data['question']['questionString'], 'questionString') optional = ['python_script', 'latex', 'edxml', 'solution'] for opt in optional: if opt in data: form.add_text(data[opt], opt) metadata = [ 'attempts', 'markdown', 'rerandomize', 'showanswer', 'weight' ] # 'author','author_comments','student_display_name'] for datum in metadata: if datum in data: method = getattr(form, 'add_' + datum) method(data[datum]) irt = ['difficulty', 'discrimination'] for datum in irt: if datum in data: method = getattr(form, 'set_' + datum + '_value') method(data[datum]) if 'files' in data: files_list = {} for filename, file in data['files'].iteritems(): files_list[filename] = DataInputStream(file) form = add_files_to_form(form, files_list) else: form = bank.get_item_form_for_create([]) form.display_name = str(data['displayName']) form.description = str(data['description']) if 'genusTypeId' in data: form.set_genus_type(Type(data['genusTypeId'])) if 'learningObjectiveIds' in data: form = set_item_learning_objectives(data, form) new_item = bank.create_item(form) return new_item
def post(self, request, bank_id=None, format=None): try: if bank_id is None: expected = ['bankId'] gutils.verify_keys_present(self.data, expected) bank_id = self.data['bankId'] bank = self.am.get_bank(gutils.clean_id(bank_id)) new_item = autils.create_new_item(bank, self.data) # create questions and answers if they are part of the # input data. There must be a better way to figure out # which attributes I should set, given the # question type? if 'question' in self.data: question = self.data['question'] if isinstance(question, basestring): question = json.loads(question) q_type = Type(question['type']) qfc = bank.get_question_form_for_create( item_id=new_item.ident, question_record_types=[q_type]) qfc = autils.update_question_form(request, question, qfc, create=True) if 'genus' in question: qfc.genus_type = Type(question['genus']) if ('fileIds' in new_item.object_map and len(new_item.object_map['fileIds'].keys()) > 0): # add these files to the question, too file_ids = new_item.object_map['fileIds'] qfc = autils.add_file_ids_to_form(qfc, file_ids) new_question = bank.create_question(qfc) if 'answers' in self.data: answers = self.data['answers'] if isinstance(answers, basestring): answers = json.loads(answers) for answer in answers: a_types = autils.get_answer_records(answer) afc = bank.get_answer_form_for_create( new_item.ident, a_types) if 'multi-choice' in answer['type']: # because multiple choice answers need to match to # the actual MC3 ChoiceIds, NOT the index passed # in by the consumer. if not new_question: raise NullArgument('Question') afc = autils.update_answer_form( answer, afc, new_question) else: afc = autils.update_answer_form(answer, afc) afc = autils.set_answer_form_genus_and_feedback( answer, afc) new_answer = bank.create_answer(afc) full_item = bank.get_item(new_item.ident) data = gutils.convert_dl_object(full_item) return gutils.CreatedResponse(data) except (KeyError, IntegrityError, PermissionDenied, Unsupported, InvalidArgument, NullArgument) as ex: gutils.handle_exceptions(ex)