Example #1
0
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
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
    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)
Example #5
0
    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)
Example #6
0
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
Example #7
0
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
Example #8
0
    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)