Skip to content

Commit

Permalink
Modified topic and story models (oppia#5049)
Browse files Browse the repository at this point in the history
* Merged with controllers

* Merged with add-copy

* Modified topic domain and services

* fixed errors

* Added tests and modified functions

* modified stories

* made review changes

* Added test

* made review changes

* Added remove skill id

* made review changes
  • Loading branch information
aks681 authored Jun 7, 2018
1 parent 561c895 commit c18c473
Show file tree
Hide file tree
Showing 18 changed files with 823 additions and 139 deletions.
2 changes: 1 addition & 1 deletion core/controllers/skill_editor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def setUp(self):
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], [])


class SkillEditorTest(BaseSkillEditorControllerTest):
Expand Down
2 changes: 1 addition & 1 deletion core/controllers/story_editor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def setUp(self):
self.topic_id = topic_services.get_new_topic_id()
self.save_new_topic(
self.topic_id, self.admin_id, 'Name', 'Description',
[self.story_id], [], [])
[self.story_id], [], [], [])


class StoryEditorTest(BaseStoryEditorControllerTest):
Expand Down
4 changes: 2 additions & 2 deletions core/controllers/topic_editor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def setUp(self):
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', [], [], [])
self.topic_id, self.admin_id, 'Name', 'Description', [], [], [], [])


class NewStoryHandlerTest(BaseTopicEditorControllerTest):
Expand Down Expand Up @@ -109,7 +109,7 @@ def test_access_topic_editor_page(self):
topic_id_2 = topic_services.get_new_topic_id()
self.save_new_topic(
topic_id_2, self.admin_id, 'Name', 'Description',
[], [], [])
[], [], [], [])
self.signup('topicmanager2@example.com', 'topicmanager2')
topic_manager_id_2 = self.get_user_id_from_email(
'topicmanager2@example.com')
Expand Down
3 changes: 2 additions & 1 deletion core/controllers/topics_and_skills_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ def post(self):
skill_services.save_new_skill(self.user_id, skill)

if topic_id is not None:
topic_services.add_skill(self.user_id, topic_id, new_skill_id)
topic_services.add_uncategorized_skill(
self.user_id, topic_id, new_skill_id)

