Repository: oppia/oppia

Issue:
Implement configuration to re-route all Oppia traffic for non-admins to a static page
We need an admin-controlled configuration bit which, when enabled (along with a ``feconf`` flag) will re-route all non-admin Oppia traffic to a static page and ensure no users can interact with any of the data providers, databases, or pages on Oppia. This will be used for the answer migration while the site is down (or really just serving this static page). The contents of the page should be generic so that it can be reused in the future. The page should not interact with any of the Oppia backend controllers or models.


Discussion:

Resolving patch:
diff --git a/core/controllers/pages.py b/core/controllers/pages.py
--- a/core/controllers/pages.py
+++ b/core/controllers/pages.py
@@ -21,6 +21,18 @@
 import feconf
 
 
+# TODO(bhenning): Convert this over to using action-based ACLs.
+def require_maintenance_mode(handler):
+    """Decorator that checks whether maintenance mode is enabled in feconf."""
+    def test_maintenance_mode(self, **kwargs):
+        if not feconf.ENABLE_MAINTENANCE_MODE:
+            raise self.UnauthorizedUserException(
+                'You cannot access this page unless the site is in '
+                'maintenance mode')
+        return handler(self, **kwargs)
+    return test_maintenance_mode
+
+
 class SplashPage(base.BaseHandler):
     """Landing page for Oppia."""
 
@@ -202,3 +214,11 @@ class ConsoleErrorPage(base.BaseHandler):
     def get(self):
         """Handles GET requests."""
         self.render_template('pages/tests/console_errors.html')
+
+
+class MaintenancePage(base.BaseHandler):
+    """Page describing that Oppia is down for maintenance mode."""
+
+    def get(self, *args, **kwargs):
+        """Handles GET requests."""
+        self.render_template('pages/maintenance/maintenance.html')
diff --git a/feconf.py b/feconf.py
--- a/feconf.py
+++ b/feconf.py
@@ -252,6 +252,11 @@ def get_empty_ratings():
 # merely avoids checking for whether the promo bar is enabled for every Oppia
 # page visited.
 ENABLE_PROMO_BAR = True
+# Whether to enable maintenance mode on the site. For non-admins, this redirects
+# all HTTP requests to the maintenance page. This is the only check which
+# determines whether the site is in maintenance mode to avoid queries to the
+# database by non-admins.
+ENABLE_MAINTENANCE_MODE = False
 
 EMAIL_INTENT_SIGNUP = 'signup'
 EMAIL_INTENT_DAILY_BATCH = 'daily_batch'
diff --git a/main.py b/main.py
--- a/main.py
+++ b/main.py
@@ -43,6 +43,7 @@
 import webapp2
 from webapp2_extras.routes import RedirectRoute
 
+current_user_services = models.Registry.import_current_user_services()
 transaction_services = models.Registry.import_transaction_services()
 
 
@@ -427,5 +428,21 @@ def ui_access_wrapper(self, *args, **kwargs):
     get_redirect_route(r'/<:.*>', base.Error404Handler),
 ]
 
+URLS_TO_SERVE = []
+
+if (feconf.ENABLE_MAINTENANCE_MODE and
+        not current_user_services.is_current_user_super_admin()):
+    # Show only the maintenance mode page.
+    URLS_TO_SERVE = [
+        get_redirect_route(r'%s' % feconf.ADMIN_URL, admin.AdminPage),
+        get_redirect_route(r'/adminhandler', admin.AdminHandler),
+        get_redirect_route(r'/adminjoboutput', admin.AdminJobOutput),
+        get_redirect_route(
+            r'/admintopicscsvdownloadhandler',
+            admin.AdminTopicsCsvDownloadHandler),
+        get_redirect_route(r'/<:.*>', pages.MaintenancePage)]
+else:
+    URLS_TO_SERVE = URLS
+
 app = transaction_services.toplevel_wrapper(  # pylint: disable=invalid-name
-    webapp2.WSGIApplication(URLS, debug=feconf.DEBUG))
+    webapp2.WSGIApplication(URLS_TO_SERVE, debug=feconf.DEBUG))


Test patch: