Repository: oppia/oppia

Issue:
For logged-in users, replace the splash page with the "My Explorations" page.
Logged-in users don't really need to keep seeing the splash page. Instead, if they are visiting "/", they should automatically be taken to their "My Explorations" page (or the equivalent of their dashboard). They should still be able to get to the gallery via going to "/gallery" or clicking the Oppia icon in the left part of the navbar.

The experience for non-logged-in users should remain the same.



Discussion:
@seanlip  Sorry for such high number of commits. Was facing some linter issue.
Discussed it with @wxyxinyu on gitter

Some notes:
- Oppia isn't a single-page app, so it would be better to do the re-routing in the backend. Otherwise we'll load '/' and then immediately reload the dashboard, which seems wasteful.
- We should test the following:
  - When logged-in or logged-out, "/gallery" goes to the gallery page
  - When logged-in, "/my_explorations" goes to the "my explorations" page
  - When the user visits "/", there's a server-side redirect to "/gallery" if the user is not logged in, and a server-side redirect to "/my_explorations" if the user is logged in
- There is one potential snag. Go to "/" when you're not logged in, then click on the "Create Exploration" button at the top right. Currently, you'll be taken to a login screen, and then back to the gallery (and the introductory "create" modal appears). Instead, I think the user should still be taken to the login screen, but then to "/my_explorations" instead, and the "create" modal should appear in similar fashion.

@seanlip  Sorry for bugging you again about this, but my latest implementation involved re-routing through the server side, but presubmit checks failed with 1 error, 1 failure. Any ideas on how should I proceed further ?

Also, @brunnre8 made me realize that there wasn't any need for reverting the commit and re-applying it later, since the initial commit (with `--no-verify`) will simply tell git not to execute any hooks, so I'll take care of that from now on.

Hi @526avijitgupta, I think it depends on the error/failure -- you'll have to look at it and analyze it to figure out what's wrong. If you post it here, maybe I can help you.

Ah, when I closed the PR, I forgot to mention that it would probably be sensible to just restart from a new fresh branch off of 'develop'. That will keep the commit history clean. We can do that later, too, just before you submit another PR, if you prefer!

@seanlip I created a [Gist](https://gist.github.com/526avijitgupta/5dbcaada2d0338bb252c) for that.

Okay, I'll start from a new branch. And actually that's exactly what I did for the recent commits.

Oh, sorry, I misinterpreted -- all the previous commits are referenced within this issue, so I just assumed they were on the same branch. My apologies.

I took a look at the gist. It looks like two backend tests fail, whereas I assume they pass on 'develop'. Thus, what you'll need to do is read those two backend tests and understand why they behave differently in develop vs your branch. You can read more about tests [here](https://github.com/oppia/oppia/wiki/Running-Tests), including instructions for running just one of the tests in isolation -- if you do that, you'll be able to see a more detailed error log.

Once you understand why the failing tests behave differently in the two branches, you'll need to decide whether the old behaviour is correct (and amend your code accordingly so that the test passes), or if the test expectations should be changed (in which case you'll need to modify the test). It would also be a good idea to add new tests to ensure that all the specifications of the issue are covered.

Hope this helps!

@seanlip Just realized, it's maybe because I'm performing redirects instead of replacement. So it is recieving status codes of 302, instead of 200/403. Your thoughts ?

Yes, a 302 status code arises when you have a redirect. I think we have tests that deal with that sort of thing -- see e.g. profile_test.py, home_test.py.

@seanlip I am pretty sure redirect is the issue here, and the logs also seem to testify this:

https://gist.github.com/526avijitgupta/5dbcaada2d0338bb252c#file-test-fail-L132-L137

https://gist.github.com/526avijitgupta/5dbcaada2d0338bb252c#file-test-fail-L195-L198

https://gist.github.com/526avijitgupta/5dbcaada2d0338bb252c#file-test-fail-L156

Yes, sorry, I was unclear -- I was agreeing that the redirect is the issue here. For the next steps, I think the process I described in https://github.com/oppia/oppia/issues/1533#issuecomment-190607919 still applies.


Resolving patch:
diff --git a/core/controllers/galleries.py b/core/controllers/galleries.py
--- a/core/controllers/galleries.py
+++ b/core/controllers/galleries.py
@@ -84,7 +84,7 @@ def get(self):
             'allow_yaml_file_upload': ALLOW_YAML_FILE_UPLOAD.value,
             'gallery_login_redirect_url': (
                 current_user_services.create_login_url(
-                    feconf.GALLERY_CREATE_MODE_URL)),
+                    feconf.MY_EXPLORATIONS_CREATE_MODE_URL)),
             'has_fully_registered': bool(
                 self.user_id and
                 user_services.has_fully_registered(self.user_id)),
diff --git a/feconf.py b/feconf.py
--- a/feconf.py
+++ b/feconf.py
@@ -348,9 +348,10 @@ def get_empty_ratings():
 FEEDBACK_THREAD_URL_PREFIX = '/threadhandler'
 FEEDBACK_THREADLIST_URL_PREFIX = '/threadlisthandler'
 GALLERY_URL = '/gallery'
-GALLERY_CREATE_MODE_URL = '%s?mode=create' % GALLERY_URL
 GALLERY_DATA_URL = '/galleryhandler/data'
 LEARN_GALLERY_URL = '/learn'
