def test_get_questions_by_skill_ids_raise_error(self): with self.assertRaisesRegexp( Exception, 'Question count is too high, please limit the question ' 'count to %d.' % feconf.MAX_QUESTIONS_FETCHABLE_AT_ONE_TIME): question_services.get_questions_by_skill_ids( 25, ['skill_1', 'skill_2'])
def get(self): """Handles GET request.""" # Skill ids are given as a comma separated list because this is # a GET request. skill_ids = self.request.get('skill_ids').split(',') question_count = self.request.get('question_count') fetch_by_difficulty_value = self.request.get('fetch_by_difficulty') if not question_count.isdigit() or int(question_count) <= 0: raise self.InvalidInputException( 'Question count has to be greater than 0') if not (fetch_by_difficulty_value == 'true' or fetch_by_difficulty_value == 'false'): raise self.InvalidInputException( 'fetch_by_difficulty must be true or false') fetch_by_difficulty = (fetch_by_difficulty_value == 'true') questions = ( question_services.get_questions_by_skill_ids( int(question_count), skill_ids, fetch_by_difficulty) ) question_dicts = [question.to_dict() for question in questions] self.values.update({ 'question_dicts': question_dicts }) self.render_json(self.values)
def get(self): """Handles GET request.""" # Skill ids are given as a comma separated list because this is # a GET request. skill_ids = self.request.get('skill_ids').split(',') question_count = self.request.get('question_count') fetch_by_difficulty_value = self.request.get('fetch_by_difficulty') if not question_count.isdigit() or int(question_count) <= 0: raise self.InvalidInputException( 'Question count has to be greater than 0') if fetch_by_difficulty_value not in ('true', 'false'): raise self.InvalidInputException( 'fetch_by_difficulty must be true or false') fetch_by_difficulty = (fetch_by_difficulty_value == 'true') if len(skill_ids) > feconf.MAX_NUMBER_OF_SKILL_IDS: skill_ids = skill_services.filter_skills_by_mastery( self.user_id, skill_ids) questions = (question_services.get_questions_by_skill_ids( int(question_count), skill_ids, fetch_by_difficulty)) random.shuffle(questions) question_dicts = [question.to_dict() for question in questions] self.values.update( {'question_dicts': question_dicts[:feconf.QUESTION_BATCH_SIZE]}) self.render_json(self.values)
def test_get_questions_by_skill_ids(self): question_services.create_new_question_skill_link( self.question_id, 'skill_1') questions, _ = (question_services.get_questions_by_skill_ids( 2, ['skill_1'], '')) self.assertEqual(len(questions), 1) self.assertEqual(questions[0].to_dict(), self.question.to_dict())
def get(self, exploration_id): """Handles GET request.""" start_cursor = self.request.get('cursor') story_id = self.request.get('story_id') story = story_services.get_story_by_id(story_id, strict=False) if story is None: raise self.InvalidInputException if not story.has_exploration(exploration_id): raise self.InvalidInputException pretest_questions, next_start_cursor = ( question_services.get_questions_by_skill_ids( feconf.NUM_PRETEST_QUESTIONS, story.get_prerequisite_skill_ids_for_exp_id(exploration_id), start_cursor)) pretest_question_dicts = [ question.to_dict() for question in pretest_questions ] self.values.update({ 'pretest_question_dicts': pretest_question_dicts, 'next_start_cursor': next_start_cursor }) self.render_json(self.values)
def test_get_questions_by_skill_ids_with_fetch_by_difficulty(self): question_services.create_new_question_skill_link( self.editor_id, self.question_id, 'skill_1', 0.3) question_services.create_new_question_skill_link( self.editor_id, self.question_id_1, 'skill_2', 0.8) question_services.create_new_question_skill_link( self.editor_id, self.question_id_2, 'skill_2', 0.5) questions = question_services.get_questions_by_skill_ids( 2, ['skill_1', 'skill_2'], True) questions.sort(key=lambda question: question.last_updated) self.assertEqual(len(questions), 2) self.assertEqual(questions[0].to_dict(), self.question.to_dict()) self.assertEqual(questions[1].to_dict(), self.question_2.to_dict())
def test_get_questions_by_skill_ids(self): question_services.create_new_question_skill_link( self.editor_id, self.question_id, 'skill_1', 0.3) question_services.create_new_question_skill_link( self.editor_id, self.question_id_1, 'skill_2', 0.8) question_services.create_new_question_skill_link( self.editor_id, self.question_id_2, 'skill_2', 0.5) questions = question_services.get_questions_by_skill_ids( 4, ['skill_1', 'skill_2']) questions.sort(key=lambda question: question.last_updated) self.assertEqual(len(questions), 3) self.assertEqual(questions[0].to_dict(), self.question.to_dict()) self.assertEqual(questions[1].to_dict(), self.question_1.to_dict()) self.assertEqual(questions[2].to_dict(), self.question_2.to_dict())
def get(self, exploration_id): """Handles GET request.""" story_url_fragment = self.request.get('story_url_fragment') story = story_fetchers.get_story_by_url_fragment(story_url_fragment) if story is None: raise self.InvalidInputException if not story.has_exploration(exploration_id): raise self.InvalidInputException pretest_questions = (question_services.get_questions_by_skill_ids( feconf.NUM_PRETEST_QUESTIONS, story.get_prerequisite_skill_ids_for_exp_id(exploration_id), True)) question_dicts = [question.to_dict() for question in pretest_questions] self.values.update({ 'pretest_question_dicts': question_dicts, }) self.render_json(self.values)
def post(self, story_id, node_id): story = story_fetchers.get_story_by_id(story_id) completed_nodes = story_fetchers.get_completed_nodes_in_story( self.user_id, story_id) completed_node_ids = [ completed_node.id for completed_node in completed_nodes ] ordered_nodes = story.story_contents.get_ordered_nodes() (next_exp_ids, next_node_id, completed_node_ids) = (self._record_node_completion( story_id, node_id, completed_node_ids, ordered_nodes)) ready_for_review_test = False exp_summaries = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( next_exp_ids)) # If there are no questions for any of the acquired skills that the # learner has completed, do not show review tests. acquired_skills = skill_fetchers.get_multi_skills( story.get_acquired_skill_ids_for_node_ids(completed_node_ids)) acquired_skill_ids = [skill.id for skill in acquired_skills] questions_available = len( question_services.get_questions_by_skill_ids( 1, acquired_skill_ids, False)) > 0 learner_completed_story = len(completed_node_ids) == len(ordered_nodes) learner_at_review_point_in_story = ( len(exp_summaries) != 0 and (len(completed_node_ids) & constants.NUM_EXPLORATIONS_PER_REVIEW_TEST == 0)) if questions_available and (learner_at_review_point_in_story or learner_completed_story): ready_for_review_test = True return self.render_json({ 'summaries': exp_summaries, 'ready_for_review_test': ready_for_review_test, 'next_node_id': next_node_id })
def post(self, story_id, node_id): story = story_fetchers.get_story_by_id(story_id) if story is None: logging.error('Could not find a story corresponding to ' '%s id.' % story_id) self.render_json({}) return topic = topic_fetchers.get_topic_by_id(story.corresponding_topic_id) completed_nodes = story_fetchers.get_completed_nodes_in_story( self.user_id, story_id) completed_node_ids = [ completed_node.id for completed_node in completed_nodes ] ordered_nodes = story.story_contents.get_ordered_nodes() (next_exp_ids, next_node_id, completed_node_ids) = (self._record_node_completion( story_id, node_id, completed_node_ids, ordered_nodes)) ready_for_review_test = False exp_summaries = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( next_exp_ids)) # If there are no questions for any of the acquired skills that the # learner has completed, do not show review tests. acquired_skills = skill_fetchers.get_multi_skills( story.get_acquired_skill_ids_for_node_ids(completed_node_ids)) acquired_skill_ids = [skill.id for skill in acquired_skills] questions_available = len( question_services.get_questions_by_skill_ids( 1, acquired_skill_ids, False)) > 0 learner_completed_story = len(completed_node_ids) == len(ordered_nodes) learner_at_review_point_in_story = ( len(exp_summaries) != 0 and (len(completed_node_ids) & constants.NUM_EXPLORATIONS_PER_REVIEW_TEST == 0)) if questions_available and (learner_at_review_point_in_story or learner_completed_story): ready_for_review_test = True # If there is no next_node_id, the story is marked as completed else # mark the story as incomplete. if next_node_id is None: learner_progress_services.mark_story_as_completed( self.user_id, story_id) else: learner_progress_services.record_story_started( self.user_id, story.id) completed_story_ids = ( learner_progress_services.get_all_completed_story_ids( self.user_id)) story_ids_in_topic = [] for story in topic.canonical_story_references: story_ids_in_topic.append(story.story_id) is_topic_completed = set(story_ids_in_topic).intersection( set(completed_story_ids)) # If at least one story in the topic is completed, # mark the topic as learnt else mark it as partially learnt. if not is_topic_completed: learner_progress_services.record_topic_started( self.user_id, topic.id) else: learner_progress_services.mark_topic_as_learnt( self.user_id, topic.id) return self.render_json({ 'summaries': exp_summaries, 'ready_for_review_test': ready_for_review_test, 'next_node_id': next_node_id })
def post(self, story_id, node_id): if not constants.ENABLE_NEW_STRUCTURE_VIEWER_UPDATES: raise self.PageNotFoundException try: story_fetchers.get_node_index_by_story_id_and_node_id( story_id, node_id) except Exception as e: raise self.PageNotFoundException(e) story = story_fetchers.get_story_by_id(story_id) completed_nodes = story_fetchers.get_completed_nodes_in_story( self.user_id, story_id) completed_node_ids = [ completed_node.id for completed_node in completed_nodes ] ordered_nodes = [ node for node in story.story_contents.get_ordered_nodes() ] next_exp_ids = [] next_node_id = None if not node_id in completed_node_ids: story_services.record_completed_node_in_story_context( self.user_id, story_id, node_id) completed_nodes = story_fetchers.get_completed_nodes_in_story( self.user_id, story_id) completed_node_ids = [ completed_node.id for completed_node in completed_nodes ] for node in ordered_nodes: if node.id not in completed_node_ids: next_exp_ids = [node.exploration_id] next_node_id = node.id break ready_for_review_test = False exp_summaries = ( summary_services.get_displayable_exp_summary_dicts_matching_ids( next_exp_ids)) # If there are no questions for any of the acquired skills that the # learner has completed, do not show review tests. acquired_skills = skill_fetchers.get_multi_skills( story.get_acquired_skill_ids_for_node_ids(completed_node_ids)) acquired_skill_ids = [skill.id for skill in acquired_skills] questions_available = len( question_services.get_questions_by_skill_ids( 1, acquired_skill_ids, False)) > 0 learner_completed_story = len(completed_nodes) == len(ordered_nodes) learner_at_review_point_in_story = ( len(exp_summaries) != 0 and (len(completed_nodes) & constants.NUM_EXPLORATIONS_PER_REVIEW_TEST == 0)) if questions_available and (learner_at_review_point_in_story or learner_completed_story): ready_for_review_test = True return self.render_json({ 'summaries': exp_summaries, 'ready_for_review_test': ready_for_review_test, 'next_node_id': next_node_id })
def get(self, topic_name): """Handles GET requests.""" if not constants.ENABLE_NEW_STRUCTURE_PLAYERS: raise self.PageNotFoundException topic = topic_fetchers.get_topic_by_name(topic_name) canonical_story_ids = topic.get_canonical_story_ids( include_only_published=True) additional_story_ids = topic.get_additional_story_ids( include_only_published=True) canonical_story_summaries = [ story_fetchers.get_story_summary_by_id(canonical_story_id) for canonical_story_id in canonical_story_ids ] additional_story_summaries = [ story_fetchers.get_story_summary_by_id(additional_story_id) for additional_story_id in additional_story_ids ] canonical_story_dicts = [] for story_summary in canonical_story_summaries: completed_node_titles = [ completed_node.title for completed_node in story_fetchers. get_completed_nodes_in_story(self.user_id, story_summary.id) ] story_summary_dict = story_summary.to_human_readable_dict() story_summary_dict['story_is_published'] = True story_summary_dict['completed_node_titles'] = completed_node_titles canonical_story_dicts.append(story_summary_dict) additional_story_dicts = [] for story_summary in additional_story_summaries: completed_node_titles = [ completed_node.title for completed_node in story_fetchers. get_completed_nodes_in_story(self.user_id, story_summary.id) ] story_summary_dict = story_summary.to_human_readable_dict() story_summary_dict['story_is_published'] = True story_summary_dict['completed_node_titles'] = completed_node_titles additional_story_dicts.append(story_summary_dict) uncategorized_skill_ids = topic.get_all_uncategorized_skill_ids() subtopics = topic.get_all_subtopics() all_skill_ids = topic.get_all_skill_ids() skill_descriptions, deleted_skill_ids = ( skill_services.get_descriptions_of_skills(all_skill_ids)) if deleted_skill_ids: deleted_skills_string = ', '.join(deleted_skill_ids) logging.error( 'The deleted skills: %s are still present in topic with id %s' % (deleted_skills_string, topic.id)) if feconf.CAN_SEND_EMAILS: email_manager.send_mail_to_admin( 'Deleted skills present in topic', 'The deleted skills: %s are still present in topic with ' 'id %s' % (deleted_skills_string, topic.id)) if self.user_id: degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.user_id, all_skill_ids) else: degrees_of_mastery = {} for skill_id in all_skill_ids: degrees_of_mastery[skill_id] = None train_tab_should_be_displayed = False if all_skill_ids: questions = question_services.get_questions_by_skill_ids( 5, all_skill_ids, False) if len(questions) == 5: train_tab_should_be_displayed = True self.values.update({ 'topic_id': topic.id, 'topic_name': topic.name, 'topic_description': topic.description, 'canonical_story_dicts': canonical_story_dicts, 'additional_story_dicts': additional_story_dicts, 'uncategorized_skill_ids': uncategorized_skill_ids, 'subtopics': subtopics, 'degrees_of_mastery': degrees_of_mastery, 'skill_descriptions': skill_descriptions, 'train_tab_should_be_displayed': train_tab_should_be_displayed }) self.render_json(self.values)
def get(self, exploration_id): """Populates the data on the individual exploration page. Args: exploration_id: str. The ID of the exploration. """ version = self.request.get('v') story_id = self.request.get('story_id') version = int(version) if version else None try: exploration = exp_services.get_exploration_by_id( exploration_id, version=version) except Exception as e: raise self.PageNotFoundException(e) exploration_rights = rights_manager.get_exploration_rights( exploration_id, strict=False) user_settings = user_services.get_user_settings(self.user_id) preferred_audio_language_code = None if user_settings is not None: preferred_audio_language_code = ( user_settings.preferred_audio_language_code) # Retrieve all classifiers for the exploration. state_classifier_mapping = {} classifier_training_jobs = ( classifier_services.get_classifier_training_jobs( exploration_id, exploration.version, exploration.states)) for index, state_name in enumerate(exploration.states): if classifier_training_jobs[index] is not None: classifier_data = classifier_training_jobs[ index].classifier_data algorithm_id = classifier_training_jobs[index].algorithm_id data_schema_version = ( classifier_training_jobs[index].data_schema_version) state_classifier_mapping[state_name] = { 'algorithm_id': algorithm_id, 'classifier_data': classifier_data, 'data_schema_version': data_schema_version } pretest_question_dicts = [] next_cursor = None if story_id: story = story_services.get_story_by_id(story_id, strict=False) if story is None: raise self.InvalidInputException if not story.has_exploration(exploration_id): raise self.InvalidInputException pretest_questions, next_cursor = ( question_services.get_questions_by_skill_ids( feconf.NUM_PRETEST_QUESTIONS, story.get_prerequisite_skill_ids_for_exp_id(exploration_id), '') ) pretest_question_dicts = [ question.to_dict() for question in pretest_questions ] self.values.update({ 'can_edit': ( rights_manager.check_can_edit_activity( self.user, exploration_rights)), 'exploration': exploration.to_player_dict(), 'exploration_id': exploration_id, 'pretest_question_dicts': pretest_question_dicts, 'next_cursor_for_pretests': next_cursor, 'is_logged_in': bool(self.user_id), 'session_id': utils.generate_new_session_id(), 'version': exploration.version, 'preferred_audio_language_code': preferred_audio_language_code, 'state_classifier_mapping': state_classifier_mapping, 'auto_tts_enabled': exploration.auto_tts_enabled, 'correctness_feedback_enabled': ( exploration.correctness_feedback_enabled), }) self.render_json(self.values)