self.render_json({
'skillId': new_skill_id
Expand Down
4 changes: 2 additions & 2 deletions core/controllers/topics_and_skills_dashboard_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def setUp(self):
self.set_admins([self.ADMIN_USERNAME])
self.topic_id = topic_services.get_new_topic_id()
self.save_new_topic(
self.topic_id, self.admin_id, 'Name', 'Description', [], [], [])
self.topic_id, self.admin_id, 'Name', 'Description', [], [], [], [])


class NewTopicHandlerTest(BaseTopicsAndSkillsDashboardTest):
Expand Down Expand Up @@ -101,5 +101,5 @@ def test_skill_creation_in_valid_topic(self):
self.assertIsNotNone(
skill_services.get_skill_by_id(skill_id, strict=False))
topic = topic_services.get_topic_by_id(self.topic_id)
self.assertEqual(topic.skill_ids, [skill_id])
self.assertEqual(topic.uncategorized_skill_ids, [skill_id])
self.logout()
2 changes: 1 addition & 1 deletion core/domain/skill_domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def validate(self):
Raises:
ValidationError: One or more attributes of the misconception are
invalid.
invalid.
"""
if not isinstance(self.name, basestring):
raise utils.ValidationError(
Expand Down
4 changes: 2 additions & 2 deletions core/domain/skill_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _migrate_skill_contents_to_latest_schema(versioned_skill_contents):
Raises:
Exception: The schema version of the skill_contents is outside of what
is supported at present.
is supported at present.
"""
skill_contents_schema_version = versioned_skill_contents['schema_version']
if not (1 <= skill_contents_schema_version
Expand Down Expand Up @@ -72,7 +72,7 @@ def _migrate_misconceptions_to_latest_schema(versioned_misconceptions):
Raises:
Exception: The schema version of misconceptions is outside of what
is supported at present.
is supported at present.
"""
misconception_schema_version = versioned_misconceptions['schema_version']
if not (1 <= misconception_schema_version
Expand Down
55 changes: 51 additions & 4 deletions core/domain/story_domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
STORY_NODE_PROPERTY_OUTLINE = 'outline'
STORY_NODE_PROPERTY_EXPLORATION_ID = 'exploration_id'


INITIAL_NODE_ID = 'initial_node_id'

CMD_MIGRATE_SCHEMA_TO_LATEST_VERSION = 'migrate_schema_to_latest_version'
Expand All @@ -48,6 +49,7 @@
# These take node_id as parameter.
CMD_ADD_STORY_NODE = 'add_story_node'
CMD_DELETE_STORY_NODE = 'delete_story_node'
CMD_UPDATE_STORY_NODE_OUTLINE_STATUS = 'update_story_node_outline_status'

# This takes additional 'title' parameters.
CMD_CREATE_NEW = 'create_new'
Expand All @@ -72,7 +74,7 @@ class StoryChange(object):

OPTIONAL_CMD_ATTRIBUTE_NAMES = [
'property_name', 'new_value', 'old_value', 'node_id', 'from_version',
'to_version', 'title'
'to_version', 'title', 'finalized'
]

def __init__(self, change_dict):
Expand All @@ -99,6 +101,10 @@ def __init__(self, change_dict):
self.node_id = change_dict['node_id']
elif self.cmd == CMD_DELETE_STORY_NODE:
self.node_id = change_dict['node_id']
elif self.cmd == CMD_UPDATE_STORY_NODE_OUTLINE_STATUS:
self.node_id = change_dict['node_id']
self.old_value = change_dict['old_value']
self.new_value = change_dict['new_value']
elif self.cmd == CMD_UPDATE_STORY_NODE_PROPERTY:
if (change_dict['property_name'] not in
self.STORY_NODE_PROPERTIES):
Expand Down Expand Up @@ -152,7 +158,7 @@ class StoryNode(object):
def __init__(
self, node_id, destination_node_ids,
acquired_skill_ids, prerequisite_skill_ids,
outline, exploration_id):
outline, outline_is_finalized, exploration_id):
"""Initializes a StoryNode domain object.
Args:
Expand All @@ -167,6 +173,8 @@ def __init__(
can use to construct the exploration. It describes the basic
theme or template of the story and is to be provided in html
form.
outline_is_finalized: bool. Whether the outline for the story
node is finalized or not.
exploration_id: str or None. The valid exploration id that fits the
story node. It can be None initially, when the story creator
has just created a story with the basic storyline (by providing
Expand All @@ -177,6 +185,7 @@ def __init__(
self.acquired_skill_ids = acquired_skill_ids
self.prerequisite_skill_ids = prerequisite_skill_ids
self.outline = html_cleaner.clean(outline)
self.outline_is_finalized = outline_is_finalized
self.exploration_id = exploration_id

@classmethod
Expand Down Expand Up @@ -230,6 +239,7 @@ def to_dict(self):
'acquired_skill_ids': self.acquired_skill_ids,
'prerequisite_skill_ids': self.prerequisite_skill_ids,
'outline': self.outline,
'outline_is_finalized': self.outline_is_finalized,
'exploration_id': self.exploration_id
}

Expand All @@ -247,7 +257,7 @@ def from_dict(cls, node_dict):
node_dict['id'], node_dict['destination_node_ids'],
node_dict['acquired_skill_ids'],
node_dict['prerequisite_skill_ids'], node_dict['outline'],
node_dict['exploration_id'])
node_dict['outline_is_finalized'], node_dict['exploration_id'])

return node

Expand All @@ -262,7 +272,7 @@ def create_default_story_node(cls, node_id):
StoryNode. The StoryNode domain object with default
value.
"""
return cls(node_id, [], [], [], '', None)
return cls(node_id, [], [], [], '', False, None)

def validate(self):
"""Validates various properties of the story node.
Expand All @@ -282,6 +292,11 @@ def validate(self):
'Expected outline to be a string, received %s' %
self.outline)

if not isinstance(self.outline_is_finalized, bool):
raise utils.ValidationError(
'Expected outline_is_finalized to be a boolean, received %s' %
self.outline_is_finalized)

self.require_valid_node_id(self.id)

if not isinstance(self.prerequisite_skill_ids, list):
Expand Down Expand Up @@ -779,6 +794,38 @@ def update_node_outline(self, node_id, new_outline):
'The node with id %s is not part of this story' % node_id)
self.story_contents.nodes[node_index].outline = new_outline

def mark_node_outline_as_finalized(self, node_id):
"""Updates the outline_is_finalized field of the node with the given
node_id as True.
Args:
node_id: str. The id of the node.
Raises:
ValueError: The node is not part of the story.
"""
node_index = self.story_contents.get_node_index(node_id)
if node_index is None:
raise ValueError(
'The node with id %s is not part of this story' % node_id)
self.story_contents.nodes[node_index].outline_is_finalized = True

