def put(self): """Handles PUT requests.""" mastery_change_per_skill = ( self.payload.get('mastery_change_per_skill')) if (not mastery_change_per_skill or not isinstance(mastery_change_per_skill, dict)): raise self.InvalidInputException( 'Expected payload to contain mastery_change_per_skill ' 'as a dict.') skill_ids = list(mastery_change_per_skill.keys()) current_degrees_of_mastery = ( skill_services.get_multi_user_skill_mastery(self.user_id, skill_ids) ) new_degrees_of_mastery = {} for skill_id in skill_ids: try: skill_domain.Skill.require_valid_skill_id(skill_id) except utils.ValidationError: raise self.InvalidInputException( 'Invalid skill ID %s' % skill_id) # float(bool) will not raise an error. if isinstance(mastery_change_per_skill[skill_id], bool): raise self.InvalidInputException( 'Expected degree of mastery of skill %s to be a number, ' 'received %s.' % (skill_id, mastery_change_per_skill[skill_id])) try: mastery_change_per_skill[skill_id] = ( float(mastery_change_per_skill[skill_id])) except (TypeError, ValueError): raise self.InvalidInputException( 'Expected degree of mastery of skill %s to be a number, ' 'received %s.' % (skill_id, mastery_change_per_skill[skill_id])) if current_degrees_of_mastery[skill_id] is None: current_degrees_of_mastery[skill_id] = 0.0 new_degrees_of_mastery[skill_id] = ( current_degrees_of_mastery[skill_id] + mastery_change_per_skill[skill_id]) if new_degrees_of_mastery[skill_id] < 0.0: new_degrees_of_mastery[skill_id] = 0.0 elif new_degrees_of_mastery[skill_id] > 1.0: new_degrees_of_mastery[skill_id] = 1.0 try: skill_fetchers.get_multi_skills(skill_ids) except Exception as e: raise self.PageNotFoundException(e) skill_services.create_multi_user_skill_mastery( self.user_id, new_degrees_of_mastery) self.render_json({})
def test_put_with_skill_mastery_lower_than_zero(self): skill_services.create_user_skill_mastery(self.user_id, self.skill_id_1, self.degree_of_mastery_1) skill_services.create_user_skill_mastery(self.user_id, self.skill_id_2, self.degree_of_mastery_2) payload = {} mastery_change_per_skill = { self.skill_id_1: -0.5, self.skill_id_2: 0.3 } payload['mastery_change_per_skill'] = mastery_change_per_skill self.login(self.NEW_USER_EMAIL) csrf_token = self.get_new_csrf_token() self.put_json('%s' % feconf.SKILL_MASTERY_DATA_URL, payload, csrf_token=csrf_token) degrees_of_mastery = {self.skill_id_1: 0.0, self.skill_id_2: 0.8} self.assertEqual( skill_services.get_multi_user_skill_mastery( self.user_id, [self.skill_id_1, self.skill_id_2]), degrees_of_mastery) self.logout()
def get(self): """Handles GET requests.""" comma_separated_topic_ids = ( self.request.get('comma_separated_topic_ids')) topic_ids = comma_separated_topic_ids.split(',') topics = topic_fetchers.get_topics_by_ids(topic_ids) all_skill_ids = [] subtopic_mastery_dict = {} for ind, topic in enumerate(topics): if not topic: raise self.InvalidInputException('Invalid topic ID %s' % topic_ids[ind]) all_skill_ids.extend(topic.get_all_skill_ids()) all_skill_ids = list(set(all_skill_ids)) all_skills_mastery_dict = skill_services.get_multi_user_skill_mastery( self.user_id, all_skill_ids) for topic in topics: subtopic_mastery_dict[topic.id] = {} for subtopic in topic.subtopics: skill_mastery_dict = { skill_id: mastery for skill_id, mastery in all_skills_mastery_dict.items() if mastery is not None and skill_id in subtopic.skill_ids } if skill_mastery_dict: # Subtopic mastery is average of skill masteries. subtopic_mastery_dict[topic.id][subtopic.id] = ( python_utils.divide(sum(skill_mastery_dict.values()), len(skill_mastery_dict))) self.values.update({'subtopic_mastery_dict': subtopic_mastery_dict}) self.render_json(self.values)
def get(self): """Handles GET requests.""" comma_separated_skill_ids = ( self.request.get('comma_separated_skill_ids')) if not comma_separated_skill_ids: raise self.InvalidInputException( 'Expected request to contain parameter ' 'comma_separated_skill_ids.') skill_ids = comma_separated_skill_ids.split(',') try: for skill_id in skill_ids: skill_domain.Skill.require_valid_skill_id(skill_id) except utils.ValidationError: raise self.InvalidInputException('Invalid skill ID %s' % skill_id) try: skill_fetchers.get_multi_skills(skill_ids) except Exception as e: raise self.PageNotFoundException(e) degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.user_id, skill_ids) self.values.update({ 'degrees_of_mastery': degrees_of_mastery }) self.render_json(self.values)
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 = [ summary.to_human_readable_dict() for summary in canonical_story_summaries ] additional_story_dicts = [ summary.to_human_readable_dict() for summary in additional_story_summaries ] uncategorized_skill_ids = topic.get_all_uncategorized_skill_ids() subtopics = topic.get_all_subtopics() assigned_skill_ids = topic.get_all_skill_ids() skill_descriptions = skill_services.get_skill_descriptions_by_ids( topic.id, assigned_skill_ids) if self.user_id: degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.user_id, assigned_skill_ids) else: degrees_of_mastery = {} for skill_id in assigned_skill_ids: degrees_of_mastery[skill_id] = None self.values.update({ 'topic_id': topic.id, 'topic_name': topic.name, '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 }) self.render_json(self.values)
def test_get_multi_user_skill_mastery(self): degree_of_mastery = skill_services.get_multi_user_skill_mastery( self.USER_ID, self.SKILL_IDS) self.assertEqual( degree_of_mastery, { self.SKILL_ID_1: self.DEGREE_OF_MASTERY_1, self.SKILL_ID_2: self.DEGREE_OF_MASTERY_2, self.SKILL_ID_3: None })
def test_create_multi_user_skill_mastery(self): skill_id_4 = skill_services.get_new_skill_id() skill_id_5 = skill_services.get_new_skill_id() skill_services.create_multi_user_skill_mastery( self.USER_ID, {skill_id_4: 0.3, skill_id_5: 0.5}) degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.USER_ID, [skill_id_4, skill_id_5]) self.assertEqual( degrees_of_mastery, {skill_id_4: 0.3, skill_id_5: 0.5})
def test_filter_skills_by_mastery(self): # Create feconf.MAX_NUMBER_OF_SKILL_IDS + 3 skill_ids # to test two things: # 1. The skill_ids should be sorted. # 2. The filtered skill_ids should be feconf.MAX_NUMBER_OF_SKILL_IDS # in number. # List of mastery values (float values between 0.0 and 1.0) masteries = [self.DEGREE_OF_MASTERY_1, self.DEGREE_OF_MASTERY_2, None] # Creating feconf.MAX_NUMBER_OF_SKILL_IDS additional user skill # masteries. for _ in python_utils.RANGE(feconf.MAX_NUMBER_OF_SKILL_IDS): skill_id = skill_services.get_new_skill_id() mastery = random.random() masteries.append(mastery) skill_services.create_user_skill_mastery(self.USER_ID, skill_id, mastery) self.SKILL_IDS.append(skill_id) # Sorting the masteries, which should represent the masteries of the # skill_ids that are finally returned. masteries.sort() degrees_of_masteries = skill_services.get_multi_user_skill_mastery( self.USER_ID, self.SKILL_IDS) arranged_filtered_skill_ids = skill_services.filter_skills_by_mastery( self.USER_ID, self.SKILL_IDS) self.assertEqual(len(arranged_filtered_skill_ids), feconf.MAX_NUMBER_OF_SKILL_IDS) # Assert that all the returned skill_ids are a part of the first # feconf.MAX_NUMBER_OF_SKILL_IDS sorted skill_ids. for i in python_utils.RANGE(feconf.MAX_NUMBER_OF_SKILL_IDS): self.assertIn(degrees_of_masteries[arranged_filtered_skill_ids[i]], masteries[:feconf.MAX_NUMBER_OF_SKILL_IDS]) # Testing the arrangement. excluded_skill_ids = list( set(self.SKILL_IDS) - set(arranged_filtered_skill_ids)) for skill_id in excluded_skill_ids: self.SKILL_IDS.remove(skill_id) self.assertEqual(arranged_filtered_skill_ids, self.SKILL_IDS)
def get(self): """Handles GET requests.""" skill_ids = (self.normalized_request.get('selected_skill_ids')) try: for skill_id in skill_ids: skill_domain.Skill.require_valid_skill_id(skill_id) except utils.ValidationError as e: raise self.InvalidInputException('Invalid skill ID %s' % skill_id) from e try: skill_fetchers.get_multi_skills(skill_ids) except Exception as e: raise self.PageNotFoundException(e) from e degrees_of_mastery = skill_services.get_multi_user_skill_mastery( self.user_id, skill_ids) self.values.update({'degrees_of_mastery': degrees_of_mastery}) self.render_json(self.values)
def put(self): """Handles PUT requests.""" mastery_change_per_skill = ( self.normalized_payload.get('mastery_change_per_skill')) skill_ids = list(mastery_change_per_skill.keys()) current_degrees_of_mastery = ( skill_services.get_multi_user_skill_mastery( self.user_id, skill_ids)) new_degrees_of_mastery = {} for skill_id in skill_ids: try: skill_domain.Skill.require_valid_skill_id(skill_id) except utils.ValidationError as e: raise self.InvalidInputException('Invalid skill ID %s' % skill_id) from e if current_degrees_of_mastery[skill_id] is None: current_degrees_of_mastery[skill_id] = 0.0 new_degrees_of_mastery[skill_id] = ( current_degrees_of_mastery[skill_id] + mastery_change_per_skill[skill_id]) if new_degrees_of_mastery[skill_id] < 0.0: new_degrees_of_mastery[skill_id] = 0.0 elif new_degrees_of_mastery[skill_id] > 1.0: new_degrees_of_mastery[skill_id] = 1.0 try: skill_fetchers.get_multi_skills(skill_ids) except Exception as e: raise self.PageNotFoundException(e) from e skill_services.create_multi_user_skill_mastery(self.user_id, new_degrees_of_mastery) self.render_json({})
def get(self, topic_name): """Handles GET requests.""" 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 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, 'practice_tab_is_displayed': topic.practice_tab_is_displayed }) self.render_json(self.values)
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 = [ summary.to_human_readable_dict() for summary in canonical_story_summaries ] additional_story_dicts = [ summary.to_human_readable_dict() for summary in additional_story_summaries ] uncategorized_skill_ids = topic.get_all_uncategorized_skill_ids() subtopics = topic.get_all_subtopics() assigned_skill_ids = topic.get_all_skill_ids() skill_descriptions, deleted_skill_ids = ( skill_services.get_descriptions_of_skills(assigned_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, assigned_skill_ids) else: degrees_of_mastery = {} for skill_id in assigned_skill_ids: degrees_of_mastery[skill_id] = None self.values.update({ 'topic_id': topic.id, 'topic_name': topic.name, '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 }) self.render_json(self.values)