Repository: oppia/oppia

Issue:
Automatically generate a few explorations with some features such as rating, stats to speed up development process.
We should have a feature in admin development panel which auto generates a few explorations (say 5). Out of the generated explorations some will have a rating (not N/A), some will have a few statistics. This would be useful when we are testing features related to top rated explorations, or statistics of exploration as currently we have to do these things manually (for eg, to generate a explorations with rating we have to play them and then give them a rating).
(Thanks @seanlip)



Discussion:
Actually let's maybe generate 30 explorations, with 20 or so belonging to a single user -- then we have a nice way to test out that user's dashboard page as well and see how it behaves under some load. It would be nice to add some feedback/suggestions for some of these explorations, too.

I have been wanting this for so long. I'll take this issue on as part of my mission to get a Hacktoberfest t-shirt, and because it's much needed. I may extend it to populate other values through the admin panel, too.

@BenHenning, are you working on this? 

Hi @BenHenning i've unassigned you for now, feel free to re-assign yourself if/when you have time.
Just a note: feel free to tackle this in small parts -- e.g. a button for "create 50 explorations" may be sufficient for now. You (or someone else) can add rating/stats later, as needed.

Also, I think @souravbadami is interested in this, so /cc-ing him here.
Also /cc @Arunabh98 @wxyxinyu 
Note: see also #1204, which seems related.

Resolving patch:
diff --git a/core/controllers/admin.py b/core/controllers/admin.py
--- a/core/controllers/admin.py
+++ b/core/controllers/admin.py
@@ -15,6 +15,7 @@
 """Controllers for the admin view."""
 
 import logging
+import random
 
 import jinja2
 
@@ -25,6 +26,7 @@
 from core.domain import collection_services
 from core.domain import config_domain
 from core.domain import config_services
+from core.domain import exp_domain
 from core.domain import exp_services
 from core.domain import recommendations_services
 from core.domain import rights_manager
@@ -179,6 +181,23 @@ def post(self):
             elif self.payload.get('action') == 'reload_collection':
                 collection_id = self.payload.get('collection_id')
                 self._reload_collection(collection_id)
+            elif self.payload.get('action') == 'generate_dummy_explorations':
+                num_dummy_exps_to_generate = self.payload.get(
+                    'num_dummy_exps_to_generate')
+                num_dummy_exps_to_publish = self.payload.get(
+                    'num_dummy_exps_to_publish')
+                if not isinstance(num_dummy_exps_to_generate, int):
+                    raise self.InvalidInputException(
+                        '%s is not a number' % num_dummy_exps_to_generate)
+                elif not isinstance(num_dummy_exps_to_publish, int):
+                    raise self.InvalidInputException(
+                        '%s is not a number' % num_dummy_exps_to_publish)
+                elif num_dummy_exps_to_generate < num_dummy_exps_to_publish:
+                    raise self.InvalidInputException(
+                        'Generate count cannot be less than publish count')
+                else:
+                    self._generate_dummy_explorations(
+                        num_dummy_exps_to_generate, num_dummy_exps_to_publish)
             elif self.payload.get('action') == 'clear_search_index':
                 exp_services.clear_search_index()
             elif self.payload.get('action') == 'save_config_properties':
@@ -282,6 +301,43 @@ def _reload_collection(self, collection_id):
         else:
             raise Exception('Cannot reload a collection in production.')
 