+MY_EXPLORATIONS_URL = '/my_explorations'
+MY_EXPLORATIONS_CREATE_MODE_URL = '%s?mode=create' % MY_EXPLORATIONS_URL
 NEW_EXPLORATION_URL = '/contributehandler/create_new'
 PLAYTEST_QUEUE_URL = '/playtest'
 RECENT_COMMITS_DATA_URL = '/recentcommitshandler/recent_commits'
diff --git a/main.py b/main.py
--- a/main.py
+++ b/main.py
@@ -30,6 +30,7 @@
 from core.controllers import reader
 from core.controllers import recent_commits
 from core.controllers import resources
+from core.domain import user_services
 from core.platform import models
 import feconf
 # pylint: enable=relative-import
@@ -61,6 +62,15 @@ def get(self):
         pass
 
 
+class HomePageRedirectHandler(base.BaseHandler):
+    "Check whether user is logged in or logged out and perform redirects on '/'"
+    def get(self):
+        if self.user_id and user_services.has_fully_registered(self.user_id):
+            self.redirect(feconf.MY_EXPLORATIONS_URL)
+        else:
+            self.redirect(feconf.GALLERY_URL)
+
+
 def get_redirect_route(regex_route, handler, name, defaults=None):
     """Returns a route that redirects /foo/ to /foo.
 
@@ -171,7 +181,8 @@ def ui_access_wrapper(self, *args, **kwargs):
         r'/value_generator_handler/<generator_id>',
         resources.ValueGeneratorHandler, 'value_generator_handler'),
 
-    get_redirect_route(r'/', galleries.GalleryPage, 'gallery_page'),
+    get_redirect_route(r'/', HomePageRedirectHandler, 'home_page'),
+
     get_redirect_route(
         r'%s' % feconf.GALLERY_URL, galleries.GalleryPage, 'gallery_page'),
     get_redirect_route(


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
@@ -129,11 +129,11 @@ def test_change_rights(self):
             BOTH_MODERATOR_AND_ADMIN_EMAIL, BOTH_MODERATOR_AND_ADMIN_USERNAME)
 
         # Navigate to any page. The role is not set.
-        self.testapp.get('/').mustcontain(no=['/moderator', '/admin'])
+        self.testapp.get('/gallery').mustcontain(no=['/moderator', '/admin'])
 
         # Log in as a superadmin. This gives access to /admin.
         self.login('superadmin@example.com', is_super_admin=True)
-        self.testapp.get('/').mustcontain('/admin', no=['/moderator'])
+        self.testapp.get('/gallery').mustcontain('/admin', no=['/moderator'])
 
         # Add a moderator, an admin, and a person with both roles, then log
         # out.
@@ -164,9 +164,10 @@ def test_change_rights(self):
             '/moderator', no=['/admin'])
         self.logout()
 
-        # Log in as a both-moderator-and-admin. Only '(Admin)' is shown in the
-        # navbar.
+        # Log in as a both-moderator-and-admin.
+        # Only '(Admin)' is shown in the navbar.
         self.login(BOTH_MODERATOR_AND_ADMIN_EMAIL)
+        self.assertEqual(self.testapp.get('/').status_int, 302)
         self.testapp.get(feconf.GALLERY_URL).mustcontain(
             '/moderator', no=['/admin'])
         self.logout()
diff --git a/core/controllers/base_test.py b/core/controllers/base_test.py
--- a/core/controllers/base_test.py
+++ b/core/controllers/base_test.py
@@ -38,6 +38,10 @@
 
 class BaseHandlerTest(test_utils.GenericTestBase):
 
+    def setUp(self):
+        super(BaseHandlerTest, self).setUp()
+        self.signup('user@example.com', 'user')
+
     def test_dev_indicator_appears_in_dev_and_not_in_production(self):
         """Test dev indicator appears in dev and not in production."""
 
@@ -87,6 +91,21 @@ def test_requests_for_invalid_paths(self):
         response = self.testapp.put('/gallery/extra', {}, expect_errors=True)
         self.assertEqual(response.status_int, 404)
 
+    def test_redirect_in_both_logged_in_and_logged_out_states(self):
+        "Test for a redirect in both logged in and logged out states on '/'."
+
+        # Logged out state
+        response = self.testapp.get('/')
+        self.assertEqual(response.status_int, 302)
+        self.assertIn('gallery', response.headers['location'])
+
+        # Login and assert that there is a redirect
+        self.login('user@example.com')
+        response = self.testapp.get('/')
+        self.assertEqual(response.status_int, 302)
+        self.assertIn('my_explorations', response.headers['location'])
+        self.logout()
+
 
 class CsrfTokenManagerTest(test_utils.GenericTestBase):
 
diff --git a/core/controllers/home_test.py b/core/controllers/home_test.py
--- a/core/controllers/home_test.py
+++ b/core/controllers/home_test.py
@@ -26,8 +26,9 @@ class HomePageTest(test_utils.GenericTestBase):
     def test_logged_out_homepage(self):
         """Test the logged-out version of the home page."""
         response = self.testapp.get('/')
-        self.assertEqual(response.status_int, 200)
-        response.mustcontain(
+        self.assertEqual(response.status_int, 302)
+        self.assertIn('gallery', response.headers['location'])
+        response.follow().mustcontain(
             'Your personal tutor',
             'Oppia - Gallery', 'About', 'Sign in', no=['Logout'])