Repository: oppia/oppia

Issue:
Remove the DeleteAllQuestionAndInvalidSuggestionsOneOffJob once it's released
The DeleteAllQuestionAndInvalidSuggestionsOneOffJob is added in #11274 and expected to be a one time job. Through this issue, we are expecting to remove it once it's released. 
Remove the DeleteAllQuestionAndInvalidSuggestionsOneOffJob once it's released
The DeleteAllQuestionAndInvalidSuggestionsOneOffJob is added in #11274 and expected to be a one time job. Through this issue, we are expecting to remove it once it's released. 


Discussion:

Resolving patch:
diff --git a/core/domain/suggestion_jobs_one_off.py b/core/domain/suggestion_jobs_one_off.py
--- a/core/domain/suggestion_jobs_one_off.py
+++ b/core/domain/suggestion_jobs_one_off.py
@@ -24,18 +24,14 @@
 
 from constants import constants
 from core import jobs
-from core.domain import feedback_services
 from core.domain import html_validation_service
 from core.domain import suggestion_services
 from core.platform import models
 import feconf
 
-(email_models, feedback_models, suggestion_models, user_models,) = (
-    models.Registry.import_models([
-        models.NAMES.email, models.NAMES.feedback, models.NAMES.suggestion,
-        models.NAMES.user]))
-
-datastore_services = models.Registry.import_datastore_services()
+(feedback_models, suggestion_models, user_models,) = (
+    models.Registry.import_models(
+        [models.NAMES.feedback, models.NAMES.suggestion, models.NAMES.user]))
 transaction_services = models.Registry.import_transaction_services()
 
 
@@ -475,82 +471,3 @@ def reduce(key, values):
             yield (key, len(values))
         else:
             yield (key, values)
-
-
-class DeleteAllQuestionAndInvalidSuggestionsOneOffJob(
-        jobs.BaseMapReduceOneOffJobManager):
-    """One-off job to delete all questions and invalid suggestion models in the
-    server.
-
-    This job is only needed once and should not be kept after the problem
-    is fixed.
-
-    This job deletes following suggestion and connected models:
-        - Deletes all the question suggestions as the old question suggestions
-          have invalid state schema version number and deleting this model will
-          be fine as questions suggestion is an unreleased feature.
-        - Delete all suggestions which does not have corresponding feedback
-          models. This deletion is only required in the test server.
-
-    TODO(#11300): This job is only needed once and we are expecting to remove it
-    once it's used.
-    """
-
-    @classmethod
-    def entity_classes_to_map_over(cls):
-        return [suggestion_models.GeneralSuggestionModel]
-
-    @staticmethod
-    def map(item):
-        if item.deleted:
-            yield ('SUGGESTION_ALREADY_DELETED', 1)
-            return
-
-        feedback_model = feedback_models.GeneralFeedbackThreadModel.get_by_id(
-            item.id)
-
-        if feedback_model is not None and item.suggestion_type != (
-                suggestion_models.SUGGESTION_TYPE_ADD_QUESTION):
-            yield ('SUGGESTION_IGNORED', 1)
-            return
-
-        model_keys = []
-        model_keys.append(datastore_services.Key(
-            suggestion_models.GeneralSuggestionModel, item.id))
-
-        if feedback_model is not None:
-            model_keys.append(datastore_services.Key(
-                feedback_models.GeneralFeedbackThreadModel, item.id))
-
-        for message in feedback_services.get_messages(item.id):
-            model_keys.append(
-                datastore_services.Key(
-                    feedback_models.GeneralFeedbackMessageModel, message.id))
-
-        reply_to_id_models = (
-            email_models.GeneralFeedbackEmailReplyToIdModel.query(
-                email_models.GeneralFeedbackEmailReplyToIdModel.thread_id == (
-                    item.id)).fetch())
-
-        model_keys += [
-            datastore_services.Key(
-                email_models.GeneralFeedbackEmailReplyToIdModel,
-                reply_to_id_model.id)
-            for reply_to_id_model in reply_to_id_models]
-
-        model_keys += feedback_models.GeneralFeedbackThreadUserModel.query(
-            feedback_models.GeneralFeedbackThreadUserModel.thread_id == item.id
-        ).fetch(keys_only=True)
-
-        if item.target_type == feconf.ENTITY_TYPE_EXPLORATION:
-            model_keys.append(
-                datastore_services.Key(
-                    feedback_models.FeedbackAnalyticsModel, item.target_id))
-
-        transaction_services.run_in_transaction(
-            datastore_services.delete_multi, model_keys)
-        yield ('SUGGESTION_DELETED', 1)
-
-    @staticmethod
-    def reduce(key, values):
-        yield (key, len(values))
diff --git a/core/jobs_registry.py b/core/jobs_registry.py
--- a/core/jobs_registry.py
+++ b/core/jobs_registry.py
@@ -108,7 +108,6 @@
     story_jobs_one_off.RegenerateStorySummaryOneOffJob,
     story_jobs_one_off.StoryMigrationOneOffJob,
     story_jobs_one_off.OrphanStoriesAuditJob,