+    def _generate_dummy_explorations(
+            self, num_dummy_exps_to_generate, num_dummy_exps_to_publish):
+        """
+        Generates and publishes the given number of dummy explorations.
+
+        Args:
+            num_dummy_exps_to_generate: int. Count of dummy explorations to
+                be generated.
+            num_dummy_exps_to_publish: int. Count of explorations to
+                be published.
+
+        Raises:
+            Exception: Environment is not DEVMODE.
+        """
+
+        if feconf.DEV_MODE:
+            logging.info(
+                '[ADMIN] %s generated %s number of dummy explorations' %
+                (self.user_id, num_dummy_exps_to_generate))
+            possible_titles = ['Hulk Neuroscience', 'Quantum Starks',
+                               'Wonder Anatomy',
+                               'Elvish, language of "Lord of the Rings',
+                               'The Science of Superheroes']
+            for i in range(num_dummy_exps_to_generate):
+                title = random.choice(possible_titles)
+                category = random.choice(feconf.SEARCH_DROPDOWN_CATEGORIES)
+                new_exploration_id = exp_services.get_new_exploration_id()
+                exploration = exp_domain.Exploration.create_default_exploration(
+                    new_exploration_id, title=title, category=category,
+                    objective='Dummy Objective')
+                exp_services.save_new_exploration(self.user_id, exploration)
+                if i <= num_dummy_exps_to_publish - 1:
+                    rights_manager.publish_exploration(
+                        self.user_id, new_exploration_id)
+        else:
+            raise Exception('Cannot generate dummy explorations in production.')
+
 
 class AdminRoleHandler(base.BaseHandler):
     """Handler for roles tab of admin page. Used to view and update roles."""


Test patch:
diff --git a/core/controllers/admin_test.py b/core/controllers/admin_test.py
--- a/core/controllers/admin_test.py
+++ b/core/controllers/admin_test.py
@@ -17,12 +17,15 @@
 from core.controllers import admin
 from core.controllers import base
 from core.domain import exp_domain
+from core.domain import exp_services
 from core.domain import stats_domain
 from core.domain import stats_services
 from core.tests import test_utils
+
 import feconf
 
 
+
 BOTH_MODERATOR_AND_ADMIN_EMAIL = 'moderator.and.admin@example.com'
 BOTH_MODERATOR_AND_ADMIN_USERNAME = 'moderatorandadm1n'
 
@@ -105,6 +108,60 @@ def test_change_about_page_config_property(self):
         self.assertIn(new_config_value, response.body)
 
 
+
+class GenerateDummyExplorationsTest(test_utils.GenericTestBase):
+    """ Test the conditions for generation of dummy explorations."""
+
+    def test_generate_count_greater_than_publish_count(self):
+        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        response = self.testapp.get('/admin')
+        csrf_token = self.get_csrf_token_from_response(response)
+        self.post_json('/adminhandler', {
+            'action': 'generate_dummy_explorations',
+            'num_dummy_exps_to_generate': 10,
+            'num_dummy_exps_to_publish': 3
+        }, csrf_token)
+        generated_exps = exp_services.get_all_exploration_summaries()
+        published_exps = exp_services.get_recently_published_exp_summaries(5)
+        self.assertEqual(len(generated_exps), 10)
+        self.assertEqual(len(published_exps), 3)
+
+    def test_generate_count_equal_to_publish_count(self):
+        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        response = self.testapp.get('/admin')
+        csrf_token = self.get_csrf_token_from_response(response)
+        self.post_json('/adminhandler', {
+            'action': 'generate_dummy_explorations',
+            'num_dummy_exps_to_generate': 2,
+            'num_dummy_exps_to_publish': 2
+        }, csrf_token)
+        generated_exps = exp_services.get_all_exploration_summaries()
+        published_exps = exp_services.get_recently_published_exp_summaries(5)
+        self.assertEqual(len(generated_exps), 2)
+        self.assertEqual(len(published_exps), 2)
+
+    def test_generate_count_less_than_publish_count(self):
+        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        response = self.testapp.get('/admin')
+        csrf_token = self.get_csrf_token_from_response(response)
+        generated_exps_response = self.post_json(
+            '/adminhandler', {
+                'action': 'generate_dummy_explorations',
+                'num_dummy_exps_to_generate': 2,
+                'num_dummy_exps_to_publish': 5
+            },
+            csrf_token=csrf_token,
+            expect_errors=True,
+            expected_status_int=400)
+        self.assertEqual(generated_exps_response['code'], 400)
+        generated_exps = exp_services.get_all_exploration_summaries()
+        published_exps = exp_services.get_recently_published_exp_summaries(5)
+        self.assertEqual(len(generated_exps), 0)
+        self.assertEqual(len(published_exps), 0)
+
 class AdminRoleHandlerTest(test_utils.GenericTestBase):
     """Checks the user role handling on the admin page."""