Repository: oppia/oppia

Issue:
[Code Health]: Deprecate the script python -m scripts.populate_sample_contributor_data. 
### Is your feature request related to a problem? Please describe.

As per the conversations from the CD Team group chats, we are planning to deprecate this script `python -m scripts.populate_sample_contributor_data.` The reason is that this script has been broken for a while and also we have come up with a (maybe) better way of populating the data in Contributor Dashboard. (That will be through Admin Page, issue for it is already being tracked here: https://github.com/oppia/oppia/issues/14698)

Link to Oppia-Wiki issue thread where some of this conversation can be seen: https://github.com/oppia/oppia-web-developer-docs/issues/296

### Describe the solution (or solutions) you'd like

Remove the code for this feature. Most likely there's a python file named as `populate_sample_contributor_data` inside scripts module which you would want to look at. And also check for its instances, if it's being used anywhere else in codebase (Perform a quick search) 

### Describe alternatives you've considered and rejected

_No response_

### Additional context

This issue involves removing the dead code for the script `python -m scripts.populate_sample_contributor_data.` So it doesn't really involves "steps to reproduce". 

For testing purposes, once the code has been removed try running the script and it should give an error like Module/File not found.
[Code Health]: Deprecate the script python -m scripts.populate_sample_contributor_data. 
### Is your feature request related to a problem? Please describe.

As per the conversations from the CD Team group chats, we are planning to deprecate this script `python -m scripts.populate_sample_contributor_data.` The reason is that this script has been broken for a while and also we have come up with a (maybe) better way of populating the data in Contributor Dashboard. (That will be through Admin Page, issue for it is already being tracked here: https://github.com/oppia/oppia/issues/14698)

Link to Oppia-Wiki issue thread where some of this conversation can be seen: https://github.com/oppia/oppia-web-developer-docs/issues/296

### Describe the solution (or solutions) you'd like

Remove the code for this feature. Most likely there's a python file named as `populate_sample_contributor_data` inside scripts module which you would want to look at. And also check for its instances, if it's being used anywhere else in codebase (Perform a quick search) 

### Describe alternatives you've considered and rejected

_No response_

### Additional context

This issue involves removing the dead code for the script `python -m scripts.populate_sample_contributor_data.` So it doesn't really involves "steps to reproduce". 

For testing purposes, once the code has been removed try running the script and it should give an error like Module/File not found.


Discussion:
Hi @Ash-2k3 I'd like to take a look at this issue and contribute to it. Can I?

@malimsZen Per the guidance at https://github.com/oppia/oppia/wiki/Contributing-code-to-Oppia#choosing-a-good-first-issue, please provide an explanation of what your PR will do (with names of files you're changing, what you plan to change in each file, etc.). If it looks good, we can assign you to this issue.

Please also follow the other instructions on that wiki page if you have not yet done so. Thanks!
Thank you for the feedback. Going through the guidance. Thanks!

Hi @Ash-2k3 I'd like to take a look at this issue and contribute to it. Can I?

@malimsZen Per the guidance at https://github.com/oppia/oppia/wiki/Contributing-code-to-Oppia#choosing-a-good-first-issue, please provide an explanation of what your PR will do (with names of files you're changing, what you plan to change in each file, etc.). If it looks good, we can assign you to this issue.

Please also follow the other instructions on that wiki page if you have not yet done so. Thanks!
Thank you for the feedback. Going through the guidance. Thanks!


Resolving patch:
diff --git a/scripts/populate_sample_contributor_data.py b/scripts/populate_sample_contributor_data.py
deleted file mode 100644
--- a/scripts/populate_sample_contributor_data.py
+++ /dev/null
@@ -1,288 +0,0 @@
-# coding: utf-8
-#
-# Copyright 2022 The Oppia Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS-IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""This script populates sample data for assisting development. After starting
-up a development server running Oppia, running this script does the following:
-    1. Create an admin user with the username "a" and assign curriculum,
-    translation, and question admin rights to "a".
-    2. Create a non-admin user with the username "b" and give the user "submit
-    question" rights.
-    3. Populate sample lessons for translations. This is achieved by reproducing
-    the "Load dummy new structures data" admin action.
-    4. Add the topics linked to the lessons above to a classroom. This is needed
-    for the topics, if published, to show up in the topic selectors and for the
-    linked opportunities to show up in the "Submit Question" tab.
-Note: The standard process for generating data is via the Admin > Activities
-tab. Here is why we use a script but not the standard process to execute the
-above workflow. In the above workflow, creating new users requires beginning
-and ending sessions several times, but ending sessions on the Admin page causes
-a "Registration session expired" error. This issue should be resolved in future
-if we want to execute the above workflow on the Admin page.
-"""
-
-from __future__ import annotations
-
-import hashlib
-import json
-
-from core import feconf
-from core.constants import constants
-from core.domain import classroom_config_domain
-from core.domain import classroom_config_services
-
-import requests
-from typing import Dict, Final, List
-
-PORT_NUMBER_FOR_GAE_SERVER: Final = 8181
-# TODO(#18260): Change this when we permanently move to the Dockerized Setup.
-
-FIREBASE_HOST = '0.0.0.0' if feconf.OPPIA_IS_DOCKERIZED else 'localhost'
-FIREBASE_AUTH_EMULATOR_HOST: Final = (
-    '%s:%s' % (FIREBASE_HOST, feconf.FIREBASE_EMULATOR_PORT))
-FIREBASE_SIGN_IN_URL: Final = (
-    'http://%s/identitytoolkit.googleapis.com/v1/accounts:signInWithPassword'
-    % FIREBASE_AUTH_EMULATOR_HOST)
-FIREBASE_SIGN_UP_URL: Final = (
-    'http://%s/identitytoolkit.googleapis.com/v1/accounts:signUp'
-    % FIREBASE_AUTH_EMULATOR_HOST)
-
-SUPER_ADMIN_EMAIL: Final = feconf.ADMIN_EMAIL_ADDRESS
-SUPER_ADMIN_USERNAME: Final = 'a'
-SUPER_ADMIN_ROLES: Final = [
-    feconf.ROLE_ID_CURRICULUM_ADMIN, feconf.ROLE_ID_TRANSLATION_ADMIN,
-    feconf.ROLE_ID_QUESTION_ADMIN]
-
-CONTRIBUTOR_EMAIL: Final = 'contributor@example.com'
-CONTRIBUTOR_USERNAME: Final = 'b'
-
-CLASSROOM_NAME: Final = 'math'
-CLASSROOM_URL_FRAGMENT: Final = 'math'
-
-# Timeout for requests in seconds.
-TIMEOUT_SECS = 60
-
-
-class SampleDataInitializer:
-    """Contains functions that populate sample data by sending requests to the
-    development server.
-
-    Attributes:
-        session: object(Session). The requests.Session object to send requests
-            to the Oppia server.
-        base_url: str. The base url of the Oppia server.
-        csrf_token: str. The csrf token of the current session.
-    """
-
-    def __init__(self, base_url: str) -> None:
-        self.session = requests.session()
-        self.base_url = base_url
-        self.csrf_token = ''
-
-    def populate_data(self) -> None:
-        """Populate sample data to help develop for the contributor
-        dashboard.
-        """
-        self._sign_up_new_user(SUPER_ADMIN_EMAIL, SUPER_ADMIN_USERNAME)
-        self._sign_up_new_user(CONTRIBUTOR_EMAIL, CONTRIBUTOR_USERNAME)
-
-        self._sign_in(SUPER_ADMIN_EMAIL)
-        self.csrf_token = self._get_csrf_token()
-        self._assign_admin_roles(SUPER_ADMIN_ROLES, SUPER_ADMIN_USERNAME)
-        self._add_submit_question_rights(CONTRIBUTOR_USERNAME)
-        self._generate_sample_new_structures_data()
-        self._add_topics_to_classroom(CLASSROOM_NAME, CLASSROOM_URL_FRAGMENT)
-
-    def _sign_up_new_user(self, email: str, username: str) -> None:
-        """Sign up a new user based on email and username. The password is
-        generated automatically from email.
-        """
-        # In development mode, the "Sign In" button will call the function
-        # AuthService.signInWithEmail() in the file
-        # core/templates/services/auth.service.ts. That function generates a
-        # password through the MD5 hash of email addresses to save developers
-        # and end-to-end test authors the trouble of providing passwords. This
-        # script also uses the MD5 hash when creating a user in the Firebase
-        # Authentication emulator. When we want to sign in a user created using
-        # this script, clicking the "Sign In" button will generate a valid
-        # password which is the same as that in the emulator.
-        password = hashlib.md5(email.encode('utf-8')).hexdigest()
-        token_id = self._sign_up_on_firebase(email, password)
-        self._begin_session(token_id)
-
-        self._make_request('GET', '/signup?return_url=/')
-        self.csrf_token = self._get_csrf_token()
-
-        params = {
-            'payload': json.dumps({
-                'username': username,
-                'agreed_to_terms': True,
-                'default_dashboard': constants.DASHBOARD_TYPE_LEARNER,
-                'can_receive_email_updates': (
-                    feconf.DEFAULT_EMAIL_UPDATES_PREFERENCE
-                )
-            }),
-            'csrf_token': self.csrf_token
-        }
-
-        self._make_request('POST', feconf.SIGNUP_DATA_URL, params=params)
-
-        # End current session, i.e. log out.
-        self._make_request('GET', '/session_end')
-        self.csrf_token = ''
-
-    def _sign_up_on_firebase(
-        self, email: str, password: str
-    ) -> str:
-        """Signs up on Firebase, and returns the token id."""
-        token_id = requests.post(
-            FIREBASE_SIGN_UP_URL,
-            params={'key': 'fake-api-key'},
-            json={
-                'email': email,
-                'password': password
-            },
-            timeout=TIMEOUT_SECS,
-        ).json()['idToken']
-
-        return str(token_id)
-
-    def _sign_in(self, email: str) -> None:
-        """Begins a session with the given email, i.e. log in with the email."""
-        password = hashlib.md5(email.encode('utf-8')).hexdigest()
-        token_id = self._sign_in_on_firebase(email, password)
-        self._begin_session(token_id)
-
-    def _sign_in_on_firebase(
-        self, email: str, password: str
-    ) -> str:
-        """Signs in on Firebase, and returns the token id."""
-        token_id = requests.post(
-            FIREBASE_SIGN_IN_URL,
-            params={'key': 'fake-api-key'},
-            json={
-                'email': email,
-                'password': password
-            },
-            timeout=TIMEOUT_SECS,
-        ).json()['idToken']
-
-        return str(token_id)
-
-    def _begin_session(self, token_id: str) -> None:
-        """Begins a session with the given token id."""
-        headers = {'Authorization': 'Bearer %s' % token_id}
-        self._make_request('GET', '/session_begin', headers=headers)
-
-    def _get_csrf_token(self) -> str:
-        """Gets the CSRF token."""
-        response = self._make_request('GET', '/csrfhandler')
-        csrf_token = str(
-            json.loads(response.text[len(feconf.XSSI_PREFIX):])['token'])
-
-        return csrf_token
-
-    def _assign_admin_roles(self, roles: List[str], username: str) -> None:
-        """Assigns the given roles to the user with the given username."""
-        for role in roles:
-            params = {
-                'payload': json.dumps({
-                    'role': role,
-                    'username': username
-                }),
-                'csrf_token': self.csrf_token
-            }
-            self._make_request(
-                'PUT', feconf.ADMIN_ROLE_HANDLER_URL, params=params)
-
-    def _add_submit_question_rights(self, username: str) -> None:
-        """Adds submit question rights to the user with the given username."""
-        params = {
-            'payload': json.dumps({'username': username}),
-            'csrf_token': self.csrf_token
-        }
-
-        self._make_request(
-            'POST', '/contributionrightshandler/submit_question', params=params)
-
-    def _generate_sample_new_structures_data(self) -> None:
-        """Generates sample new structures data."""
-        params = {
-            'payload': json.dumps({
-                'action': 'generate_dummy_new_structures_data'}),
-            'csrf_token': self.csrf_token
-        }
-
-        self._make_request('POST', '/adminhandler', params=params)
-
-    def _add_topics_to_classroom(
-        self, classroom_name: str, classroom_url_fragment: str
-    ) -> None:
-        """Adds all dummy topics to a classroom."""
-        response = self._make_request(
-            'GET', '/topics_and_skills_dashboard/data')
-        topic_summary_dicts = json.loads(
-            response.text[len(feconf.XSSI_PREFIX):])['topic_summary_dicts']
-        topic_ids = [
-            topic_summary_dict['id'] for topic_summary_dict in
-            topic_summary_dicts]
-
-        math_classroom_dict: classroom_config_domain.ClassroomDict = {
-            'classroom_id': 'math_classroom_id',
-            'name': classroom_name,
-            'url_fragment': classroom_url_fragment,
-            'course_details': '',
-            'topic_list_intro': '',
-            'topic_id_to_prerequisite_topic_ids': dict.fromkeys(topic_ids, [])
-        }
-        math_classroom = classroom_config_domain.Classroom.from_dict(
-            math_classroom_dict)
-
-        classroom_config_services.create_new_classroom(math_classroom)
-
-    def _make_request(
-        self,
-        method: str,
-        url: str,
-        params: Dict[str, str] | None = None,
-        headers: Dict[str, str] | None = None
-    ) -> requests.Response:
-        """Makes a request to the Oppia server."""
-        if params is None:
-            params = {}
-        if headers is None:
-            headers = {}
-
-        response = self.session.request(
-            method, self.base_url + url, headers=headers, params=params)
-
-        return response
-
-
-def main() -> None:
-    """Populates data for contributor dashboard debugging."""
-    initializer = (
-        SampleDataInitializer(
-            base_url='http://localhost:%s' % PORT_NUMBER_FOR_GAE_SERVER
-        )
-    )
-    initializer.populate_data()
-
-
-# The 'no coverage' pragma is used as this line is un-testable. This is because
-# it will only be called when populate_sample_contributor_data.py used as a
-# script.
-if __name__ == '__main__': # pragma: no cover
-    main()


Test patch:
diff --git a/scripts/backend_test_shards.json b/scripts/backend_test_shards.json
--- a/scripts/backend_test_shards.json
+++ b/scripts/backend_test_shards.json
@@ -323,7 +323,6 @@
         "core.jobs.batch_jobs.rejecting_suggestion_for_invalid_content_ids_jobs_test",
         "core.jobs.batch_jobs.manual_voice_artist_name_job_test",
         "core.jobs.io.cache_io_test",
-        "scripts.populate_sample_contributor_data_test",
         "core.platform.secrets.cloud_secrets_services_test",
         "extensions.interactions.ItemSelectionInput.ItemSelectionInput_test",
         "extensions.interactions.SetInput.SetInput_test",
diff --git a/scripts/populate_sample_contributor_data_test.py b/scripts/populate_sample_contributor_data_test.py
deleted file mode 100644
--- a/scripts/populate_sample_contributor_data_test.py
+++ /dev/null
@@ -1,241 +0,0 @@
-# coding: utf-8
-#
-# Copyright 2022 The Oppia Authors. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS-IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Unit tests for scripts/populate_sample_data.py."""
-
-from __future__ import annotations
-
-from core import feconf
-from core.controllers import base
-from core.domain import opportunity_services
-from core.domain import question_fetchers
-from core.domain import skill_services
-from core.domain import story_fetchers
-from core.domain import topic_fetchers
-from core.domain import user_services
-from core.platform import models
-from core.platform.auth import firebase_auth_services_test
-from core.tests import test_utils
-from scripts import populate_sample_contributor_data
-
-import requests
-from typing import Dict, List, Optional
-import webtest
-
-auth_services = models.Registry.import_auth_services()
-
-
-class MockResponse:
-
-    def __init__(
-        self,
-        ok: bool = True,
-        json: Dict[str, str] | None = None,
-        status_code: int = 200,
-        reason: str = 'foo'
-    ) -> None:
-        if json is None:
-            json = {}
-        self.ok = ok
-        self.json_dict = json
-        self.status_code = status_code
-        self.reason = reason
-
-    def json(self) -> Dict[str, str]:
-        """Get json dict or raise ValueError if json_dict not a dict."""
-        if not isinstance(self.json_dict, dict):
-            raise ValueError('Payload not JSON.')
-        return self.json_dict
-
-
-class SampleDataInitializerTests(test_utils.GenericTestBase):
-
-    def setUp(self) -> None:
-        self.AUTO_CREATE_DEFAULT_SUPERADMIN_USER = False
-        super().setUp()
-        self.firebase_sdk_stub = (
-            firebase_auth_services_test.FirebaseAdminSdkStub())
-        self.firebase_sdk_stub.install(self)
-        self.token_by_email: Dict[str, str] = {}
-        self.token_of_current_user: Optional[str] = None
-        self.initializer = (
-            populate_sample_contributor_data.SampleDataInitializer(
-                base_url=''))
-
-        self.initializer.csrf_token = self.get_new_csrf_token()
-
-        self.request_swap = self.swap(
-            self.initializer.session,
-            'request',
-            self._mock_request)
-
-        self.post_to_firebase_swap = self.swap_with_checks(
-            requests, 'post',
-            self._mock_post_to_firebase,
-            expected_args=[
-                (populate_sample_contributor_data.FIREBASE_SIGN_UP_URL,),
-                (populate_sample_contributor_data.FIREBASE_SIGN_UP_URL,),
-                (populate_sample_contributor_data.FIREBASE_SIGN_IN_URL,)
-            ]
-        )
-
-    def tearDown(self) -> None:
-        self.firebase_sdk_stub.uninstall()
-        self.logout()
-        super().tearDown()
-
-    def _mock_request(
-        self,
-        method: str,
-        url: str,
-        params: Dict[str, str] | None = None,
-        headers: Dict[str, str] | None = None
-    ) -> webtest.TestResponse:
-        """Returns a mock response for the given request."""
-        if method == 'GET':
-            if url == '/session_begin':
-                assert headers is not None
-                cur_token = headers.get('Authorization', '').strip('Bearer ')
-                for email, token in self.token_by_email.items():
-                    if token == cur_token:
-                        self._mock_login_as_admin(email)
-                        break
-            with self.swap(
-                base, 'load_template', test_utils.mock_load_template
-            ):
-                return self.testapp.get(url, params=params, headers=headers)
-        if method == 'POST':
-            return self.testapp.post(url, params=params, headers=headers)
-        if method == 'PUT':
-            return self.testapp.put(url, params=params, headers=headers)
-
-    def _mock_post_to_firebase(
-        self,
-        url: str,
-        **kwargs: Dict[str, str]
-    ) -> MockResponse | None:
-        """Mock for the post request to Firebase. The request is for signing
-        up or signing in a user on Firebase.
-        """
-        email = kwargs['json']['email']
-
-        if url == populate_sample_contributor_data.FIREBASE_SIGN_UP_URL:
-            auth_id = self.get_auth_id_from_email(email)
-            self.token_by_email[email] = (
-                self.firebase_sdk_stub.create_user(auth_id, email))
-
-        self.token_of_current_user = self.token_by_email[email]
-        return MockResponse(json={'idToken': self.token_of_current_user})
-
-    def _mock_login_as_admin(self, email: str) -> None:
-        """Sets the environment variables to simulate a login of admin."""
-        self.login(email, is_super_admin=True)
-
-    def test_populate_data_is_called(self) -> None:
-        populate_data_swap = self.swap_with_call_counter(
-            populate_sample_contributor_data.SampleDataInitializer,
-            'populate_data')
-        with populate_data_swap as call_counter:
-            populate_sample_contributor_data.main()
-
-        self.assertEqual(call_counter.times_called, 1)
-
-    def test_populate_data(self) -> None:
-        with self.request_swap, self.post_to_firebase_swap:
-            self.initializer.populate_data()
-
-        self._assert_sign_up_new_user(
-            populate_sample_contributor_data.SUPER_ADMIN_EMAIL,
-            populate_sample_contributor_data.SUPER_ADMIN_USERNAME)
-        self._assert_sign_up_new_user(
-            populate_sample_contributor_data.CONTRIBUTOR_EMAIL,
-            populate_sample_contributor_data.CONTRIBUTOR_USERNAME)
-        self._assert_user_roles(
-            populate_sample_contributor_data.SUPER_ADMIN_USERNAME,
-            populate_sample_contributor_data.SUPER_ADMIN_ROLES)
-        self._assert_can_submit_question_suggestions(
-            populate_sample_contributor_data.CONTRIBUTOR_USERNAME)
-        self._assert_generate_sample_new_structures_data()
-        self._assert_topics_in_classroom(
-            populate_sample_contributor_data.CLASSROOM_NAME)
-
-    def _assert_user_roles(self, username: str, roles: List[str]) -> None:
-        """Asserts that the user has the given roles."""
-        user_settings = user_services.get_user_settings_from_username(username)
-        assert user_settings is not None
-        self.assertEqual(
-            user_settings.roles, [feconf.ROLE_ID_FULL_USER] + roles)
-
-    def _assert_can_submit_question_suggestions(self, username: str) -> None:
-        """Asserts that the user can submit question suggestions."""
-        user_id = user_services.get_user_id_from_username(username)
-        assert user_id is not None
-        self.assertTrue(user_services.can_submit_question_suggestions(user_id))
-
-    def _assert_generate_sample_new_structures_data(self) -> None:
-        """Asserts that the sample new structures data is generated."""
-        topic_summaries = topic_fetchers.get_all_topic_summaries()
-        self.assertEqual(len(topic_summaries), 1)
-
-        topic = topic_fetchers.get_topic_by_name('Dummy Topic 1')
-        assert topic is not None
-        story_id = topic.canonical_story_references[0].story_id
-        self.assertIsNotNone(
-            story_fetchers.get_story_by_id(story_id, strict=False))
-
-        skill_summaries = skill_services.get_all_skill_summaries()
-        self.assertEqual(len(skill_summaries), 3)
-
-        questions, _ = (
-            question_fetchers.get_questions_and_skill_descriptions_by_skill_ids(
-                10,
-                [
-                    skill_summaries[0].id,
-                    skill_summaries[1].id,
-                    skill_summaries[2].id
-                ],
-                0)
-        )
-        self.assertEqual(len(questions), 5)
-
-        translation_opportunities, _, _ = (
-            opportunity_services.get_translation_opportunities('hi', '', None))
-        self.assertEqual(len(translation_opportunities), 3)
-
-    def _assert_topics_in_classroom(self, classroom_name: str) -> None:
-        """Asserts that test topics are in the classroom."""
-        classroom_dict = self.get_json(
-            '%s/%s' % (feconf.CLASSROOM_DATA_HANDLER, classroom_name))
-        topic_summaries = topic_fetchers.get_all_topic_summaries()
-        topic_summary_dicts_from_classroom = classroom_dict[
-            'topic_summary_dicts']
-        for index, topic_summary in enumerate(topic_summaries):
-            topic_summary_dict = dict(topic_summary.to_dict())
-            topic_summary_dict_from_classroom = (
-                topic_summary_dicts_from_classroom[index])
-            topic_summary_dict['is_published'] = (
-                topic_summary_dict_from_classroom['is_published'])
-            self.assertEqual(
-                topic_summary_dict, topic_summary_dict_from_classroom)
-
-    def _assert_sign_up_new_user(self, email: str, username: str) -> None:
-        """Asserts that the function _mock_firebase_auth_create_user() is called
-        and a user with the given email and username is created.
-        """
-        self.assertIsNotNone(self.firebase_sdk_stub.get_user_by_email(email))
-        user_settings = user_services.get_user_settings_from_email(email)
-        assert user_settings is not None
-        self.assertEqual(user_settings.username, username)