Repository: nextcloud/appstore

Issue:
App title and description must be available in English
Both can be localized however we don't expect everything to be translated. Because we use English as fallback if a language is not present we should require the English contents in the info.xml



Discussion:

Resolving patch:
diff --git a/nextcloudappstore/core/api/v1/release/parser.py b/nextcloudappstore/core/api/v1/release/parser.py
--- a/nextcloudappstore/core/api/v1/release/parser.py
+++ b/nextcloudappstore/core/api/v1/release/parser.py
@@ -181,4 +181,20 @@ def parse_app_metadata(xml: str, schema: str, pre_xslt: str,
     transform = lxml.etree.XSLT(lxml.etree.XML(xslt))
     transformed_doc = transform(pre_transformed_doc)
     mapped = element_to_dict(transformed_doc.getroot())
+    validate_english_present(mapped)
     return mapped
+
+
+def validate_english_present(info: Dict) -> None:
+    """
+    Validates that name, summary and description are present in english
+    :param info: the parsed xml
+    :raises: InvalidAppMetadataXmlException if at least one of the required
+     fields is not present in english
+    """
+    app = info['app']
+    translated_fields = ['name', 'summary', 'description']
+    for field in translated_fields:
+        if 'en' not in app[field]:
+            msg = 'At least one element "%s" with lang "en" required' % field
+            raise InvalidAppMetadataXmlException(msg)


Test patch:
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml
new file mode 100644
--- /dev/null
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_description.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+    <id>news</id>
+    <name>News</name>
+    <summary>An RSS/Atom feed reader</summary>
+    <description lang="de">An RSS/Atom feed reader</description>
+    <version>8.8.2</version>
+    <licence>agpl</licence>
+    <author>Bernhard Posselt</author>
+    <category>multimedia</category>
+    <dependencies>
+        <owncloud min-version="9.0"/>
+    </dependencies>
+</info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml
new file mode 100644
--- /dev/null
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_name.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+    <id>news</id>
+    <name lang="de">News</name>
+    <summary>An RSS/Atom feed reader</summary>
+    <description>An RSS/Atom feed reader</description>
+    <version>8.8.2</version>
+    <licence>agpl</licence>
+    <author>Bernhard Posselt</author>
+    <category>multimedia</category>
+    <dependencies>
+        <owncloud min-version="9.0"/>
+    </dependencies>
+</info>
diff --git a/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml
new file mode 100644
--- /dev/null
+++ b/nextcloudappstore/core/api/v1/tests/data/infoxmls/no_en_summary.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../appmetadata/info.xsd">
+    <id>news</id>
+    <name>News</name>
+    <summary lang="de">An RSS/Atom feed reader</summary>
+    <description>An RSS/Atom feed reader</description>
+    <version>8.8.2</version>
+    <licence>agpl</licence>
+    <author>Bernhard Posselt</author>
+    <category>multimedia</category>
+    <dependencies>
+        <owncloud min-version="9.0"/>
+    </dependencies>
+</info>
diff --git a/nextcloudappstore/core/api/v1/tests/test_parser.py b/nextcloudappstore/core/api/v1/tests/test_parser.py
--- a/nextcloudappstore/core/api/v1/tests/test_parser.py
+++ b/nextcloudappstore/core/api/v1/tests/test_parser.py
@@ -128,6 +128,27 @@ def test_extract_zip(self):
         with (self.assertRaises(UnsupportedAppArchiveException)):
             extractor.extract_app_metadata(path)
 
+    def test_validate_english_name(self):
+        xml = self._get_test_xml('data/infoxmls/no_en_name.xml')
+        with (self.assertRaises(InvalidAppMetadataXmlException)):
+            parse_app_metadata(xml, self.config.info_schema,
+                               self.config.pre_info_xslt,
+                               self.config.info_xslt)
+
+    def test_validate_english_summary(self):
+        xml = self._get_test_xml('data/infoxmls/no_en_summary.xml')
+        with (self.assertRaises(InvalidAppMetadataXmlException)):
+            parse_app_metadata(xml, self.config.info_schema,
+                               self.config.pre_info_xslt,
+                               self.config.info_xslt)
+
+    def test_validate_english_description(self):
+        xml = self._get_test_xml('data/infoxmls/no_en_description.xml')
+        with (self.assertRaises(InvalidAppMetadataXmlException)):
+            parse_app_metadata(xml, self.config.info_schema,
+                               self.config.pre_info_xslt,
+                               self.config.info_xslt)
+
     def test_map_data(self):
         full = self._get_test_xml('data/infoxmls/full.xml')
         result = parse_app_metadata(full, self.config.info_schema,