Repository: oppia/oppia

Issue:
[BUG]: Unable to view opportunities using certain filters in the contributor dashboard review screen.
### Describe the bug

Unable to view opportunities using certain filters in the contributor dashboard review screen.

### URL of the page where the issue is observed.

https://www.oppiatestserver.org/contributor-dashboard#

### Steps To Reproduce

1. Go to the review screen on the test server.
2. Use filters shown in the screenshot.
3. See error.

### Expected Behavior

Opportunities submitted by contributors should be listed.

### Screenshots/Videos

![image](https://github.com/oppia/oppia/assets/11008603/031eab2f-3edb-4613-93fa-6c7b861da24b)


### What device are you using?

_No response_

### Operating System

_No response_

### What browsers are you seeing the problem on?

_No response_

### Browser version

_No response_

### Additional context

_No response_

### Tips for developers

Before tackling the bug, please use `git bisect` (see https://git-scm.com/docs/git-bisect) to investigate which PR caused it (you only need to go back as far as commit https://github.com/oppia/oppia/commits/9a334e9). If you find the PR, leave a comment on this issue pointing to it, or just say that it happened before commit 9a334e9 if you could reproduce it there. This will help us fix the issue by reverting the faulty PR.

Also, if this is your first issue, please make sure to follow https://github.com/oppia/oppia/wiki/Contributing-code-to-Oppia#choosing-a-good-first-issue and https://github.com/oppia/oppia/wiki/Contributing-code-to-Oppia#setting-things-up before claiming it. Thanks!

[BUG]: Unable to view opportunities using certain filters in the contributor dashboard review screen.
### Describe the bug

Unable to view opportunities using certain filters in the contributor dashboard review screen.

### URL of the page where the issue is observed.

https://www.oppiatestserver.org/contributor-dashboard#

### Steps To Reproduce

1. Go to the review screen on the test server.
2. Use filters shown in the screenshot.
3. See error.

### Expected Behavior

Opportunities submitted by contributors should be listed.

### Screenshots/Videos

![image](https://github.com/oppia/oppia/assets/11008603/031eab2f-3edb-4613-93fa-6c7b861da24b)


### What device are you using?

_No response_

### Operating System

_No response_

### What browsers are you seeing the problem on?

_No response_

### Browser version

_No response_

### Additional context

_No response_

### Tips for developers

Before tackling the bug, please use `git bisect` (see https://git-scm.com/docs/git-bisect) to investigate which PR caused it (you only need to go back as far as commit https://github.com/oppia/oppia/commits/9a334e9). If you find the PR, leave a comment on this issue pointing to it, or just say that it happened before commit 9a334e9 if you could reproduce it there. This will help us fix the issue by reverting the faulty PR.

Also, if this is your first issue, please make sure to follow https://github.com/oppia/oppia/wiki/Contributing-code-to-Oppia#choosing-a-good-first-issue and https://github.com/oppia/oppia/wiki/Contributing-code-to-Oppia#setting-things-up before claiming it. Thanks!



Discussion:
Error thrown here: https://github.com/oppia/oppia/blob/develop/core/domain/story_fetchers.py#L326, when fetching stories here: https://github.com/oppia/oppia/blob/develop/core/controllers/contributor_dashboard.py#L379. Though this seems like an issue with a corrupt topic on the test server (topic with an invalid story reference that was probably deleted). On our side, we could set `strict=False` in the `story_fetchers.get_stories_by_ids()` call and filter out `None` stories to account for this.
Hi @sagangwee, I'm wiling to work on this bug; I think it's a good first issue for me. For the change itself, I've gone ahead and modified the contributor_dashboard.py to set strict to False, and then skip None stories in the following loop. If this is assigned to me, I'll also add some test logic. Assuming no unforeseen issues with testing, I can have the PR ready by tomorrow. Thank you!
![image](https://github.com/oppia/oppia/assets/87464153/dcea1ea8-9044-422e-acd3-b005bb32eea6)

@jakeump Seems reasonable, go for it. Thanks!
Error thrown here: https://github.com/oppia/oppia/blob/develop/core/domain/story_fetchers.py#L326, when fetching stories here: https://github.com/oppia/oppia/blob/develop/core/controllers/contributor_dashboard.py#L379. Though this seems like an issue with a corrupt topic on the test server (topic with an invalid story reference that was probably deleted). On our side, we could set `strict=False` in the `story_fetchers.get_stories_by_ids()` call and filter out `None` stories to account for this.
Hi @sagangwee, I'm wiling to work on this bug; I think it's a good first issue for me. For the change itself, I've gone ahead and modified the contributor_dashboard.py to set strict to False, and then skip None stories in the following loop. If this is assigned to me, I'll also add some test logic. Assuming no unforeseen issues with testing, I can have the PR ready by tomorrow. Thank you!
![image](https://github.com/oppia/oppia/assets/87464153/dcea1ea8-9044-422e-acd3-b005bb32eea6)

@jakeump Seems reasonable, go for it. Thanks!

Resolving patch:
diff --git a/core/controllers/contributor_dashboard.py b/core/controllers/contributor_dashboard.py
--- a/core/controllers/contributor_dashboard.py
+++ b/core/controllers/contributor_dashboard.py
@@ -383,10 +383,12 @@ def _get_reviewable_exploration_opportunity_summaries(
                 for reference in topic.get_all_story_references()
                 if reference.story_is_published
             ],
-            strict=True
+            strict=False
         )
         topic_exp_ids = []
         for story in topic_stories:
+            if story is None:
+                continue
             for node in story.story_contents.get_ordered_nodes():
                 if node.exploration_id is None:
                     raise Exception(


Test patch:
diff --git a/core/controllers/contributor_dashboard_test.py b/core/controllers/contributor_dashboard_test.py
--- a/core/controllers/contributor_dashboard_test.py
+++ b/core/controllers/contributor_dashboard_test.py
@@ -513,6 +513,37 @@ def test_raises_error_if_story_contain_none_exploration_id(self) -> None:
                     params={'topic_name': 'topic'}
                 )
 
+    def test_skip_story_if_story_is_none(self) -> None:
+        # Create a new exploration and linked story.
+        continue_state_name = 'continue state'
+        exp_100 = self.save_new_linear_exp_with_state_names_and_interactions(
+            '100',
+            self.owner_id,
+            ['Introduction', continue_state_name, 'End state'],
+            ['TextInput', 'Continue'],
+            category='Algebra',
+            correctness_feedback_enabled=True
+        )
+        self.publish_exploration(self.owner_id, exp_100.id)
+        self.create_story_for_translation_opportunity(
+            self.owner_id, self.admin_id, 'story_id_100', self.topic_id,
+            exp_100.id)
+        corrupt_story = None
+        swap_with_corrupt_story = self.swap_to_always_return(
+            story_fetchers, 'get_stories_by_ids', [corrupt_story]
+        )
+        self.login(self.CURRICULUM_ADMIN_EMAIL)
+
+        # Get translation opportunities with 'None' story.
+        with swap_with_corrupt_story:
+            response = self.get_json(
+                '%s' % feconf.REVIEWABLE_OPPORTUNITIES_URL,
+                params={'topic_name': 'topic'}
+            )
+
+        # The 'None' story should be skipped.
+        self.assertEqual(len(response['opportunities']), 0)
+
     def test_get_reviewable_translation_opportunities_when_state_is_removed(
         self
     ) -> None: