def test_delete_story(self):
     story_services.delete_story(self.USER_ID, self.STORY_ID)
     self.assertEqual(
         story_fetchers.get_story_by_id(self.STORY_ID, strict=False), None)
     self.assertEqual(
         story_fetchers.get_story_summary_by_id(self.STORY_ID,
                                                strict=False), None)
Example #2
0
    def test_job_skips_deleted_story(self):
        """Tests that the regenerate summary job skips deleted story."""
        story = story_domain.Story.create_default_story(
            self.STORY_ID, 'A title', 'Description', self.TOPIC_ID,
            'title-four')
        story_services.save_new_story(self.albert_id, story)
        topic_services.add_canonical_story(self.albert_id, self.TOPIC_ID,
                                           story.id)

        story_services.delete_story(self.albert_id, self.STORY_ID)

        # Ensure the story is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            story_fetchers.get_story_by_id(self.STORY_ID)

        # Start migration job on sample story.
        job_id = (
            story_jobs_one_off.RegenerateStorySummaryOneOffJob.create_new())
        story_jobs_one_off.RegenerateStorySummaryOneOffJob.enqueue(job_id)

        # This running without errors indicates the deleted story is
        # being ignored.
        self.process_and_flush_pending_tasks()

        # Ensure the story is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            story_fetchers.get_story_by_id(self.STORY_ID)

        output = story_jobs_one_off.RegenerateStorySummaryOneOffJob.get_output(
            job_id)
        expected = [[u'story_deleted', [u'Encountered 1 deleted stories.']]]
        self.assertEqual(expected, [ast.literal_eval(x) for x in output])
    def test_migration_job_skips_deleted_story(self):
        """Tests that the story migration job skips deleted story
        and does not attempt to migrate.
        """
        story = story_domain.Story.create_default_story(
            self.STORY_ID, title='A title')
        story_services.save_new_story(self.albert_id, story)

        # Delete the story before migration occurs.
        story_services.delete_story(
            self.albert_id, self.STORY_ID)

        # Ensure the story is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            story_services.get_story_by_id(self.STORY_ID)

        # Start migration job on sample story.
        job_id = (
            story_jobs_one_off.StoryMigrationOneOffJob.create_new())
        story_jobs_one_off.StoryMigrationOneOffJob.enqueue(job_id)

        # This running without errors indicates the deleted story is
        # being ignored.
        self.process_and_flush_pending_tasks()

        # Ensure the story is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            story_services.get_story_by_id(self.STORY_ID)

        output = story_jobs_one_off.StoryMigrationOneOffJob.get_output(job_id) # pylint: disable=line-too-long
        expected = [[u'story_deleted',
                     [u'Encountered 1 deleted stories.']]]
        self.assertEqual(expected, [ast.literal_eval(x) for x in output])
    def test_job_skips_deleted_story(self):
        """Tests that StoryThumbnailSizeAuditOneOffJob skips deleted
        story.
        """
        self.save_new_story_with_story_contents_schema_v5(
            self.STORY_ID, 'image.svg', '#F8BF74', 21131, self.albert_id,
            'A title', 'A description', 'A note', self.TOPIC_ID)
        story = story_fetchers.get_story_by_id(self.STORY_ID)
        topic_services.add_canonical_story(self.albert_id, self.TOPIC_ID,
                                           story.id)

        # Delete the story before migration occurs.
        story_services.delete_story(self.albert_id, self.STORY_ID)

        # Start migration job on sample story nodes.
        job_id = (
            story_jobs_one_off.StoryThumbnailSizeAuditOneOffJob.create_new())
        story_jobs_one_off.StoryThumbnailSizeAuditOneOffJob.enqueue(job_id)

        # This running without errors indicates that deleted story are
        # skipped.
        self.process_and_flush_pending_mapreduce_tasks()

        output = (story_jobs_one_off.StoryThumbnailSizeAuditOneOffJob.
                  get_output(job_id))
        expected = []
        self.assertEqual(expected, [ast.literal_eval(x) for x in output])
