def setUp(self): super(TopicServicesUnitTests, self).setUp() self.TOPIC_ID = topic_services.get_new_topic_id() self.topic = self.save_new_topic(self.TOPIC_ID, self.user_id, 'Name', 'Description', [self.story_id_1, self.story_id_2], [self.story_id_3], [self.skill_id]) self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_b = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([user_services.get_username(self.user_id_a)]) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_b = user_services.UserActionsInfo(self.user_id_b) self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
def test_get_topic_by_version(self): topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, self.user_id, 'topic name', 'Description', [], [], [], [], 1) changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE, 'old_value': 'en', 'new_value': 'bn' })] topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, changelist, 'Change language code') topic_v0 = topic_fetchers.get_topic_by_id(topic_id, version=0) topic_v1 = topic_fetchers.get_topic_by_id(topic_id, version=1) self.assertEqual(topic_v1.language_code, 'en') self.assertEqual(topic_v0.language_code, 'bn')
def test_migrate_story_contents_to_latest_schema(self): story_id = story_services.get_new_story_id() topic_id = topic_services.get_new_topic_id() user_id = 'user_id' self.save_new_topic(topic_id, user_id, 'Topic', 'A new topic', [], [], [], [], 0) self.save_new_story(story_id, user_id, 'Title', 'Description', 'Notes', topic_id) story_model = story_models.StoryModel.get(story_id) self.assertEqual(story_model.story_contents_schema_version, 1) swap_story_object = self.swap(story_domain, 'Story', MockStoryObject) current_schema_version_swap = self.swap( feconf, 'CURRENT_STORY_CONTENTS_SCHEMA_VERSION', 2) with swap_story_object, current_schema_version_swap: story = story_fetchers.get_story_from_model(story_model) self.assertEqual(story.story_contents_schema_version, 2)
def test_update_story_with_invalid_corresponding_topic_id_value(self): topic_id = topic_services.get_new_topic_id() story_id = story_services.get_new_story_id() self.save_new_story(story_id, self.USER_ID, 'Title', 'Description', 'Notes', topic_id) changelist = [ story_domain.StoryChange({ 'cmd': story_domain.CMD_ADD_STORY_NODE, 'node_id': self.NODE_ID_1, 'title': 'Title 1' }) ] with self.assertRaisesRegexp( Exception, ('Expected story to only belong to a valid topic, but ' 'found an topic with ID: %s' % topic_id)): story_services.update_story(self.USER_ID, story_id, changelist, 'Added node.')
def setUp(self): super(StoryMigrationOneOffJobTests, self).setUp() # Setup user who will own the test stories. self.signup(self.ALBERT_EMAIL, self.ALBERT_NAME) self.albert_id = self.get_user_id_from_email(self.ALBERT_EMAIL) self.TOPIC_ID = topic_services.get_new_topic_id() self.story_id_1 = 'story_id_1' self.story_id_2 = 'story_id_2' self.story_id_3 = 'story_id_3' self.skill_id_1 = 'skill_id_1' self.skill_id_2 = 'skill_id_2' self.save_new_topic( self.TOPIC_ID, self.albert_id, name='Name', description='Description', canonical_story_ids=[self.story_id_1, self.story_id_2], additional_story_ids=[self.story_id_3], uncategorized_skill_ids=[self.skill_id_1, self.skill_id_2], subtopics=[], next_subtopic_id=1) self.process_and_flush_pending_mapreduce_tasks()
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicEditorControllerTests, self).setUp() self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email( self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_manager = user_services.UserActionsInfo( self.topic_manager_id) self.admin = user_services.UserActionsInfo(self.admin_id) self.new_user = user_services.UserActionsInfo(self.new_user_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill( self.skill_id, self.admin_id, description='Skill Description') self.skill_id_2 = skill_services.get_new_skill_id() self.save_new_skill( self.skill_id_2, self.admin_id, description='Skill Description 2') self.topic_id = topic_services.get_new_topic_id() self.save_new_topic( self.topic_id, self.admin_id, name='Name', abbreviated_name='abbrev', thumbnail_filename=None, description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.skill_id, self.skill_id_2], subtopics=[], next_subtopic_id=1) changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 })] topic_services.update_topic_and_subtopic_pages( self.admin_id, self.topic_id, changelist, 'Added subtopic.')
def test_editable_topic_handler_get(self): skill_services.delete_skill(self.admin_id, self.skill_id_2) # Check that non-admins cannot access the editable topic data. self.login(self.NEW_USER_EMAIL) self.get_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), expected_status_int=401) self.logout() # Check that admins can access the editable topic data. self.login(self.ADMIN_EMAIL) with self.swap(feconf, 'CAN_SEND_EMAILS', True): messages = self.mail_stub.get_sent_messages( to=feconf.ADMIN_EMAIL_ADDRESS) self.assertEqual(len(messages), 0) json_response = self.get_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id)) self.assertEqual(self.topic_id, json_response['topic_dict']['id']) self.assertEqual( 'Skill Description', json_response['skill_id_to_description_dict'][self.skill_id]) messages = self.mail_stub.get_sent_messages( to=feconf.ADMIN_EMAIL_ADDRESS) expected_email_html_body = ('The deleted skills: %s are still' ' present in topic with id %s' % (self.skill_id_2, self.topic_id)) self.assertEqual(len(messages), 1) self.assertIn(expected_email_html_body, messages[0].html.decode()) self.logout() # Check that editable topic handler is accessed only when a topic id # passed has an associated topic. self.login(self.ADMIN_EMAIL) self.get_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, topic_services.get_new_topic_id()), expected_status_int=404) self.logout()
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicsAndSkillsDashboardTests, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_id = topic_services.get_new_topic_id() self.linked_skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.linked_skill_id, self.admin_id, 'Description 3') skill_services.publish_skill(self.linked_skill_id, self.admin_id) self.save_new_topic(self.topic_id, self.admin_id, 'Name', 'abbrev', None, 'Description', [], [], [self.linked_skill_id], [], 1)
def test_skill_which_is_assigned_to_topic_but_not_subtopic(self): skill_id = skill_services.get_new_skill_id() self.save_new_skill( skill_id, self.admin_id, description='DescriptionSkill') topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, self.admin_id, name='TopicName1', description='DescriptionTopic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[skill_id], subtopics=[], next_subtopic_id=1) url = '%s/%s' % ( feconf.SKILL_EDITOR_DATA_URL_PREFIX, skill_id) json_response = self.get_json(url) self.assertEqual(skill_id, json_response['skill']['id']) self.assertIsNone( json_response['assigned_skill_topic_data_dict']['TopicName1']) self.assertEqual( 1, len(json_response['grouped_skill_summaries']['Name'])) self.logout()
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseStoryEditorControllerTests, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.admin = user_services.UserActionsInfo(self.admin_id) self.topic_id = topic_services.get_new_topic_id() self.story_id = story_services.get_new_story_id() self.save_new_story(self.story_id, self.admin_id, self.topic_id) self.save_new_topic( self.topic_id, self.admin_id, name='Name', abbreviated_name='name', url_fragment='name', description='Description', canonical_story_ids=[self.story_id], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=1)
def test_changing_user_role_from_exploration_editor_to_topic_manager(self): user_email = '*****@*****.**' username = '******' self.signup(user_email, username) user_id = self.get_user_id_from_email(self.ADMIN_EMAIL) topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, user_id, name='Name', abbreviated_name='abbrev', thumbnail_filename=None, description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=1) self.login(self.ADMIN_EMAIL, is_super_admin=True) response_dict = self.get_json( feconf.ADMIN_ROLE_HANDLER_URL, params={'method': 'username', 'username': username}) self.assertEqual( response_dict, {username: feconf.ROLE_ID_EXPLORATION_EDITOR}) # Check role correctly gets updated. csrf_token = self.get_new_csrf_token() response_dict = self.post_json( feconf.ADMIN_ROLE_HANDLER_URL, {'role': feconf.ROLE_ID_TOPIC_MANAGER, 'username': username, 'topic_id': topic_id}, csrf_token=csrf_token) self.assertEqual(response_dict, {}) response_dict = self.get_json( feconf.ADMIN_ROLE_HANDLER_URL, params={'method': 'username', 'username': username}) self.assertEqual( response_dict, {username: feconf.ROLE_ID_TOPIC_MANAGER}) self.logout()
def setUp(self): super(StoryFetchersUnitTests, self).setUp() self.STORY_ID = story_services.get_new_story_id() self.TOPIC_ID = topic_services.get_new_topic_id() self.save_new_topic(self.TOPIC_ID, self.USER_ID, name='Topic', description='A new topic', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=0) self.save_new_story(self.STORY_ID, self.USER_ID, 'Title', 'Description', 'Notes', self.TOPIC_ID) topic_services.add_canonical_story(self.USER_ID, self.TOPIC_ID, self.STORY_ID) changelist = [ story_domain.StoryChange({ 'cmd': story_domain.CMD_ADD_STORY_NODE, 'node_id': self.NODE_ID_1, 'title': 'Title 1' }) ] story_services.update_story(self.USER_ID, self.STORY_ID, changelist, 'Added node.') self.story = story_fetchers.get_story_by_id(self.STORY_ID) self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_b = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([user_services.get_username(self.user_id_a)]) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_b = user_services.UserActionsInfo(self.user_id_b) self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicEditorControllerTests, self).setUp() self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_manager = user_services.UserActionsInfo( self.topic_manager_id) self.admin = user_services.UserActionsInfo(self.admin_id) self.new_user = user_services.UserActionsInfo(self.new_user_id) self.skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id, self.admin_id, 'Skill Description') self.skill_id_2 = skill_services.get_new_skill_id() self.save_new_skill(self.skill_id_2, self.admin_id, 'Skill Description 2') self.topic_id = topic_services.get_new_topic_id() self.save_new_topic(self.topic_id, self.admin_id, 'Name', 'Description', [], [], [self.skill_id, self.skill_id_2], [], 1) changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 }) ] topic_services.update_topic_and_subtopic_pages(self.admin_id, self.topic_id, changelist, 'Added subtopic.')
def setUp(self): super(TopicFetchersUnitTests, self).setUp() self.TOPIC_ID = topic_services.get_new_topic_id() changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 })] self.save_new_topic( self.TOPIC_ID, self.user_id, name='Name', abbreviated_name='name', url_fragment='name-one', description='Description', canonical_story_ids=[self.story_id_1, self.story_id_2], additional_story_ids=[self.story_id_3], uncategorized_skill_ids=[self.skill_id_1, self.skill_id_2], subtopics=[], next_subtopic_id=1) self.save_new_story(self.story_id_1, self.user_id, self.TOPIC_ID) self.save_new_story( self.story_id_3, self.user_id, self.TOPIC_ID, title='Title 3', description='Description 3') self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_b = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) topic_services.update_topic_and_subtopic_pages( self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic') self.topic = topic_fetchers.get_topic_by_id(self.TOPIC_ID) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([user_services.get_username(self.user_id_a)]) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_b = user_services.UserActionsInfo(self.user_id_b) self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicEditorControllerTest, self).setUp() self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_manager = user_services.UserActionsInfo( self.topic_manager_id) self.admin = user_services.UserActionsInfo(self.admin_id) self.new_user = user_services.UserActionsInfo(self.new_user_id) self.topic_id = topic_services.get_new_topic_id() self.save_new_topic(self.topic_id, self.admin_id, 'Name', 'Description', [], [], [], [])
def test_job_when_subtopics_do_not_have_math_rich_text(self): topic_id1 = topic_services.get_new_topic_id() subtopic_page1 = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id1)) subtopic_page_services.save_subtopic_page( self.albert_id, subtopic_page1, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Sample' }) ]) job_id = ( topic_jobs_one_off.SubTopicPageMathRteAuditOneOffJob.create_new()) topic_jobs_one_off.SubTopicPageMathRteAuditOneOffJob.enqueue(job_id) self.process_and_flush_pending_tasks() output = (topic_jobs_one_off.SubTopicPageMathRteAuditOneOffJob. get_output(job_id)) self.assertEqual(output, [])
def test_get_topic_by_version(self): topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, self.user_id, name='topic name', abbreviated_name='topic-name', url_fragment='topic-name', description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[], subtopics=[], next_subtopic_id=1) changelist = [topic_domain.TopicChange({ 'cmd': topic_domain.CMD_UPDATE_TOPIC_PROPERTY, 'property_name': topic_domain.TOPIC_PROPERTY_LANGUAGE_CODE, 'old_value': 'en', 'new_value': 'bn' })] topic_services.update_topic_and_subtopic_pages( self.user_id, topic_id, changelist, 'Change language code') topic_v0 = topic_fetchers.get_topic_by_id(topic_id, version=0) topic_v1 = topic_fetchers.get_topic_by_id(topic_id, version=1) self.assertEqual(topic_v1.language_code, 'en') self.assertEqual(topic_v0.language_code, 'bn')
def test_update_story_which_not_corresponding_topic_id(self): topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, self.USER_ID, 'A New Topic', 'A new topic description.', [], [], [], [], 0) story_id = story_services.get_new_story_id() self.save_new_story( story_id, self.USER_ID, 'Title', 'Description', 'Notes', topic_id) changelist = [ story_domain.StoryChange({ 'cmd': story_domain.CMD_ADD_STORY_NODE, 'node_id': self.NODE_ID_1, 'title': 'Title 1' }) ] with self.assertRaisesRegexp( Exception, ('Expected story to belong to the topic %s, but it is ' 'neither a part of the canonical stories or the ' 'additional stories of the topic.' % topic_id)): story_services.update_story( self.USER_ID, story_id, changelist, 'Added node.')
def test_editable_skill_handler_delete_when_associated_topics_exist(self): self.login(self.ADMIN_EMAIL) # Check DELETE removes skill from the topic and returns 200 when the # skill still has associated topics. topic_id = topic_services.get_new_topic_id() self.save_new_topic(topic_id, self.admin_id, name='Topic1', description='Description1', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.skill_id], subtopics=[], next_subtopic_id=1) topic = topic_fetchers.get_topic_by_id(topic_id) self.assertTrue(self.skill_id in topic.get_all_skill_ids()) self.delete_json(self.url, expected_status_int=200) topic = topic_fetchers.get_topic_by_id(topic_id) self.assertFalse(self.skill_id in topic.get_all_skill_ids()) self.logout()
def setUp(self): """Completes the sign-up process for the various users.""" super(BaseTopicsAndSkillsDashboardTests, self).setUp() self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME) self.signup(self.TOPIC_MANAGER_EMAIL, self.TOPIC_MANAGER_USERNAME) self.signup(self.NEW_USER_EMAIL, self.NEW_USER_USERNAME) self.admin_id = self.get_user_id_from_email(self.ADMIN_EMAIL) self.topic_manager_id = self.get_user_id_from_email( self.TOPIC_MANAGER_EMAIL) self.new_user_id = self.get_user_id_from_email(self.NEW_USER_EMAIL) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([self.TOPIC_MANAGER_USERNAME]) self.topic_id = topic_services.get_new_topic_id() self.linked_skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.linked_skill_id, self.admin_id, description='Description 3') self.subtopic_skill_id = skill_services.get_new_skill_id() self.save_new_skill(self.subtopic_skill_id, self.admin_id, description='Subtopic Skill') subtopic = topic_domain.Subtopic.create_default_subtopic( 1, 'Subtopic Title') subtopic.skill_ids = [self.subtopic_skill_id] self.save_new_topic(self.topic_id, self.admin_id, name='Name', abbreviated_name='name', url_fragment='name', description='Description', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.linked_skill_id], subtopics=[subtopic], next_subtopic_id=2)
def test_editable_topic_handler_delete(self): # Check that admins can delete a topic. self.login(self.ADMIN_EMAIL) self.delete_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), expected_status_int=200) self.logout() # Check that non-admins cannot delete a topic. self.login(self.NEW_USER_EMAIL) self.delete_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), expected_status_int=401) self.logout() # Check that topic can not be deleted when the topic id passed does # not have a topic associated with it. self.login(self.ADMIN_EMAIL) self.delete_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, topic_services.get_new_topic_id()), expected_status_int=404) self.logout()
def test_changing_user_role_from_exploration_editor_to_topic_manager(self): user_email = '*****@*****.**' username = '******' self.signup(user_email, username) user_id = self.get_user_id_from_email(self.ADMIN_EMAIL) topic_id = topic_services.get_new_topic_id() self.save_new_topic( topic_id, user_id, 'Name', 'Description', [], [], [], [], 1) self.login(self.ADMIN_EMAIL, is_super_admin=True) response_dict = self.get_json( feconf.ADMIN_ROLE_HANDLER_URL, params={'method': 'username', 'username': username}) self.assertEqual( response_dict, {username: feconf.ROLE_ID_EXPLORATION_EDITOR}) # Check role correctly gets updated. csrf_token = self.get_new_csrf_token() response_dict = self.post_json( feconf.ADMIN_ROLE_HANDLER_URL, {'role': feconf.ROLE_ID_TOPIC_MANAGER, 'username': username, 'topic_id': topic_id}, csrf_token=csrf_token) self.assertEqual(response_dict, {}) response_dict = self.get_json( feconf.ADMIN_ROLE_HANDLER_URL, params={'method': 'username', 'username': username}) self.assertEqual( response_dict, {username: feconf.ROLE_ID_TOPIC_MANAGER}) self.logout()
def setUp(self): super(TopicFetchersUnitTests, self).setUp() self.TOPIC_ID = topic_services.get_new_topic_id() changelist = [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'title': 'Title', 'subtopic_id': 1 }) ] self.save_new_topic(self.TOPIC_ID, self.user_id, 'Name', 'Description', [self.story_id_1, self.story_id_2], [self.story_id_3], [self.skill_id_1, self.skill_id_2], [], 1) self.save_new_story(self.story_id_1, self.user_id, 'Title', 'Description', 'Notes', self.TOPIC_ID) self.save_new_story(self.story_id_3, self.user_id, 'Title 3', 'Description 3', 'Notes', self.TOPIC_ID) self.signup('*****@*****.**', 'A') self.signup('*****@*****.**', 'B') self.signup(self.ADMIN_EMAIL, username=self.ADMIN_USERNAME) self.user_id_a = self.get_user_id_from_email('*****@*****.**') self.user_id_b = self.get_user_id_from_email('*****@*****.**') self.user_id_admin = self.get_user_id_from_email(self.ADMIN_EMAIL) topic_services.update_topic_and_subtopic_pages(self.user_id_admin, self.TOPIC_ID, changelist, 'Added a subtopic') self.topic = topic_fetchers.get_topic_by_id(self.TOPIC_ID) self.set_admins([self.ADMIN_USERNAME]) self.set_topic_managers([user_services.get_username(self.user_id_a)]) self.user_a = user_services.UserActionsInfo(self.user_id_a) self.user_b = user_services.UserActionsInfo(self.user_id_b) self.user_admin = user_services.UserActionsInfo(self.user_id_admin)
def _load_dummy_new_structures_data(self): """Loads the database with two topics (one of which is empty), a story and three skills in the topic (two of them in a subtopic) and a question attached to each skill. Raises: Exception: Cannot load new structures data in production mode. Exception: User does not have enough rights to generate data. """ if constants.DEV_MODE: if self.user.role != feconf.ROLE_ID_ADMIN: raise Exception( 'User does not have enough rights to generate data.') topic_id_1 = topic_services.get_new_topic_id() topic_id_2 = topic_services.get_new_topic_id() story_id = story_services.get_new_story_id() skill_id_1 = skill_services.get_new_skill_id() skill_id_2 = skill_services.get_new_skill_id() skill_id_3 = skill_services.get_new_skill_id() question_id_1 = question_services.get_new_question_id() question_id_2 = question_services.get_new_question_id() question_id_3 = question_services.get_new_question_id() skill_1 = self._create_dummy_skill(skill_id_1, 'Dummy Skill 1', '<p>Dummy Explanation 1</p>') skill_2 = self._create_dummy_skill(skill_id_2, 'Dummy Skill 2', '<p>Dummy Explanation 2</p>') skill_3 = self._create_dummy_skill(skill_id_3, 'Dummy Skill 3', '<p>Dummy Explanation 3</p>') question_1 = self._create_dummy_question(question_id_1, 'Question 1', [skill_id_1]) question_2 = self._create_dummy_question(question_id_2, 'Question 2', [skill_id_2]) question_3 = self._create_dummy_question(question_id_3, 'Question 3', [skill_id_3]) question_services.add_question(self.user_id, question_1) question_services.add_question(self.user_id, question_2) question_services.add_question(self.user_id, question_3) question_services.create_new_question_skill_link( self.user_id, question_id_1, skill_id_1, 0.3) question_services.create_new_question_skill_link( self.user_id, question_id_2, skill_id_2, 0.5) question_services.create_new_question_skill_link( self.user_id, question_id_3, skill_id_3, 0.7) topic_1 = topic_domain.Topic.create_default_topic( topic_id_1, 'Dummy Topic 1', 'abbrev') topic_2 = topic_domain.Topic.create_default_topic( topic_id_2, 'Empty Topic', 'abbrev') topic_1.add_canonical_story(story_id) topic_1.add_uncategorized_skill_id(skill_id_1) topic_1.add_uncategorized_skill_id(skill_id_2) topic_1.add_uncategorized_skill_id(skill_id_3) topic_1.add_subtopic(1, 'Dummy Subtopic Title') topic_1.move_skill_id_to_subtopic(None, 1, skill_id_2) topic_1.move_skill_id_to_subtopic(None, 1, skill_id_3) subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id_1)) self._reload_exploration('0') self._reload_exploration('16') story = story_domain.Story.create_default_story( story_id, 'Dummy Story 1', topic_id_1) story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, 1), 'Dummy Chapter 1') story.update_node_destination_node_ids( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), ['%s%d' % (story_domain.NODE_ID_PREFIX, 2)]) story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, 1), '0') story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, 2), 'Dummy Chapter 2') story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, 2), '16') skill_services.save_new_skill(self.user_id, skill_1) skill_services.save_new_skill(self.user_id, skill_2) skill_services.save_new_skill(self.user_id, skill_3) story_services.save_new_story(self.user_id, story) topic_services.save_new_topic(self.user_id, topic_1) topic_services.save_new_topic(self.user_id, topic_2) subtopic_page_services.save_subtopic_page( self.user_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Dummy Subtopic Title' }) ]) topic_services.publish_story(topic_id_1, story_id, self.user_id) topic_services.publish_topic(topic_id_1, self.user_id) else: raise Exception('Cannot load new structures data in production.')
def _load_dummy_new_structures_data(self): """Loads the database with two topics (one of which is empty), a story and three skills in the topic (two of them in a subtopic) and a question attached to each skill. Raises: Exception: Cannot load new structures data in production mode. Exception: User does not have enough rights to generate data. """ if constants.DEV_MODE: if self.user.role != feconf.ROLE_ID_ADMIN: raise Exception( 'User does not have enough rights to generate data.') topic_id_1 = topic_services.get_new_topic_id() topic_id_2 = topic_services.get_new_topic_id() story_id = story_services.get_new_story_id() skill_id_1 = skill_services.get_new_skill_id() skill_id_2 = skill_services.get_new_skill_id() skill_id_3 = skill_services.get_new_skill_id() question_id_1 = question_services.get_new_question_id() question_id_2 = question_services.get_new_question_id() question_id_3 = question_services.get_new_question_id() skill_1 = self._create_dummy_skill(skill_id_1, 'Dummy Skill 1', '<p>Dummy Explanation 1</p>') skill_2 = self._create_dummy_skill(skill_id_2, 'Dummy Skill 2', '<p>Dummy Explanation 2</p>') skill_3 = self._create_dummy_skill(skill_id_3, 'Dummy Skill 3', '<p>Dummy Explanation 3</p>') question_1 = self._create_dummy_question(question_id_1, 'Question 1', [skill_id_1]) question_2 = self._create_dummy_question(question_id_2, 'Question 2', [skill_id_2]) question_3 = self._create_dummy_question(question_id_3, 'Question 3', [skill_id_3]) question_services.add_question(self.user_id, question_1) question_services.add_question(self.user_id, question_2) question_services.add_question(self.user_id, question_3) question_services.create_new_question_skill_link( self.user_id, question_id_1, skill_id_1, 0.3) question_services.create_new_question_skill_link( self.user_id, question_id_2, skill_id_2, 0.5) question_services.create_new_question_skill_link( self.user_id, question_id_3, skill_id_3, 0.7) topic_1 = topic_domain.Topic.create_default_topic( topic_id_1, 'Dummy Topic 1', 'abbrev', 'description') topic_2 = topic_domain.Topic.create_default_topic( topic_id_2, 'Empty Topic', 'abbrev', 'description') topic_1.add_canonical_story(story_id) topic_1.add_uncategorized_skill_id(skill_id_1) topic_1.add_uncategorized_skill_id(skill_id_2) topic_1.add_uncategorized_skill_id(skill_id_3) topic_1.add_subtopic(1, 'Dummy Subtopic Title') topic_1.move_skill_id_to_subtopic(None, 1, skill_id_2) topic_1.move_skill_id_to_subtopic(None, 1, skill_id_3) subtopic_page = ( subtopic_page_domain.SubtopicPage.create_default_subtopic_page( 1, topic_id_1)) # These explorations were chosen since they pass the validations # for published stories. self._reload_exploration('15') self._reload_exploration('25') self._reload_exploration('13') story = story_domain.Story.create_default_story( story_id, 'Help Jaime win the Arcade', topic_id_1) story_node_dicts = [{ 'exp_id': '15', 'title': 'What are the place values?', 'description': 'Jaime learns the place value of each digit ' + 'in a big number.' }, { 'exp_id': '25', 'title': 'Finding the value of a number', 'description': 'Jaime understands the value of his ' + 'arcade score.' }, { 'exp_id': '13', 'title': 'Comparing Numbers', 'description': 'Jaime learns if a number is smaller or ' + 'greater than another number.' }] def generate_dummy_story_nodes(node_id, exp_id, title, description): """Generates and connects sequential story nodes. Args: node_id: int. The node id. exp_id: str. The exploration id. title: str. The title of the story node. description: str. The description of the story node. """ story.add_node('%s%d' % (story_domain.NODE_ID_PREFIX, node_id), title) story.update_node_description( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), description) story.update_node_exploration_id( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), exp_id) if node_id != len(story_node_dicts): story.update_node_destination_node_ids( '%s%d' % (story_domain.NODE_ID_PREFIX, node_id), ['%s%d' % (story_domain.NODE_ID_PREFIX, node_id + 1)]) exp_services.update_exploration(self.user_id, exp_id, [ exp_domain.ExplorationChange({ 'cmd': exp_domain.CMD_EDIT_EXPLORATION_PROPERTY, 'property_name': 'category', 'new_value': 'Astronomy' }) ], 'Change category') for i, story_node_dict in enumerate(story_node_dicts): generate_dummy_story_nodes(i + 1, **story_node_dict) skill_services.save_new_skill(self.user_id, skill_1) skill_services.save_new_skill(self.user_id, skill_2) skill_services.save_new_skill(self.user_id, skill_3) story_services.save_new_story(self.user_id, story) topic_services.save_new_topic(self.user_id, topic_1) topic_services.save_new_topic(self.user_id, topic_2) subtopic_page_services.save_subtopic_page( self.user_id, subtopic_page, 'Added subtopic', [ topic_domain.TopicChange({ 'cmd': topic_domain.CMD_ADD_SUBTOPIC, 'subtopic_id': 1, 'title': 'Dummy Subtopic Title' }) ]) topic_services.publish_story(topic_id_1, story_id, self.user_id) else: raise Exception('Cannot load new structures data in production.')
def setUp(self): super(StoryProgressUnitTests, self).setUp() self.STORY_1_ID = 'story_id' self.STORY_ID_1 = 'story_id_1' self.NODE_ID_3 = 'node_3' self.NODE_ID_4 = 'node_4' self.owner_id = 'owner' self.TOPIC_ID = topic_services.get_new_topic_id() self.save_new_topic(self.TOPIC_ID, self.USER_ID, 'New Topic', 'abbrev', None, 'A new topic', [], [], [], [], 0) story = story_domain.Story.create_default_story( self.STORY_1_ID, 'Title', self.TOPIC_ID) story.description = ('Description') self.node_1 = { 'id': self.NODE_ID_1, 'title': 'Title 1', 'destination_node_ids': ['node_2'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': None } self.node_2 = { 'id': self.NODE_ID_2, 'title': 'Title 2', 'destination_node_ids': ['node_3'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': None } self.node_3 = { 'id': self.NODE_ID_3, 'title': 'Title 3', 'destination_node_ids': ['node_4'], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': None } self.node_4 = { 'id': self.NODE_ID_4, 'title': 'Title 4', 'destination_node_ids': [], 'acquired_skill_ids': [], 'prerequisite_skill_ids': [], 'outline': '', 'outline_is_finalized': False, 'exploration_id': None } story.story_contents.nodes = [ story_domain.StoryNode.from_dict(self.node_1), story_domain.StoryNode.from_dict(self.node_2), story_domain.StoryNode.from_dict(self.node_3), story_domain.StoryNode.from_dict(self.node_4) ] self.nodes = story.story_contents.nodes story.story_contents.initial_node_id = 'node_1' story.story_contents.next_node_id = 'node_5' story_services.save_new_story(self.USER_ID, story) topic_services.add_canonical_story(self.USER_ID, self.TOPIC_ID, story.id)
def test_handler_updates_story_summary_dicts(self): self.login(self.ADMIN_EMAIL) topic_id = topic_services.get_new_topic_id() canonical_story_id = story_services.get_new_story_id() additional_story_id = story_services.get_new_story_id() # 'self.topic_id' does not contain any canonical_story_summary_dicts # or additional_story_summary_dicts. response = self.get_json( '%s/%s' % (feconf.TOPIC_EDITOR_STORY_URL, self.topic_id)) self.assertEqual(response['canonical_story_summary_dicts'], []) self.assertEqual(response['additional_story_summary_dicts'], []) self.save_new_topic(topic_id, self.admin_id, name='New name', abbreviated_name='abbrev', thumbnail_filename=None, description='New description', canonical_story_ids=[canonical_story_id], additional_story_ids=[additional_story_id], uncategorized_skill_ids=[self.skill_id], subtopics=[], next_subtopic_id=1) self.save_new_story(canonical_story_id, self.admin_id, 'title', 'description', 'note', topic_id) self.save_new_story(additional_story_id, self.admin_id, 'another title', 'another description', 'another note', topic_id) topic_services.publish_story(topic_id, canonical_story_id, self.admin_id) response = self.get_json('%s/%s' % (feconf.TOPIC_EDITOR_STORY_URL, topic_id)) canonical_story_summary_dict = response[ 'canonical_story_summary_dicts'][0] additional_story_summary_dict = response[ 'additional_story_summary_dicts'][0] self.assertEqual(canonical_story_summary_dict['description'], 'description') self.assertEqual(canonical_story_summary_dict['title'], 'title') self.assertEqual(canonical_story_summary_dict['id'], canonical_story_id) self.assertEqual(canonical_story_summary_dict['story_is_published'], True) self.assertEqual(additional_story_summary_dict['description'], 'another description') self.assertEqual(additional_story_summary_dict['title'], 'another title') self.assertEqual(additional_story_summary_dict['id'], additional_story_id) self.assertEqual(additional_story_summary_dict['story_is_published'], False) self.logout()
def test_editable_topic_handler_put(self): # Check that admins can edit a topic. change_cmd = { 'version': 2, 'commit_message': 'Some changes and added a subtopic.', 'topic_and_subtopic_page_change_dicts': [{ 'cmd': 'update_topic_property', 'property_name': 'name', 'old_value': '', 'new_value': 'A new name' }, { 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_html', 'old_value': { 'html': '', 'content_id': 'content' }, 'subtopic_id': 1, 'new_value': { 'html': '<p>New Data</p>', 'content_id': 'content' } }, { 'cmd': 'add_subtopic', 'subtopic_id': 2, 'title': 'Title2' }, { 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_html', 'old_value': { 'html': '', 'content_id': 'content' }, 'new_value': { 'html': '<p>New Value</p>', 'content_id': 'content' }, 'subtopic_id': 2 }, { 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_audio', 'old_value': { 'voiceovers_mapping': { 'content': {} } }, 'new_value': { 'voiceovers_mapping': { 'content': { 'en': { 'filename': 'test.mp3', 'file_size_bytes': 100, 'needs_update': False, 'duration_secs': 0.34342 } } } }, 'subtopic_id': 2 }] } self.login(self.ADMIN_EMAIL) csrf_token = self.get_new_csrf_token() skill_services.delete_skill(self.admin_id, self.skill_id_2) with self.swap(feconf, 'CAN_SEND_EMAILS', True): messages = self.mail_stub.get_sent_messages( to=feconf.ADMIN_EMAIL_ADDRESS) self.assertEqual(len(messages), 0) json_response = self.put_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), change_cmd, csrf_token=csrf_token) self.assertEqual(self.topic_id, json_response['topic_dict']['id']) self.assertEqual('A new name', json_response['topic_dict']['name']) self.assertEqual(2, len(json_response['topic_dict']['subtopics'])) self.assertEqual( 'Skill Description', json_response['skill_id_to_description_dict'][self.skill_id]) messages = self.mail_stub.get_sent_messages( to=feconf.ADMIN_EMAIL_ADDRESS) expected_email_html_body = ('The deleted skills: %s are still' ' present in topic with id %s' % (self.skill_id_2, self.topic_id)) self.assertEqual(len(messages), 1) self.assertIn(expected_email_html_body, messages[0].html.decode()) # Test if the corresponding subtopic pages were created. json_response = self.get_json( '%s/%s/%s' % (feconf.SUBTOPIC_PAGE_EDITOR_DATA_URL_PREFIX, self.topic_id, 1)) self.assertEqual( { 'subtitled_html': { 'html': '<p>New Data</p>', 'content_id': 'content' }, 'recorded_voiceovers': { 'voiceovers_mapping': { 'content': {} } }, 'written_translations': { 'translations_mapping': { 'content': {} } } }, json_response['subtopic_page']['page_contents']) json_response = self.get_json( '%s/%s/%s' % (feconf.SUBTOPIC_PAGE_EDITOR_DATA_URL_PREFIX, self.topic_id, 2)) self.assertEqual( { 'subtitled_html': { 'html': '<p>New Value</p>', 'content_id': 'content' }, 'recorded_voiceovers': { 'voiceovers_mapping': { 'content': { 'en': { 'file_size_bytes': 100, 'filename': 'test.mp3', 'needs_update': False, 'duration_secs': 0.34342 } } } }, 'written_translations': { 'translations_mapping': { 'content': {} } } }, json_response['subtopic_page']['page_contents']) self.logout() # Test that any topic manager cannot edit the topic. self.login(self.TOPIC_MANAGER_EMAIL) self.put_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), change_cmd, csrf_token=csrf_token, expected_status_int=401) self.logout() # Check that non-admins and non-topic managers cannot edit a topic. self.put_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), change_cmd, csrf_token=csrf_token, expected_status_int=401) # Check that topic can not be edited when version is None. self.login(self.ADMIN_EMAIL) json_response = self.put_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), {'version': None}, csrf_token=csrf_token, expected_status_int=400) self.assertEqual(json_response['error'], 'Invalid POST request: a version must be specified.') self.logout() # Check topic can not be edited when payload version differs from # topic version. self.login(self.ADMIN_EMAIL) topic_id_1 = topic_services.get_new_topic_id() self.save_new_topic(topic_id_1, self.admin_id, name='Name 1', abbreviated_name='abbrev', thumbnail_filename=None, description='Description 1', canonical_story_ids=[], additional_story_ids=[], uncategorized_skill_ids=[self.skill_id], subtopics=[], next_subtopic_id=1) json_response = self.put_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, topic_id_1), {'version': '3'}, csrf_token=csrf_token, expected_status_int=400) self.assertEqual( json_response['error'], 'Trying to update version 1 of topic from version 3, ' 'which is too old. Please reload the page and try again.') self.logout()
def test_get_new_topic_id(self): new_topic_id = topic_services.get_new_topic_id() self.assertEqual(len(new_topic_id), 12) self.assertEqual(topic_models.TopicModel.get_by_id(new_topic_id), None)
def test_editable_topic_handler_put(self): # Check that admins can edit a topic. change_cmd = { 'version': 2, 'commit_message': 'Some changes and added a subtopic.', 'topic_and_subtopic_page_change_dicts': [{ 'change_affects_subtopic_page': False, 'cmd': 'update_topic_property', 'property_name': 'name', 'old_value': '', 'new_value': 'A new name' }, { 'change_affects_subtopic_page': True, 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_html', 'old_value': { 'html': '', 'content_id': 'content' }, 'subtopic_id': 1, 'new_value': { 'html': '<p>New Data</p>', 'content_id': 'content' } }, { 'change_affects_subtopic_page': False, 'cmd': 'add_subtopic', 'subtopic_id': 2, 'title': 'Title2' }, { 'change_affects_subtopic_page': True, 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_html', 'old_value': { 'html': '', 'content_id': 'content' }, 'new_value': { 'html': '<p>New Value</p>', 'content_id': 'content' }, 'subtopic_id': 2 }, { 'change_affects_subtopic_page': True, 'cmd': 'update_subtopic_page_property', 'property_name': 'page_contents_audio', 'old_value': { 'content': {} }, 'new_value': { 'content': { 'en': { 'filename': 'test.mp3', 'file_size_bytes': 100, 'needs_update': False } } }, 'subtopic_id': 2 }] } self.login(self.ADMIN_EMAIL) response = self.get_html_response( '%s/%s' % (feconf.TOPIC_EDITOR_URL_PREFIX, self.topic_id)) csrf_token = self.get_csrf_token_from_response(response) json_response = self.put_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), change_cmd, csrf_token=csrf_token) self.assertEqual(self.topic_id, json_response['topic_dict']['id']) self.assertEqual('A new name', json_response['topic_dict']['name']) self.assertEqual(2, len(json_response['topic_dict']['subtopics'])) self.assertEqual( 'Skill Description', json_response['skill_id_to_description_dict'][self.skill_id]) # Test if the corresponding subtopic pages were created. json_response = self.get_json( '%s/%s/%s' % (feconf.SUBTOPIC_PAGE_EDITOR_DATA_URL_PREFIX, self.topic_id, 1)) self.assertEqual( { 'subtitled_html': { 'html': '<p>New Data</p>', 'content_id': 'content' }, 'content_ids_to_audio_translations': { 'content': {} }, 'written_translations': { 'translations_mapping': { 'content': {} } } }, json_response['subtopic_page']['page_contents']) json_response = self.get_json( '%s/%s/%s' % (feconf.SUBTOPIC_PAGE_EDITOR_DATA_URL_PREFIX, self.topic_id, 2)) self.assertEqual( { 'subtitled_html': { 'html': '<p>New Value</p>', 'content_id': 'content' }, 'content_ids_to_audio_translations': { 'content': { 'en': { 'file_size_bytes': 100, 'filename': 'test.mp3', 'needs_update': False } } }, 'written_translations': { 'translations_mapping': { 'content': {} } } }, json_response['subtopic_page']['page_contents']) self.logout() # Test that any topic manager cannot edit the topic. self.login(self.TOPIC_MANAGER_EMAIL) self.put_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), change_cmd, csrf_token=csrf_token, expected_status_int=401) self.logout() # Check that non-admins and non-topic managers cannot edit a topic. self.put_json('%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), change_cmd, csrf_token=csrf_token, expected_status_int=401) # Check that topic can not be edited when version is None. self.login(self.ADMIN_EMAIL) json_response = self.put_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, self.topic_id), {'version': None}, csrf_token=csrf_token, expected_status_int=400) self.assertEqual(json_response['error'], 'Invalid POST request: a version must be specified.') self.logout() # Check topic can not be edited when payload version differs from # topic version. self.login(self.ADMIN_EMAIL) topic_id_1 = topic_services.get_new_topic_id() self.save_new_topic(topic_id_1, self.admin_id, 'Name 1', 'Description 1', [], [], [self.skill_id], [], 1) json_response = self.put_json( '%s/%s' % (feconf.TOPIC_EDITOR_DATA_URL_PREFIX, topic_id_1), {'version': '3'}, csrf_token=csrf_token, expected_status_int=400) self.assertEqual( json_response['error'], 'Trying to update version 1 of topic from version 3, ' 'which is too old. Please reload the page and try again.') self.logout()