Repository: oppia/oppia

Issue:
[SEO] Fix titles - duplicate titles & titles that are too short
**Is your feature request related to a problem? Please describe.**
There are multiple pages with duplicate titles and multiple pages with titles that are too short. 
**Issue 1 for SEO: Duplicate Titles**
The ones with duplicate titles are:
https://www.oppia.org/community-library
https://www.oppia.org/math/fractions
https://www.oppia.org/learn/math
Looks like the page title has been changed through javascript. Eg: https://www.oppia.org/learn/math page
![image](https://user-images.githubusercontent.com/85778814/123713410-35a1ff80-d829-11eb-9fea-705426d4bd91.png)
However, search engines still get the title as just "Oppia"
![image](https://user-images.githubusercontent.com/85778814/123713490-63874400-d829-11eb-9de8-46ae559d76ee.png)

**Issue 2 for SEO: Titles too short**
Pages with titles too short:
https://www.oppia.org/about
https://www.oppia.org/donate
https://www.oppia.org/get-started
https://www.oppia.org/contact

Evidence from SEO report:
![image](https://user-images.githubusercontent.com/85778814/123713115-941aae00-d828-11eb-9a5c-b69c6141fcc2.png)

**Describe the solution you'd like**
Recommendations:
1. https://www.oppia.org/community-library: Update <title> from "Oppia" to "Community Library Lessons | Free Learning for All | Oppia"
2. https://www.oppia.org/math/fractions: Update <title> from "Oppia" to "Learn Fractions | Add, Subtract, Multiply and Divide | Oppia"
3. https://www.oppia.org/learn/math: Update <title> from "Oppia" to "Learn Math | Free Learning for All | Oppia"
4. https://www.oppia.org/about: Update <title> from "About | Oppia" to "About Us| Free Learning for All | Oppia"
5. https://www.oppia.org/donate: Update <title> from "Donate - Oppia" to "Donate | Make a Positive Impact | Oppia"
6. https://www.oppia.org/get-started: Update <title> from "Get Started - Oppia" to "Exploration| How to Create an Exploration | Oppia". Also change URL to https://www.oppia.org/how-to-create-an-exploration
7. https://www.oppia.org/contact: Update <title> from "Contact | Oppia" to "How to Contact Us | Oppia"




Discussion:

Resolving patch:
diff --git a/scripts/run_mypy_checks.py b/scripts/run_mypy_checks.py
--- a/scripts/run_mypy_checks.py
+++ b/scripts/run_mypy_checks.py
@@ -22,6 +22,7 @@
 
 import argparse
 import os
+import site
 import subprocess
 import sys
 
@@ -740,6 +741,7 @@
 MYPY_TOOLS_DIR = os.path.join(os.getcwd(), 'third_party', 'python3_libs')
 PYTHON3_CMD = 'python3'
 
+_PATHS_TO_INSERT = [MYPY_TOOLS_DIR, ]
 
 _PARSER = argparse.ArgumentParser(
     description='Python type checking using mypy script.'
@@ -775,11 +777,12 @@ def install_third_party_libraries(skip_install):
         install_third_party_libs.main()
 
 
-def get_mypy_cmd(files, using_global_mypy):
+def get_mypy_cmd(files, mypy_exec_path, using_global_mypy):
     """Return the appropriate command to be run.
 
     Args:
         files: list(list(str)). List having first element as list of string.
+        mypy_exec_path: str. Path of mypy executable.
         using_global_mypy: bool. Whether generated command should run using
             global mypy.
 
@@ -789,8 +792,7 @@ def get_mypy_cmd(files, using_global_mypy):
     if using_global_mypy:
         mypy_cmd = 'mypy'
     else:
-        mypy_cmd = os.path.join(
-            os.getcwd(), 'third_party', 'python3_libs', 'bin', 'mypy')
+        mypy_cmd = mypy_exec_path
     if files:
         cmd = [mypy_cmd, '--config-file', CONFIG_FILE_PATH] + files
     else:
@@ -811,7 +813,8 @@ def install_mypy_prerequisites(install_globally):
             installed globally.
 
     Returns:
-        int. The return code from installing prerequisites.
+        tuple(int, str). The return code from installing prerequisites and the
+        path of the mypy executable.
     """
     # TODO(#13398): Change MyPy installation after Python3 migration. Now, we
     # install packages globally for CI. In CI, pip installation is not in a way
@@ -832,11 +835,17 @@ def install_mypy_prerequisites(install_globally):
     output = process.communicate()
     if 'can\'t combine user with prefix' in output[1]:
         uextention_text = ['--user', '--prefix=', '--system']
-        process = subprocess.Popen(
+        new_process = subprocess.Popen(
             cmd + uextention_text, stdout=subprocess.PIPE,
             stderr=subprocess.PIPE)
-
-    return process.returncode
+        new_process.communicate()
+        _PATHS_TO_INSERT.append(os.path.join(site.USER_BASE, 'bin'))
+        mypy_exec_path = os.path.join(site.USER_BASE, 'bin', 'mypy')
+        return (new_process.returncode, mypy_exec_path)
+    else:
+        _PATHS_TO_INSERT.append(os.path.join(MYPY_TOOLS_DIR, 'bin'))
+        mypy_exec_path = os.path.join(MYPY_TOOLS_DIR, 'bin', 'mypy')
+        return (process.returncode, mypy_exec_path)
 
 
 def main(args=None):
@@ -853,7 +862,8 @@ def main(args=None):
     common.fix_third_party_imports()
 
     python_utils.PRINT('Installing Mypy and stubs for third party libraries.')
-    return_code = install_mypy_prerequisites(parsed_args.install_globally)
+    return_code, mypy_exec_path = install_mypy_prerequisites(
+        parsed_args.install_globally)
     if return_code != 0:
         python_utils.PRINT(
             'Cannot install Mypy and stubs for third party libraries.')
@@ -864,14 +874,10 @@ def main(args=None):
 
     python_utils.PRINT('Starting Mypy type checks.')
     cmd = get_mypy_cmd(
-        parsed_args.files, parsed_args.install_globally)
+        parsed_args.files, mypy_exec_path, parsed_args.install_globally)
 
-    _paths_to_insert = [
-        MYPY_TOOLS_DIR,
-        os.path.join(MYPY_TOOLS_DIR, 'bin'),
-    ]
     env = os.environ.copy()
-    for path in _paths_to_insert:
+    for path in _PATHS_TO_INSERT:
         env['PATH'] = '%s%s' % (path, os.pathsep) + env['PATH']
     env['PYTHONPATH'] = MYPY_TOOLS_DIR
 


Test patch:
diff --git a/scripts/run_mypy_checks_test.py b/scripts/run_mypy_checks_test.py
--- a/scripts/run_mypy_checks_test.py
+++ b/scripts/run_mypy_checks_test.py
@@ -72,7 +72,7 @@ def mock_popen_failure(
             ['dir1/', 'dir2/'])
 
         def mock_install_mypy_prerequisites_success(unused_ci):
-            return 0
+            return (0, self.mypy_cmd_path)
         self.swap_install_success = self.swap(
             run_mypy_checks, 'install_mypy_prerequisites',
             mock_install_mypy_prerequisites_success)
@@ -99,7 +99,7 @@ def communicate(self):
             os.getcwd(), 'third_party', 'python3_libs', 'bin', 'mypy')
 
         def mock_install_mypy_prerequisites(unused_ci):
-            return 0
+            return (0, self.mypy_cmd_path)
         self.mypy_install_swap = self.swap_with_checks(
             run_mypy_checks, 'install_mypy_prerequisites',
             mock_install_mypy_prerequisites)
@@ -118,13 +118,15 @@ def test_get_mypy_cmd_without_files(self):
         ]
         with self.files_swap:
             with self.directories_swap:
-                cmd = run_mypy_checks.get_mypy_cmd(None, False)
+                cmd = run_mypy_checks.get_mypy_cmd(
+                    None, self.mypy_cmd_path, False)
                 self.assertEqual(cmd, expected_cmd)
 
     def test_get_mypy_cmd_for_ci(self):
         with self.files_swap:
             with self.directories_swap:
-                cmd = run_mypy_checks.get_mypy_cmd(None, True)
+                cmd = run_mypy_checks.get_mypy_cmd(
+                    None, self.mypy_cmd_path, True)
                 self.assertEqual(cmd[0], 'mypy')
 
     def test_get_mypy_cmd_with_files(self):
@@ -135,30 +137,32 @@ def test_get_mypy_cmd_with_files(self):
         with self.files_swap:
             with self.directories_swap:
                 cmd = run_mypy_checks.get_mypy_cmd(
-                    ['file1.py', 'file2.py'], False)
+                    ['file1.py', 'file2.py'], self.mypy_cmd_path, False)
                 self.assertEqual(cmd, expected_cmd)
 
     def test_install_mypy_prerequisites(self):
         with self.popen_swap_success:
-            code = run_mypy_checks.install_mypy_prerequisites(False)
+            code, path = run_mypy_checks.install_mypy_prerequisites(False)
             self.assertEqual(code, 0)
+            self.assertEqual(path, self.mypy_cmd_path)
 
     def test_install_mypy_prerequisites_for_ci(self):
         with self.popen_swap_success:
-            code = run_mypy_checks.install_mypy_prerequisites(True)
+            code, _ = run_mypy_checks.install_mypy_prerequisites(True)
             self.assertEqual(code, 0)
 
     def test_install_mypy_prerequisites_with_user_prefix_error(self):
         with self.popen_swap_user_prefix_error:
-            code = run_mypy_checks.install_mypy_prerequisites(False)
+            code, path = run_mypy_checks.install_mypy_prerequisites(False)
             self.assertEqual(code, 0)
+            self.assertNotEqual(path, self.mypy_cmd_path)
 
     def test_install_mypy_prerequisites_with_wrong_script(self):
         with self.popen_swap_failure:
             with self.swap(
                 run_mypy_checks, 'MYPY_REQUIREMENTS_FILE_PATH',
                 'scripts.wrong'):
-                code = run_mypy_checks.install_mypy_prerequisites(False)
+                code, _ = run_mypy_checks.install_mypy_prerequisites(False)
                 self.assertEqual(code, 1)
 
     def test_running_script_without_mypy_errors(self):