Repository: oppia/oppia

Issue:
Implement the validate function
**Describe the bug**
The validate function in the literally-canvas-diagram-editor.component.ts has to be implemented once the data is saved.

**Additional context**
TODO as a part of milestone 1 part 2 of adding svg editor to rte.



Discussion:

Resolving patch:
diff --git a/core/domain/html_cleaner.py b/core/domain/html_cleaner.py
--- a/core/domain/html_cleaner.py
+++ b/core/domain/html_cleaner.py
@@ -118,8 +118,9 @@ def strip_html_tags(html_string):
 
 
 def get_image_filenames_from_html_strings(html_strings):
-    """Extracts the image filename from the oppia-noninteractive-image RTE
-    component from all the html strings passed in.
+    """Extracts the image filename from the oppia-noninteractive-image and
+    oppia-noninteractive-svgdiagram RTE component from all the html strings
+    passed in.
 
     Args:
         html_strings: list(str). List of HTML strings.
@@ -136,6 +137,10 @@ def get_image_filenames_from_html_strings(html_strings):
         if 'id' in rte_comp and rte_comp['id'] == 'oppia-noninteractive-image':
             filenames.append(
                 rte_comp['customization_args']['filepath-with-value'])
+        elif ('id' in rte_comp and
+              rte_comp['id'] == 'oppia-noninteractive-svgdiagram'):
+            filenames.append(
+                rte_comp['customization_args']['svg_filename-with-value'])
 
     return list(set(filenames))
 
diff --git a/extensions/rich_text_components/components.py b/extensions/rich_text_components/components.py
--- a/extensions/rich_text_components/components.py
+++ b/extensions/rich_text_components/components.py
@@ -120,13 +120,13 @@ def validate(cls, value_dict):
             raise Exception('Invalid filepath')
 
 
-class Svgeditor(BaseRteComponent):
-    """Class for Svgeditor component."""
+class Svgdiagram(BaseRteComponent):
+    """Class for Svgdiagram component."""
 
     @classmethod
     def validate(cls, value_dict):
-        """Validates Svgeditor component."""
-        super(Svgeditor, cls).validate(value_dict)
+        """Validates Svgdiagram component."""
+        super(Svgdiagram, cls).validate(value_dict)
         filename_re = r'^[A-Za-z0-9+/_-]*\.(svg)$'
         filename = value_dict['svg_filename-with-value']
         if not re.match(filename_re, filename):
diff --git a/feconf.py b/feconf.py
--- a/feconf.py
+++ b/feconf.py
@@ -550,8 +550,8 @@ def get_empty_ratings():
     'Math': {
         'dir': os.path.join(RTE_EXTENSIONS_DIR, 'Math')
     },
-    'Svgeditor': {
-        'dir': os.path.join(RTE_EXTENSIONS_DIR, 'svgeditor')
+    'Svgdiagram': {
+        'dir': os.path.join(RTE_EXTENSIONS_DIR, 'svgdiagram')
     },
     'Tabs': {
         'dir': os.path.join(RTE_EXTENSIONS_DIR, 'Tabs')
@@ -908,7 +908,7 @@ def get_empty_ratings():
             'oppia-noninteractive-collapsible': ['b', 'i', 'li', 'p', 'pre'],
             'oppia-noninteractive-video': ['b', 'i', 'li', 'p', 'pre'],
             'oppia-noninteractive-tabs': ['b', 'i', 'li', 'p', 'pre'],
-            'oppia-noninteractive-svgeditor': ['b', 'i', 'li', 'p', 'pre']
+            'oppia-noninteractive-svgdiagram': ['b', 'i', 'li', 'p', 'pre']
         },
         # Valid html tags in TextAngular.
         'ALLOWED_TAG_LIST': [
@@ -927,7 +927,7 @@ def get_empty_ratings():
             'oppia-noninteractive-collapsible',
             'oppia-noninteractive-video',
             'oppia-noninteractive-tabs',
-            'oppia-noninteractive-svgeditor'
+            'oppia-noninteractive-svgdiagram'
         ]
     },
     'RTE_TYPE_CKEDITOR': {
@@ -945,7 +945,7 @@ def get_empty_ratings():
             'oppia-noninteractive-link': ['strong', 'em', 'li', 'p', 'pre'],
             'oppia-noninteractive-math': ['strong', 'em', 'li', 'p', 'pre'],
             'oppia-noninteractive-image': ['blockquote', 'li', '[document]'],
-            'oppia-noninteractive-svgeditor': [
+            'oppia-noninteractive-svgdiagram': [
                 'blockquote', 'li', '[document]'
             ],
             'oppia-noninteractive-collapsible': [
@@ -971,7 +971,7 @@ def get_empty_ratings():
             'oppia-noninteractive-collapsible',
             'oppia-noninteractive-video',
             'oppia-noninteractive-tabs',
-            'oppia-noninteractive-svgeditor'
+            'oppia-noninteractive-svgdiagram'
         ]
 
     }


Test patch:
diff --git a/core/domain/html_cleaner_test.py b/core/domain/html_cleaner_test.py
--- a/core/domain/html_cleaner_test.py
+++ b/core/domain/html_cleaner_test.py
@@ -221,8 +221,20 @@ def test_get_image_filenames_from_html_strings(self):
             '</oppia-noninteractive-image><oppia-noninteractive-image '
             'filepath-with-value="&quot;img4.svg&quot;" caption-with-value='
             '"&quot;&quot;" alt-with-value="&quot;Image&quot;">'
+            '</oppia-noninteractive-image>',
+            '<oppia-noninteractive-svgdiagram '
+            'svg_filename-with-value="&quot;img5.svg&quot;"'
+            ' alt-with-value="&quot;Image&quot;">'
+            '</oppia-noninteractive-svgdiagram><oppia-noninteractive-svgdiag'
+            'ram svg_filename-with-value="&quot;img6.svg&quot;"'
+            ' alt-with-value="&quot;Image&quot;">'
+            '</oppia-noninteractive-svgdiagram><oppia-noninteractive-image '
+            'filepath-with-value="&quot;img7.svg&quot;" caption-with-value='
+            '"&quot;&quot;" alt-with-value="&quot;Image&quot;">'
             '</oppia-noninteractive-image>'
         ]
         self.assertItemsEqual(
-            ['img.svg', 'img2.svg', 'img3.svg', 'img4.svg'],
+            [
+                'img.svg', 'img2.svg', 'img3.svg', 'img4.svg',
+                'img5.svg', 'img6.svg', 'img7.svg'],
             html_cleaner.get_image_filenames_from_html_strings(html_strings))
