-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix part of #19864 : Added feature to generate dummy suggestion questions #20248
base: develop
Are you sure you want to change the base?
Changes from all commits
70371aa
11f28fb
dd66179
a09c80e
966ba65
1b22292
c54c49c
fffb5f5
541e490
ad7208f
9e463e2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,7 @@ | |
from core.domain import story_services | ||
from core.domain import subtopic_page_domain | ||
from core.domain import subtopic_page_services | ||
from core.domain import suggestion_services | ||
from core.domain import topic_domain | ||
from core.domain import topic_fetchers | ||
from core.domain import topic_services | ||
|
@@ -223,6 +224,8 @@ class AdminHandlerNormalizePayloadDict(TypedDict): | |
collection_id: Optional[str] | ||
num_dummy_exps_to_generate: Optional[int] | ||
num_dummy_exps_to_publish: Optional[int] | ||
num_dummy_question_suggestions_generate: Optional[int] | ||
skill_id: Optional[str] | ||
num_dummy_translation_opportunities_to_generate: Optional[int] | ||
data: Optional[str] | ||
topic_id: Optional[str] | ||
|
@@ -256,6 +259,7 @@ class AdminHandler( | |
'generate_dummy_new_skill_data', | ||
'generate_dummy_blog_post', | ||
'generate_dummy_classroom', | ||
'generate_dummy_question_suggestions', | ||
'upload_topic_similarities', | ||
'regenerate_topic_related_opportunities', | ||
'update_platform_parameter_rules', | ||
|
@@ -285,6 +289,18 @@ class AdminHandler( | |
}, | ||
'default_value': None | ||
}, | ||
'skill_id': { | ||
'schema': { | ||
'type': 'basestring' | ||
}, | ||
'default_value': None | ||
}, | ||
'num_dummy_question_suggestions_generate': { | ||
'schema': { | ||
'type': 'int' | ||
}, | ||
'default_value': None | ||
}, | ||
'num_dummy_exps_to_publish': { | ||
'schema': { | ||
'type': 'int' | ||
|
@@ -363,6 +379,9 @@ class AdminHandler( | |
@acl_decorators.can_access_admin_page | ||
def get(self) -> None: | ||
"""Populates the data on the admin page.""" | ||
skill_summaries = skill_services.get_all_skill_summaries() | ||
skill_summary_dicts = [ | ||
summary.to_dict() for summary in skill_summaries] | ||
demo_exploration_ids = list(feconf.DEMO_EXPLORATIONS.keys()) | ||
|
||
topic_summaries = topic_fetchers.get_all_topic_summaries() | ||
|
@@ -394,6 +413,7 @@ def get(self) -> None: | |
'role_to_actions': role_services.get_role_actions(), | ||
'topic_summaries': topic_summary_dicts, | ||
'platform_params_dicts': platform_params_dicts, | ||
'skill_list': skill_summary_dicts, | ||
}) | ||
|
||
@acl_decorators.can_access_admin_page | ||
|
@@ -428,6 +448,10 @@ def post(self) -> None: | |
Exception. The commit_message must be provided when the action | ||
is update_platform_parameter_rules. | ||
InvalidInputException. The input provided is not valid. | ||
Exception. The skill_id must be provided when | ||
the action is generate_dummy_question_suggestions. | ||
Exception. The num_dummy_question_suggestions_generate must be | ||
provided when the action is generate_dummy_question_suggestions. | ||
""" | ||
assert self.user_id is not None | ||
assert self.normalized_payload is not None | ||
|
@@ -505,6 +529,25 @@ def post(self) -> None: | |
self._generate_dummy_skill_and_questions() | ||
elif action == 'generate_dummy_classroom': | ||
self._generate_dummy_classroom() | ||
elif action == 'generate_dummy_question_suggestions': | ||
skill_id = self.normalized_payload.get('skill_id') | ||
if skill_id is None: | ||
raise Exception( | ||
'The \'skill_id\' must be provided when' | ||
' the action is _generate_dummy_question_suggestions.' | ||
) | ||
num_dummy_question_suggestions_generate = ( | ||
self.normalized_payload.get( | ||
'num_dummy_question_suggestions_generate') | ||
) | ||
if num_dummy_question_suggestions_generate is None: | ||
raise Exception( | ||
'The \'num_dummy_question_suggestions_generate\' must' | ||
' be provided when the action is ' | ||
'_generate_dummy_question_suggestions.' | ||
) | ||
self._generate_dummy_question_suggestions( | ||
skill_id, num_dummy_question_suggestions_generate) | ||
elif action == 'upload_topic_similarities': | ||
data = self.normalized_payload.get('data') | ||
if data is None: | ||
|
@@ -1541,6 +1584,117 @@ def _generate_dummy_classroom(self) -> None: | |
else: | ||
raise Exception('Cannot generate dummy classroom in production.') | ||
|
||
def _generate_dummy_question_suggestions( | ||
self, skill_id: str, | ||
num_dummy_question_suggestions_generate: int) -> None: | ||
"""Generates and loads the database with a specified number of | ||
suggestion question for the selected skill. | ||
|
||
Raises: | ||
Exception. Cannot load suggestion questions in production mode. | ||
Exception. User does not have enough rights to generate data. | ||
""" | ||
assert self.user_id is not None | ||
if constants.DEV_MODE: | ||
if ((feconf.ROLE_ID_QUESTION_ADMIN not in self.user.roles) | ||
and (not user_services.can_submit_question_suggestions( | ||
self.user_id))): | ||
raise Exception(( | ||
'User \'%s\' must be a question submitter or question admin' | ||
' in order to generate question suggestions.' | ||
) % self.username) | ||
for _ in range(num_dummy_question_suggestions_generate): | ||
content_id_generator = translation_domain.ContentIdGenerator() | ||
content_id_generator.generate( | ||
translation_domain.ContentType.CONTENT) | ||
content_id_generator.generate( | ||
translation_domain.ContentType.DEFAULT_OUTCOME) | ||
state = state_domain.State.create_default_state( | ||
'default_state', | ||
content_id_generator.generate( | ||
translation_domain.ContentType.CONTENT), | ||
content_id_generator.generate( | ||
translation_domain.ContentType.DEFAULT_OUTCOME), | ||
is_initial_state=True) | ||
state.update_interaction_id('TextInput') | ||
solution_dict: state_domain.SolutionDict = { | ||
'answer_is_exclusive': False, | ||
'correct_answer': 'Solution', | ||
'explanation': { | ||
'content_id': content_id_generator.generate( | ||
translation_domain.ContentType.SOLUTION), | ||
'html': '<p>This is a solution.</p>', | ||
}, | ||
} | ||
hints_list = [ | ||
state_domain.Hint( | ||
state_domain.SubtitledHtml( | ||
content_id_generator.generate( | ||
translation_domain.ContentType.HINT), | ||
'<p>This is a hint.</p>')), | ||
] | ||
# Ruling out None for mypy type checking, | ||
# as interaction_id is already updated. | ||
assert state.interaction.id is not None | ||
solution = state_domain.Solution.from_dict( | ||
state.interaction.id, solution_dict) | ||
state.update_interaction_solution(solution) | ||
state.update_interaction_hints(hints_list) | ||
state.update_interaction_customization_args({ | ||
'placeholder': { | ||
'value': { | ||
'content_id': content_id_generator.generate( | ||
translation_domain.ContentType.CUSTOMIZATION_ARG, # pylint: disable=line-too-long | ||
extra_prefix='placeholder'), | ||
'unicode_str': 'Enter text here', | ||
}, | ||
}, | ||
'rows': {'value': 1}, | ||
'catchMisspellings': {'value': False} | ||
}) | ||
# Here, state is a State domain object and it is created using | ||
# 'create_default_state' method. So, 'state' is a default_state | ||
# and it is always going to contain a default_outcome. Thus to | ||
# narrow down the type from Optional[Outcome] to Outcome for | ||
# default_outcome, we used assert here. | ||
assert state.interaction.default_outcome is not None | ||
state.interaction.default_outcome.labelled_as_correct = True | ||
state.interaction.default_outcome.dest = None | ||
suggestion_change: Dict[ | ||
str, Union[str, float, question_domain.QuestionDict] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use AcceptableChangeDictTypes instead of the Union? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nikitaevg Yeah, I had a doubt about this. If we change |
||
] = { | ||
'cmd': ( | ||
question_domain | ||
.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION), | ||
'question_dict': { | ||
'id': '', | ||
'version': 0, | ||
'question_state_data': state.to_dict(), | ||
'language_code': 'en', | ||
'question_state_data_schema_version': 1, | ||
'linked_skill_ids': [skill_id], | ||
'inapplicable_skill_misconception_ids': [], | ||
'next_content_id_index': ( | ||
content_id_generator.next_content_id_index) | ||
}, | ||
'skill_id': skill_id, | ||
'skill_difficulty': 0.3 | ||
} | ||
|
||
suggestion = suggestion_services.create_suggestion( | ||
feconf.SUGGESTION_TYPE_ADD_QUESTION, | ||
feconf.ENTITY_TYPE_SKILL, | ||
skill_id, 1, | ||
self.user_id, suggestion_change, 'test description') | ||
|
||
( | ||
suggestion_services | ||
.update_question_contribution_stats_at_submission( | ||
suggestion)) | ||
Comment on lines
+1690
to
+1693
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you add parenthesis around this expression? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added parenthesis because this was exceeding max line character limit, so to distribute it into 2 lines. |
||
else: | ||
raise Exception( | ||
'Cannot generate dummy question suggestion in production.') | ||
|
||
|
||
class AdminRoleHandlerNormalizedGetRequestDict(TypedDict): | ||
"""Dict representation of AdminRoleHandler's GET normalized_request | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's usually a very well serving pattern - handle corner cases first and common cases later.
Here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikitaevg In the whole file it is written like this so I thought it is the appropriate method, so now do I need to change mine code as well as other part of file?