-    suggestion_jobs_one_off.DeleteAllQuestionAndInvalidSuggestionsOneOffJob,
     suggestion_jobs_one_off.QuestionSuggestionMigrationJobManager,
     suggestion_jobs_one_off.PopulateFinalReviewerIdOneOffJob,
     suggestion_jobs_one_off.PopulateSuggestionLanguageCodeMigrationOneOffJob,


Test patch:
diff --git a/core/domain/suggestion_jobs_one_off_test.py b/core/domain/suggestion_jobs_one_off_test.py
--- a/core/domain/suggestion_jobs_one_off_test.py
+++ b/core/domain/suggestion_jobs_one_off_test.py
@@ -2908,187 +2908,3 @@ def test_job_with_multi_message_models_yields_without_update(self):
         suggestion_model = suggestion_models.GeneralSuggestionModel.get_by_id(
             self.EXPLORATION_THREAD_ID)
         self.assertEqual(suggestion_model.final_reviewer_id, None)
-
-
-class DeleteAllQuestionAndInvalidSuggestionsOneOffJobTests(
-        test_utils.GenericTestBase):
-
-    target_id = 'exp1'
-    target_version_at_submission = 1
-    exploration_category = 'Algebra'
-    EXPLORATION_THREAD_ID = 'exploration.exp1.thread_1'
-    SKILL_THREAD_ID = 'skill1.thread1'
-    AUTHOR_EMAIL = 'author1@example.com'
-    REVIEWER_EMAIL = 'reviewer@example.com'
-
-    edit_state_content_change_dict = {
-        'cmd': exp_domain.CMD_EDIT_STATE_PROPERTY,
-        'property_name': exp_domain.STATE_PROPERTY_CONTENT,
-        'state_name': 'Introduction',
-        'new_value': {
-            'content_id': 'content',
-            'html': 'new html content'
-        },
-        'old_value': {
-            'content_id': 'content',
-            'html': 'old html content'
-        }
-    }
-
-    # The question_state_data is set to valid state data in the setup.
-    add_question_change_dict = {
-        'cmd': question_domain.CMD_CREATE_NEW_FULLY_SPECIFIED_QUESTION,
-        'question_dict': {
-            'question_state_data': {},
-            'language_code': 'en',
-            'question_state_data_schema_version': (
-                feconf.CURRENT_STATE_SCHEMA_VERSION),
-            'linked_skill_ids': ['skill_1'],
-            'inapplicable_skill_misconception_ids': ['skillid12345-1']
-        },
-        'skill_id': 'skill_1',
-        'skill_difficulty': 0.3,
-    }
-
-    def _run_job_and_verify_output(self, expected_output):
-        """Runs the DeleteAllQuestionAndInvalidSuggestionsOneOffJobTests and
-        verifies that the output matches the expected output.
-
-        Args:
-            expected_output: list(str). The expected output from the one off
-                job.
-        """
-        job_id = (
-            suggestion_jobs_one_off
-            .DeleteAllQuestionAndInvalidSuggestionsOneOffJob.create_new())
-        (
-            suggestion_jobs_one_off
-            .DeleteAllQuestionAndInvalidSuggestionsOneOffJob.enqueue(job_id)
-        )
-        self.process_and_flush_pending_mapreduce_tasks()
-
-        actual_output = (
-            suggestion_jobs_one_off
-            .DeleteAllQuestionAndInvalidSuggestionsOneOffJob.get_output(
-                job_id))
-
-        self.assertEqual(actual_output, expected_output)
-
-    def setUp(self):
-        super(
-            DeleteAllQuestionAndInvalidSuggestionsOneOffJobTests, self).setUp()
-        self.signup(self.AUTHOR_EMAIL, 'author')
-        self.author_id = self.get_user_id_from_email(self.AUTHOR_EMAIL)
-        self.signup(self.REVIEWER_EMAIL, 'reviewer')
-        self.reviewer_id = self.get_user_id_from_email(self.REVIEWER_EMAIL)
-        # Add valid question state data to the question dict.
-        self.add_question_change_dict['question_dict'][
-            'question_state_data'] = self._create_valid_question_data(
-                'default_state').to_dict()
-
-        self.skill_id = 'skill_id'
-        self.save_new_skill(
-            self.skill_id, self.author_id, description='Skill Description')
-
-        self.process_and_flush_pending_mapreduce_tasks()
-
-    def test_no_action_is_performed_for_suggestions_that_are_marked_deleted(
-            self):
-        suggestion_models.GeneralSuggestionModel(
-            id=self.EXPLORATION_THREAD_ID,
-            suggestion_type=(
-                suggestion_models.SUGGESTION_TYPE_EDIT_STATE_CONTENT),
-            target_type=suggestion_models.TARGET_TYPE_EXPLORATION,
-            target_id=self.target_id,
-            target_version_at_submission=self.target_version_at_submission,
-            status=suggestion_models.STATUS_ACCEPTED,
-            author_id=self.author_id,
-            final_reviewer_id=None,
-            change_cmd=self.edit_state_content_change_dict,
-            score_category='score_category'
-        ).put()
-
-        suggestion_model = suggestion_models.GeneralSuggestionModel.get_by_id(
-            self.EXPLORATION_THREAD_ID)
-        suggestion_model.deleted = True
-        suggestion_model.update_timestamps()
-        suggestion_model.put()
-
-        expected_output = [u'[u\'SUGGESTION_ALREADY_DELETED\', 1]']
-        self._run_job_and_verify_output(expected_output)
-
-        suggestion_model = suggestion_models.GeneralSuggestionModel.get_by_id(
-            self.EXPLORATION_THREAD_ID)
-        self.assertEqual(suggestion_model.final_reviewer_id, None)
-
-    def test_migration_job_deletes_existing_question_suggestion(self):
-        suggestion = suggestion_services.create_suggestion(
-            suggestion_models.SUGGESTION_TYPE_ADD_QUESTION,
-            suggestion_models.TARGET_TYPE_SKILL, self.skill_id, 1,
-            self.author_id, self.add_question_change_dict, 'test description')
-
-        expected_output = ['[u\'SUGGESTION_DELETED\', 1]']
-        self._run_job_and_verify_output(expected_output)
-
-        suggestion_model = suggestion_models.GeneralSuggestionModel.get_by_id(
-            suggestion.suggestion_id)
-        self.assertEqual(suggestion_model, None)
-
-    def test_migration_job_ignore_exp_suggestion_with_feedback_model(self):
-        exp_id = 'expId1'
-        exploration = (
-            self.save_new_linear_exp_with_state_names_and_interactions(
-                exp_id, self.author_id, ['State 1', 'State 2'],
-                ['TextInput'], category='Algebra'))
-
-        add_translation_change_dict = {
-            'cmd': exp_domain.CMD_ADD_TRANSLATION,
-            'state_name': 'State 1',
-            'content_id': 'content',
-            'language_code': 'hi',
-            'content_html': exploration.states['State 1'].content.html,
-            'translation_html': '<p>This is translated html.</p>'
-        }
-
-        suggestion_services.create_suggestion(
-            suggestion_models.SUGGESTION_TYPE_TRANSLATE_CONTENT,
-            suggestion_models.TARGET_TYPE_EXPLORATION,
-            exp_id, 1, self.author_id, add_translation_change_dict,
-            'test description')
-
-        expected_output = ['[u\'SUGGESTION_IGNORED\', 1]']
-        self._run_job_and_verify_output(expected_output)
-
-    def test_migration_job_deletes_suggestion_without_feedback_model(self):
-        exp_id = 'expId1'
-        exploration = (
-            self.save_new_linear_exp_with_state_names_and_interactions(
-                exp_id, self.author_id, ['State 1', 'State 2'],
-                ['TextInput'], category='Algebra'))
-
-        add_translation_change_dict = {
-            'cmd': exp_domain.CMD_ADD_TRANSLATION,
-            'state_name': 'State 1',
-            'content_id': 'content',
-            'language_code': 'hi',
-            'content_html': exploration.states['State 1'].content.html,
-            'translation_html': '<p>This is translated html.</p>'
-        }
-
-        suggestion = suggestion_services.create_suggestion(
-            suggestion_models.SUGGESTION_TYPE_TRANSLATE_CONTENT,
-            suggestion_models.TARGET_TYPE_EXPLORATION,
-            exp_id, 1, self.author_id, add_translation_change_dict,
-            'test description')
-
-        feedback_models.GeneralFeedbackThreadModel.get_by_id(
-            suggestion.suggestion_id).delete()
-        self.assertEqual(feedback_models.GeneralFeedbackThreadModel.get_by_id(
-            suggestion.suggestion_id), None)
-
-        expected_output = ['[u\'SUGGESTION_DELETED\', 1]']
-        self._run_job_and_verify_output(expected_output)
-
-        suggestion_model = suggestion_models.GeneralSuggestionModel.get_by_id(
-            suggestion.suggestion_id)
-        self.assertEqual(suggestion_model, None)