def mark_node_outline_as_unfinalized(self, node_id):
"""Updates the outline_is_finalized field of the node with the given
node_id as False.
Args:
node_id: str. The id of the node.
Raises:
ValueError: The node is not part of the story.
"""
node_index = self.story_contents.get_node_index(node_id)
if node_index is None:
raise ValueError(
'The node with id %s is not part of this story' % node_id)
self.story_contents.nodes[node_index].outline_is_finalized = False

def update_node_acquired_skill_ids(self, node_id, new_acquired_skill_ids):
"""Updates the acquired skill ids field of a given node.
Expand Down
25 changes: 24 additions & 1 deletion core/domain/story_domain_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def test_defaults(self):
'acquired_skill_ids': [],
'prerequisite_skill_ids': [],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}],
'initial_node_id': self.NODE_ID_1,
Expand Down Expand Up @@ -129,6 +130,11 @@ def test_get_number_from_node_id(self):
self.assertEqual(
story_domain.StoryNode.get_number_from_node_id('node_10'), 10)

def test_node_outline_finalized_validation(self):
self.story.story_contents.nodes[0].outline_is_finalized = 'abs'
self._assert_validation_error(
'Expected outline_is_finalized to be a boolean')

def test_nodes_validation(self):
self.story.story_contents.initial_node_id = 'node_10'
self._assert_validation_error('Expected starting node to exist')
Expand All @@ -153,6 +159,7 @@ def test_nodes_validation(self):
'prerequisite_skill_ids': [],
'acquired_skill_ids': [],
'outline': 'Outline',
'outline_is_finalized': False,
'exploration_id': 'exploration_id'
})
]
Expand Down Expand Up @@ -203,6 +210,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_2'],
'prerequisite_skill_ids': ['skill_1'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_2 = {
Expand All @@ -211,6 +219,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_3'],
'prerequisite_skill_ids': ['skill_2'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_3 = {
Expand All @@ -219,6 +228,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_4'],
'prerequisite_skill_ids': ['skill_3'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
self.story.story_contents.initial_node_id = 'node_1'
Expand All @@ -238,6 +248,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_2'],
'prerequisite_skill_ids': ['skill_1'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_2 = {
Expand All @@ -246,6 +257,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_3'],
'prerequisite_skill_ids': ['skill_2'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_3 = {
Expand All @@ -254,6 +266,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_4'],
'prerequisite_skill_ids': ['skill_3'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
self.story.story_contents.nodes = [
Expand All @@ -270,6 +283,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_2'],
'prerequisite_skill_ids': ['skill_1'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_2 = {
Expand All @@ -278,6 +292,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_3'],
'prerequisite_skill_ids': ['skill_2'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_3 = {
Expand All @@ -286,6 +301,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_4'],
'prerequisite_skill_ids': ['skill_3'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
self.story.story_contents.nodes = [
Expand All @@ -303,6 +319,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_2'],
'prerequisite_skill_ids': ['skill_1'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_2 = {
Expand All @@ -311,6 +328,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_3'],
'prerequisite_skill_ids': ['skill_2'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_3 = {
Expand All @@ -319,6 +337,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_4'],
'prerequisite_skill_ids': ['skill_3'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
self.story.story_contents.nodes = [
Expand All @@ -337,6 +356,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_2'],
'prerequisite_skill_ids': ['skill_1', 'skill_0'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_2 = {
Expand All @@ -345,6 +365,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': ['skill_3', 'skill_4'],
'prerequisite_skill_ids': ['skill_2'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_3 = {
Expand All @@ -353,6 +374,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': [],
'prerequisite_skill_ids': ['skill_4'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
node_4 = {
Expand All @@ -361,6 +383,7 @@ def test_all_nodes_visited(self):
'acquired_skill_ids': [],
'prerequisite_skill_ids': ['skill_2'],
'outline': '',
'outline_is_finalized': False,
'exploration_id': None
}
self.story.story_contents.nodes = [
Expand All @@ -378,7 +401,7 @@ def test_story_contents_export_import(self):
story_node = story_domain.StoryNode(
self.NODE_ID_1, [self.NODE_ID_2],
[self.SKILL_ID_1], [self.SKILL_ID_2],
'Outline', self.EXP_ID)
'Outline', False, self.EXP_ID)
story_contents = story_domain.StoryContents(
[story_node], self.NODE_ID_1, 2)
story_contents_dict = story_contents.to_dict()
Expand Down
Loading

0 comments on commit c18c473

Please sign in to comment.