def test_link_multiple_skills_for_question_increments_question_count(self): opportunity_services.create_skill_opportunity(self.SKILL_ID, 'description') self.save_new_question(self.QUESTION_ID, self.USER_ID, self._create_valid_question_data('ABC'), ['skill_2']) question_services.link_multiple_skills_for_question( self.USER_ID, self.QUESTION_ID, [self.SKILL_ID], [0.3]) skill_opportunities, _, _ = ( opportunity_services.get_skill_opportunities(None)) opportunity = skill_opportunities[0] self.assertEqual(opportunity.question_count, 1)
def test_create_multi_question_skill_links_for_question(self): self.question = self.save_new_question( self.question_id, self.editor_id, self._create_valid_question_data('ABC'), ['skill_1']) with self.assertRaisesRegexp( Exception, 'Skill difficulties and skill ids should match. ' 'The lengths of the two lists are different.'): question_services.link_multiple_skills_for_question( self.editor_id, self.question_id, ['skill_1', 'skill_2'], [0.5]) question_services.link_multiple_skills_for_question( self.editor_id, self.question_id, ['skill_1', 'skill_2'], [0.5, 0.7]) skill_ids = [skill.id for skill in question_services.get_skills_linked_to_question( self.question_id)] self.assertItemsEqual(skill_ids, ['skill_1', 'skill_2'])
class QuestionCreationHandler(base.BaseHandler): """A handler that creates the question model given a question dict.""" @acl_decorators.can_manage_question_skill_status def post(self, comma_separated_skill_ids): """Handles POST requests.""" skill_ids = comma_separated_skill_ids.split(',') try: for skill_id in skill_ids: skill_domain.Skill.require_valid_skill_id(skill_id) except Exception: raise self.InvalidInputException try: skill_services.get_multi_skills(skill_ids) except Exception, e: raise self.PageNotFoundException(e) question_dict = self.payload.get('question_dict') if ((question_dict['id'] is not None) or ('question_state_data' not in question_dict) or ('language_code' not in question_dict) or (question_dict['version'] != 1)): raise self.InvalidInputException question_dict['question_state_data_schema_version'] = ( feconf.CURRENT_STATE_SCHEMA_VERSION) question_dict['id'] = question_services.get_new_question_id() question_dict['linked_skill_ids'] = skill_ids try: question = question_domain.Question.from_dict(question_dict) except Exception: raise self.InvalidInputException question_services.add_question(self.user_id, question) # TODO(vinitamurthi): Replace DEFAULT_SKILL_DIFFICULTY # with a value passed from the frontend. question_services.link_multiple_skills_for_question( self.user_id, question.id, skill_ids, [constants.DEFAULT_SKILL_DIFFICULTY] * len(skill_ids)) self.values.update({'question_id': question.id}) self.render_json(self.values)
def post(self): """Handles POST requests.""" skill_ids = self.payload.get('skill_ids') if not skill_ids: raise self.InvalidInputException( 'skill_ids parameter isn\'t present in the payload') if len(skill_ids) > constants.MAX_SKILLS_PER_QUESTION: raise self.InvalidInputException( 'More than %d QuestionSkillLinks for one question ' 'is not supported.' % constants.MAX_SKILLS_PER_QUESTION) try: for skill_id in skill_ids: skill_domain.Skill.require_valid_skill_id(skill_id) except Exception as e: raise self.InvalidInputException('Skill ID(s) aren\'t valid: ', e) try: skill_fetchers.get_multi_skills(skill_ids) except Exception as e: raise self.PageNotFoundException(e) question_dict = self.payload.get('question_dict') if ((question_dict['id'] is not None) or ('question_state_data' not in question_dict) or ('language_code' not in question_dict) or (question_dict['version'] != 0)): raise self.InvalidInputException( 'Question Data should contain id, state data, language code, ' + 'and its version should be set as 0') question_dict['question_state_data_schema_version'] = ( feconf.CURRENT_STATE_SCHEMA_VERSION) question_dict['id'] = question_services.get_new_question_id() question_dict['linked_skill_ids'] = skill_ids try: question = question_domain.Question.from_dict(question_dict) except Exception as e: raise self.InvalidInputException('Question structure is invalid:', e) skill_difficulties = self.payload.get('skill_difficulties') if not skill_difficulties: raise self.InvalidInputException( 'skill_difficulties not present in the payload') if len(skill_ids) != len(skill_difficulties): raise self.InvalidInputException( 'Skill difficulties don\'t match up with skill IDs') try: skill_difficulties = [ float(difficulty) for difficulty in skill_difficulties ] except (ValueError, TypeError) as e: raise self.InvalidInputException( 'Skill difficulties must be a float value') from e if any((difficulty < 0 or difficulty > 1) for difficulty in skill_difficulties): raise self.InvalidInputException( 'Skill difficulties must be between 0 and 1') question_services.add_question(self.user_id, question) question_services.link_multiple_skills_for_question( self.user_id, question.id, skill_ids, skill_difficulties) html_list = question.question_state_data.get_all_html_content_strings() filenames = ( html_cleaner.get_image_filenames_from_html_strings(html_list)) image_validation_error_message_suffix = ( 'Please go to the question editor for question with id %s and edit ' 'the image.' % question.id) for filename in filenames: image = self.request.get(filename) if not image: logging.exception( 'Image not provided for file with name %s when the question' ' with id %s was created.' % (filename, question.id)) raise self.InvalidInputException( 'No image data provided for file with name %s. %s' % (filename, image_validation_error_message_suffix)) try: file_format = ( image_validation_services.validate_image_and_filename( image, filename)) except utils.ValidationError as e: e = '%s %s' % (e, image_validation_error_message_suffix) raise self.InvalidInputException(e) image_is_compressible = (file_format in feconf.COMPRESSIBLE_IMAGE_FORMATS) fs_services.save_original_and_compressed_versions_of_image( filename, feconf.ENTITY_TYPE_QUESTION, question.id, image, 'image', image_is_compressible) self.values.update({'question_id': question.id}) self.render_json(self.values)
def post(self): """Handles POST requests.""" skill_ids = self.payload.get('skill_ids') if not skill_ids: raise self.InvalidInputException( 'skill_ids parameter isn\'t present in the payload') if len(skill_ids) > constants.MAX_SKILLS_PER_QUESTION: raise self.InvalidInputException( 'More than %d QuestionSkillLinks for one question ' 'is not supported.' % constants.MAX_SKILLS_PER_QUESTION) try: for skill_id in skill_ids: skill_domain.Skill.require_valid_skill_id(skill_id) except Exception as e: raise self.InvalidInputException('Skill ID(s) aren\'t valid: ', e) try: skill_services.get_multi_skills(skill_ids) except Exception as e: raise self.PageNotFoundException(e) question_dict = self.payload.get('question_dict') if ((question_dict['id'] is not None) or ('question_state_data' not in question_dict) or ('language_code' not in question_dict) or (question_dict['version'] != 1)): raise self.InvalidInputException( 'Question Data should contain id, state data, language code, ' + 'and its version should be set as 1') question_dict['question_state_data_schema_version'] = ( feconf.CURRENT_STATE_SCHEMA_VERSION) question_dict['id'] = question_services.get_new_question_id() question_dict['linked_skill_ids'] = skill_ids try: question = question_domain.Question.from_dict(question_dict) except Exception as e: raise self.InvalidInputException('Question structure is invalid:', e) skill_difficulties = self.payload.get('skill_difficulties') if not skill_difficulties: raise self.InvalidInputException( 'skill_difficulties not present in the payload') if len(skill_ids) != len(skill_difficulties): raise self.InvalidInputException( 'Skill difficulties don\'t match up with skill IDs') try: skill_difficulties = [ float(difficulty) for difficulty in skill_difficulties ] except (ValueError, TypeError): raise self.InvalidInputException( 'Skill difficulties must be a float value') if any((difficulty < 0 or difficulty > 1) for difficulty in skill_difficulties): raise self.InvalidInputException( 'Skill difficulties must be between 0 and 1') question_services.add_question(self.user_id, question) question_services.link_multiple_skills_for_question( self.user_id, question.id, skill_ids, skill_difficulties) self.values.update({'question_id': question.id}) self.render_json(self.values)