Example #5
0
    def test_opportunity_get_deleted_with_deleting_story(self):
        story_services.update_story(self.owner_id, self.STORY_ID, [
            story_domain.StoryChange({
                'cmd': 'add_story_node',
                'node_id': 'node_1',
                'title': 'Node1',
            }),
            story_domain.StoryChange({
                'cmd': 'update_story_node_property',
                'property_name': 'exploration_id',
                'node_id': 'node_1',
                'old_value': None,
                'new_value': '0'
            })
        ], 'Changes.')

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        story_services.delete_story(self.owner_id, self.STORY_ID)

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 0)
    def test_thumbnail_size_job_skips_deleted_story(self):
        """Tests that the story migration job skips deleted story
        and does not attempt to migrate.
        """
        story = story_domain.Story.create_default_story(
            self.STORY_ID, 'A title', 'Description', self.TOPIC_ID,
            'title-two')
        story_services.save_new_story(self.albert_id, story)
        topic_services.add_canonical_story(self.albert_id, self.TOPIC_ID,
                                           story.id)

        # Delete the story before migration occurs.
        story_services.delete_story(self.albert_id, self.STORY_ID)

        # Ensure the story is deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            story_fetchers.get_story_by_id(self.STORY_ID)

        # Start migration job on sample story.
        job_id = (story_jobs_one_off.PopulateStoryThumbnailSizeOneOffJob.
                  create_new())
        story_jobs_one_off.PopulateStoryThumbnailSizeOneOffJob.enqueue(job_id)

        # This running without errors indicates the deleted story is
        # being ignored.
        self.process_and_flush_pending_mapreduce_tasks()

        # Ensure the story is still deleted.
        with self.assertRaisesRegexp(Exception, 'Entity .* not found'):
            story_fetchers.get_story_by_id(self.STORY_ID)

        output = (story_jobs_one_off.PopulateStoryThumbnailSizeOneOffJob.
                  get_output(job_id))
        expected = [[u'story_deleted', 1]]
        self.assertEqual(expected, [ast.literal_eval(x) for x in output])
 def test_job_skips_deleted_stories(self):
     story = story_domain.Story.create_default_story(
         'story_id', 'A title', 'Description', 'topic_id', 'title')
     story_services.save_new_story(self.albert_id, story)
     story_services.delete_story(self.albert_id, 'story_id')
     job_id = (story_jobs_one_off.StoryMathRteAuditOneOffJob.create_new())
     story_jobs_one_off.StoryMathRteAuditOneOffJob.enqueue(job_id)
     self.process_and_flush_pending_tasks()
     output = story_jobs_one_off.StoryMathRteAuditOneOffJob.get_output(
         job_id)
     self.assertEqual(output, [])
    def test_opportunity_get_deleted_with_deleting_story(self):
        self.add_exploration_0_to_story()

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 1)

        story_services.delete_story(self.owner_id, self.STORY_ID)

        translation_opportunities, _, _ = (
            opportunity_services.get_translation_opportunities('hi', None))
        self.assertEqual(len(translation_opportunities), 0)
Example #9
0
    def delete(self, topic_id, story_id):
        """Handles Delete requests."""
        story_domain.Story.require_valid_story_id(story_id)
        topic_domain.Topic.require_valid_topic_id(topic_id)

        story = story_services.get_story_by_id(story_id, strict=False)
        if story is None:
            raise self.PageNotFoundException

        story_services.delete_story(self.user_id, story_id)

        self.render_json(self.values)