diff --git a/core/domain/rte_component_registry_test.py b/core/domain/rte_component_registry_test.py
--- a/core/domain/rte_component_registry_test.py
+++ b/core/domain/rte_component_registry_test.py
@@ -143,9 +143,9 @@ def test_rte_components_are_valid(self):
                 component_id)
             self.assertTrue(self._is_camel_cased(component_id))
 
-            # TODO(#9356): Remove this if condition once the Svgeditor
+            # TODO(#9356): Remove this if condition once the Svgdiagram
             # directive is created in the second part of 1st milestone.
-            if component_id == 'Svgeditor':
+            if component_id == 'Svgdiagram':
                 continue
 
             # Check that the component directory exists.
@@ -203,17 +203,17 @@ def test_require_file_contains_all_imports(self):
 
         rtc_ts_filenames = []
         for component_id in feconf.ALLOWED_RTE_EXTENSIONS:
-            # TODO(#9356): Remove this if condition once the Svgeditor
-            # directive is created in the second part of 1st milestone.
-            if component_id == 'Svgeditor':
-                continue
             component_dir = os.path.join(
                 feconf.RTE_EXTENSIONS_DIR, component_id)
             directives_dir = os.path.join(component_dir, 'directives')
             directive_filenames = os.listdir(directives_dir)
+            # When reading for all the .ts files in the directives directory,
+            # the .spec.ts files should not be included.
             rtc_ts_filenames.extend(
                 filename for filename
-                in directive_filenames if filename.endswith('.ts'))
+                in directive_filenames if (
+                    filename.endswith('.ts') and
+                    not filename.endswith('.spec.ts')))
 
         rtc_ts_file = os.path.join(
             feconf.RTE_EXTENSIONS_DIR, 'richTextComponentsRequires.ts')
diff --git a/core/tests/karma.conf.ts b/core/tests/karma.conf.ts
--- a/core/tests/karma.conf.ts
+++ b/core/tests/karma.conf.ts
@@ -38,6 +38,12 @@ module.exports = function(config) {
       // since Karma is unable to run tests on multiple files due to some
       // unknown reason.
       'core/templates/combined-tests.spec.ts',
+      {
+        pattern: 'third_party/static/literallycanvas-0.5.2/lib/img/*.png',
+        watched: false,
+        served: true,
+        included: false
+      },
       {
         pattern: 'extensions/**/*.png',
         watched: false,
@@ -65,6 +71,7 @@ module.exports = function(config) {
       // We access files directly in our code, for example /folder/,
       // so we need to proxy the requests from /folder/ to /base/folder/.
       '/assets/': '/base/assets/',
+      '/third_party/': '/base/third_party',
       '/extensions/': '/base/extensions/'
     },
     preprocessors: {
diff --git a/extensions/rich_text_components/components_test.py b/extensions/rich_text_components/components_test.py
--- a/extensions/rich_text_components/components_test.py
+++ b/extensions/rich_text_components/components_test.py
@@ -217,8 +217,8 @@ def test_video_validation(self):
         self.check_validation(
             components.Video, valid_items, invalid_items)
 
-    def test_svg_editor_validation(self):
-        """Tests svg editor component validation."""
+    def test_svg_diagram_validation(self):
+        """Tests svg diagram component validation."""
         valid_items = [{
             'svg_filename-with-value': 'random.svg',
             'alt-with-value': '1234'
@@ -238,7 +238,7 @@ def test_svg_editor_validation(self):
         }]
 
         self.check_validation(
-            components.Svgeditor, valid_items, invalid_items)
+            components.Svgdiagram, valid_items, invalid_items)
 
 
 class ComponentDefinitionTests(test_utils.GenericTestBase):
@@ -292,7 +292,7 @@ def test_component_e2e_tests(self):
                 text_inside_constant = text_inside_constant[
                     text_inside_constant.find(',') + 1:]
 
-        # TODO(#9356): Add svgeditor to validations once the e2e tests for it
+        # TODO(#9356): Add svgdiagram to validations once the e2e tests for it
         # are created in the 2nd milestone.
-        actual_components.remove('Svgeditor')
+        actual_components.remove('Svgdiagram')
         self.assertEqual(set(actual_components), set(rte_components_with_test))