Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uploading & downloading of the AppAPI Apps #1145

Merged
merged 10 commits into from
Sep 28, 2023
24 changes: 24 additions & 0 deletions nextcloudappstore/api/v1/release/importer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from typing import Any, Dict, Set, Tuple # type: ignore

from django.conf import settings # type: ignore
Expand All @@ -7,6 +8,8 @@
from nextcloudappstore.core.facades import any_match
from nextcloudappstore.core.models import (
App,
AppApiReleaseApiScope,
AppApiReleaseDeployMethod,
AppAuthor,
AppRelease,
Category,
Expand Down Expand Up @@ -159,6 +162,25 @@ def import_data(self, key: str, value: Any, obj: Any) -> None:
obj.save()


class AppApiImporter(ScalarImporter):
def import_data(self, key: str, value: Any, obj: Any) -> None:
obj.aa_proto = value["protocol"]
obj.aa_is_system = value.get("aa_is_system", False)
for supported_deploy_types in ("docker_install",):
if supported_deploy_types in value:
install_data = json.dumps(value[supported_deploy_types])
AppApiReleaseDeployMethod.objects.get_or_create(
app_release=obj,
install_type=supported_deploy_types,
install_data=install_data,
)
for scope in value.get("scopes", []):
scope_type = list(scope)[0]
AppApiReleaseApiScope.objects.get_or_create(
app_release=obj, optional=bool(scope_type != "required"), scope_name=scope[scope_type]
)


class AppReleaseImporter(Importer):
def __init__(
self,
Expand All @@ -169,6 +191,7 @@ def __init__(
string_attribute_importer: StringAttributeImporter,
default_attribute_importer: DefaultAttributeImporter,
l10n_importer: L10NImporter,
app_api_importer: AppApiImporter,
) -> None:
super().__init__(
{
Expand All @@ -185,6 +208,7 @@ def __init__(
"download": string_attribute_importer,
"changelog": l10n_importer,
"is_nightly": default_attribute_importer,
"external_app": app_api_importer,
},
{
"version",
Expand Down
37 changes: 37 additions & 0 deletions nextcloudappstore/api/v1/release/info.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
maxOccurs="1" />
<xs:element name="versions" type="versions" minOccurs="0"
maxOccurs="1" />
<xs:element name="external-app" type="external-app" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:unique name="uniqueNameL10n">
Expand Down Expand Up @@ -644,6 +645,42 @@
</xs:sequence>
</xs:complexType>

<xs:complexType name="docker-install">
<xs:sequence>
<xs:element name="registry" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="image" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="image-tag" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="scopes_required">
<xs:sequence>
<xs:element name="value" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="scopes_optional">
<xs:sequence>
<xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="scopes">
<xs:sequence>
<xs:element name="required" type="scopes_required" minOccurs="1" maxOccurs="1"/>
<xs:element name="optional" type="scopes_optional" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="external-app">
<xs:sequence>
<xs:element name="docker-install" type="docker-install" minOccurs="0" maxOccurs="1"/>
<xs:element name="scopes" type="scopes" minOccurs="1" maxOccurs="1"/>
<xs:element name="protocol" type="non-empty-string" minOccurs="0" maxOccurs="1"/>
<xs:element name="system" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="jobs">
<xs:sequence>
<xs:element name="job" type="php-class" minOccurs="1"
Expand Down
35 changes: 35 additions & 0 deletions nextcloudappstore/api/v1/release/info.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,45 @@
</licenses>

<xsl:apply-templates select="dependencies"/>
<xsl:apply-templates select="external-app"/>
</release>
</app>
</xsl:template>

<xsl:template match="external-app">
<external-app>
<docker-install>
<registry type="string">
<xsl:value-of select="docker-install/registry"/>
</registry>
<image type="string">
<xsl:value-of select="docker-install/image"/>
</image>
<image-tag type="string">
<xsl:value-of select="docker-install/image-tag"/>
</image-tag>
</docker-install>
<scopes type="list">
<xsl:for-each select="scopes/required/value">
<required>
<xsl:value-of select="."/>
</required>
</xsl:for-each>
<xsl:for-each select="scopes/optional/value">
<optional>
<xsl:value-of select="."/>
</optional>
</xsl:for-each>
</scopes>
<protocol type="string">
<xsl:value-of select="protocol"/>
</protocol>
<system type="boolean">
<xsl:value-of select="system"/>
</system>
</external-app>
</xsl:template>

<xsl:template match="dependencies">
<php-min-version type="min-version">
<xsl:value-of select="php/@min-version"/>
Expand Down
26 changes: 26 additions & 0 deletions nextcloudappstore/api/v1/release/pre-info.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
<xsl:copy-of select="remote"/>
<xsl:copy-of select="requiremin"/>
<xsl:copy-of select="requiremax"/>

<xsl:apply-templates select="external-app"/>
</info>
</xsl:template>

Expand Down Expand Up @@ -147,4 +149,28 @@
</repair-steps>
</xsl:template>

<xsl:template match="external-app">
<external-app>
<xsl:apply-templates select="docker-install"/>
<xsl:apply-templates select="scopes"/>
<xsl:copy-of select="protocol"/>
<xsl:copy-of select="system"/>
</external-app>
</xsl:template>

<xsl:template match="docker-install">
<docker-install>
<xsl:copy-of select="registry"/>
<xsl:copy-of select="image"/>
<xsl:copy-of select="image-tag"/>
</docker-install>
</xsl:template>

<xsl:template match="scopes">
<scopes>
<xsl:copy-of select="required"/>
<xsl:copy-of select="optional"/>
</scopes>
</xsl:template>

</xsl:stylesheet>
49 changes: 49 additions & 0 deletions nextcloudappstore/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from nextcloudappstore.core.models import (
App,
AppApiReleaseApiScope,
AppApiReleaseDeployMethod,
AppAuthor,
AppRating,
AppRelease,
Expand Down Expand Up @@ -114,6 +116,49 @@ def get_raw_php_version_spec(self, obj):
return obj.raw_php_version_spec.replace(",", " ")


class DeployMethodSerializer(serializers.ModelSerializer):
class Meta:
model = AppApiReleaseDeployMethod
fields = ("install_type", "install_data")


class ApiScopeSerializer(serializers.ModelSerializer):
class Meta:
model = AppApiReleaseApiScope
fields = ("optional", "scope_name")


class AppApiAppReleaseSerializer(AppReleaseSerializer):
deploy_methods = DeployMethodSerializer(many=True, read_only=True)
api_scopes = ApiScopeSerializer(many=True, read_only=True)

class Meta:
model = AppRelease
fields = (
"version",
"php_extensions",
"databases",
"shell_commands",
"php_version_spec",
"platform_version_spec",
"min_int_size",
"download",
"created",
"licenses",
"last_modified",
"is_nightly",
"raw_php_version_spec",
"raw_platform_version_spec",
"signature",
"translations",
"signature_digest",
"aa_proto",
"aa_is_system",
"deploy_methods",
"api_scopes",
)


class ScreenshotSerializer(serializers.ModelSerializer):
class Meta:
model = Screenshot
Expand Down Expand Up @@ -157,6 +202,10 @@ def get_discussion(self, obj):
return obj.discussion_url


class AppApiAppSerializer(AppSerializer):
releases = AppApiAppReleaseSerializer(many=True, read_only=True)


class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
Expand Down
37 changes: 37 additions & 0 deletions nextcloudappstore/api/v1/tests/data/infoxmls/app_api.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0"?>
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
<id>aa_skeleton</id>
<name>AppAPI Skeleton2</name>
<description>Testing info.xml</description>
<version>2.0.0</version>
<licence>agpl</licence>
<author>Andrey Borysenko</author>
<category>tools</category>
<bugs>https://github.com/cloud-py-api/nc_py_api/issues</bugs>
<dependencies>
<nextcloud min-version="28" max-version="28"/>
</dependencies>
<documentation>
<developer>https://cloud-py-api.github.io/nc_py_api/</developer>
</documentation>
<website>https://github.com/cloud-py-api/nc_py_api</website>
<discussion>https://github.com/cloud-py-api/nc_py_api/discussions</discussion>
<external-app>
<docker-install>
<registry>ghcr.io</registry>
<image>cloud-py-api/skeleton</image>
<image-tag>1.0.0</image-tag>
</docker-install>
<scopes>
<required>
<value>FILES</value>
<value>NOTIFICATIONS</value>
</required>
<optional>
<value>TALK</value>
</optional>
</scopes>
<protocol>https</protocol>
<system>true</system>
</external-app>
</info>
27 changes: 27 additions & 0 deletions nextcloudappstore/api/v1/tests/data/infoxmls/app_api_minimal.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../release/info.xsd">
<id>aa_skeleton</id>
<name>AppAPI Skeleton</name>
<description>Almost minimal info.xml</description>
<version>1.0.0</version>
<licence>agpl</licence>
<author>Alexander Piskun</author>
<category>tools</category>
<bugs>https://github.com/cloud-py-api/nc_py_api/issues</bugs>
<dependencies>
<nextcloud min-version="27" max-version="28"/>
</dependencies>
<external-app>
<docker-install>
<registry>ghcr.io</registry>
<image>cloud-py-api/skeleton</image>
<image-tag>latest</image-tag>
</docker-install>
<scopes>
<required>
<value>FILES</value>
</required>
</scopes>
<protocol>http</protocol>
</external-app>
</info>
27 changes: 27 additions & 0 deletions nextcloudappstore/api/v1/tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,33 @@ def test_parse_changelog_brackets_prefix_v(self):
expected = self._get_contents("data/changelogs/0.6.0.md").strip()
self.assertEqual(expected, changelog)

def test_appapi(self):
xml = self._get_contents("data/infoxmls/app_api.xml")
result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
assert result["app"]["release"]["version"] == "2.0.0"
r_ex_app = result["app"]["release"]["external_app"]
assert r_ex_app["docker_install"] == {
"image": "cloud-py-api/skeleton",
"image_tag": "1.0.0",
"registry": "ghcr.io",
}
assert r_ex_app["scopes"] == [{"required": "FILES"}, {"required": "NOTIFICATIONS"}, {"optional": "TALK"}]
assert r_ex_app["protocol"] == "https"
assert r_ex_app["system"] == "true"

def test_appapi_minimal(self):
xml = self._get_contents("data/infoxmls/app_api_minimal.xml")
result = parse_app_metadata(xml, self.config.info_schema, self.config.pre_info_xslt, self.config.info_xslt)
assert result["app"]["release"]["version"] == "1.0.0"
r_ex_app = result["app"]["release"]["external_app"]
assert r_ex_app["docker_install"] == {
"image": "cloud-py-api/skeleton",
"image_tag": "latest",
"registry": "ghcr.io",
}
assert r_ex_app["scopes"] == [{"required": "FILES"}]
assert r_ex_app["protocol"] == "http"

def _get_contents(self, target):
path = self.get_path(target)
return read_file_contents(path)
Expand Down
Loading
Loading