Example #10
0
def delete_topic(committer_id, topic_id, force_deletion=False):
    """Deletes the topic with the given topic_id.

    Args:
        committer_id: str. ID of the committer.
        topic_id: str. ID of the topic to be deleted.
        force_deletion: bool. If true, the topic and its history are fully
            deleted and are unrecoverable. Otherwise, the topic and all
            its history are marked as deleted, but the corresponding models are
            still retained in the datastore. This last option is the preferred
            one.

    Raises:
        ValueError. User does not have enough rights to delete a topic.
    """
    topic_rights_model = topic_models.TopicRightsModel.get(topic_id)
    topic_rights_model.delete(
        committer_id, feconf.COMMIT_MESSAGE_TOPIC_DELETED,
        force_deletion=force_deletion)

    # Delete the summary of the topic (regardless of whether
    # force_deletion is True or not).
    delete_topic_summary(topic_id)
    topic_model = topic_models.TopicModel.get(topic_id)
    for subtopic in topic_model.subtopics:
        subtopic_page_services.delete_subtopic_page(
            committer_id, topic_id, subtopic['id'])

    all_story_references = (
        topic_model.canonical_story_references +
        topic_model.additional_story_references)
    for story_reference in all_story_references:
        story_services.delete_story(
            committer_id, story_reference['story_id'],
            force_deletion=force_deletion)
    topic_model.delete(
        committer_id, feconf.COMMIT_MESSAGE_TOPIC_DELETED,
        force_deletion=force_deletion)

    feedback_services.delete_threads_for_multiple_entities(
        feconf.ENTITY_TYPE_TOPIC, [topic_id])

    # This must come after the topic is retrieved. Otherwise the memcache
    # key will be reinstated.
    caching_services.delete_multi(
        caching_services.CACHE_NAMESPACE_TOPIC, None, [topic_id])
    (
        opportunity_services
        .delete_exploration_opportunities_corresponding_to_topic(topic_id))
Example #11
0
    def test_model_with_last_updated_greater_than_current_time(self):
        story_services.delete_story(self.owner_id, '1')
        story_services.delete_story(self.owner_id, '2')
        expected_output = [(
            u'[u\'failed validation check for current time check of '
            'StorySummaryModel\', '
            '[u\'Entity id %s: The last_updated field has a '
            'value %s which is greater than the time when the job was run\']]'
        ) % (self.model_instance_0.id, self.model_instance_0.last_updated)]

        mocked_datetime = datetime.datetime.utcnow() - datetime.timedelta(
            hours=13)
        with datastore_services.mock_datetime_for_datastore(mocked_datetime):
            self.run_job_and_check_output(
                expected_output, sort=True, literal_eval=False)
Example #12
0
    def map(item):
        if item.deleted:
            yield (DeleteOrphanStoriesOneOffJob._DELETED_KEY, 1)
            return

        topic = topic_fetchers.get_topic_by_id(item.corresponding_topic_id,
                                               strict=False)
        if topic is None or item.id not in topic.get_canonical_story_ids():
            try:
                story_services.delete_story(feconf.SYSTEM_COMMITTER_ID,
                                            item.id)
                yield (DeleteOrphanStoriesOneOffJob._PROCESSED_KEY, item.id)
                return
            except Exception as e:
                yield (DeleteOrphanStoriesOneOffJob._ERROR_KEY,
                       'Deletion of story %s failed: %s' % (item.id, e))
                return

        yield (DeleteOrphanStoriesOneOffJob._SKIPPED_KEY, 1)
Example #13
0
    def delete(self, topic_id, story_id):
        """Handles Delete requests."""
        story_domain.Story.require_valid_story_id(story_id)
        topic_domain.Topic.require_valid_topic_id(topic_id)

        story = story_services.get_story_by_id(story_id, strict=False)
        if story is None:
            raise self.PageNotFoundException

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        if topic is None:
            raise self.PageNotFoundException

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        if topic is None:
            raise self.PageNotFoundException(
                Exception('The topic with the given id doesn\'t exist.'))

        story_services.delete_story(self.user_id, story_id)

        self.render_json(self.values)
Example #14
0
    def delete(self, topic_id, story_id):
        """Handles Delete requests."""
        if not feconf.ENABLE_NEW_STRUCTURES:
            raise self.PageNotFoundException

        story_domain.Story.require_valid_story_id(story_id)
        topic_domain.Topic.require_valid_topic_id(topic_id)

        story = story_services.get_story_by_id(story_id, strict=False)
        if story is None:
            raise self.PageNotFoundException

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        if topic is None or story_id not in topic.canonical_story_ids:
            raise self.PageNotFoundException

        topic = topic_services.get_topic_by_id(topic_id, strict=False)
        if topic is None:
            raise self.PageNotFoundException(
                Exception('The topic with the given id doesn\'t exist.'))

        story_services.delete_story(self.user_id, story_id)
        topic_services.delete_story(self.user_id, topic_id, story_id)
Example #15
0
 def delete(self, story_id):
     """Handles Delete requests."""
     story_services.delete_story(self.user_id, story_id)
     self.render_json(self.values)