зеркало из https://github.com/nextcloud/appstore.git
Add ocs ids
This commit is contained in:
Родитель
243fdacca0
Коммит
a3c3996b7e
|
@ -228,6 +228,7 @@ A full blown example would look like this (needs to be utf-8 encoded):
|
|||
<commands>
|
||||
<command>A\Php\Class</command>
|
||||
</commands>
|
||||
<ocsid>123</ocsid>
|
||||
</info>
|
||||
|
||||
The following tags are validated and used in the following way:
|
||||
|
@ -395,6 +396,13 @@ commands/command
|
|||
* optional
|
||||
* must contain a php class which is registered as occ command
|
||||
* will not be used, only validated
|
||||
ocsid
|
||||
* optional
|
||||
* used only to identify the app for Nextcloud versions 9 and 10
|
||||
* equal to the id on the old app store, e.g. **https://apps.owncloud.com/content/show.php/Spreed.ME?content=174436** would use **174436**
|
||||
* if not provided in your info.xml then the app will not be available for Nextcloud 9 and 10
|
||||
* if you do not have an id yet, create an app on the apps.owncloud.com app store and use that id. This ensure that duplicate ids are not used accidentally
|
||||
* deprecated; Support will be moved once 9 an 10 run out of support
|
||||
|
||||
The following character maximum lengths are enforced:
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ def categories(request):
|
|||
def in_category(app, category):
|
||||
categories = app.categories.all()
|
||||
for cat in categories:
|
||||
if cat.id == category:
|
||||
if cat.ocsid == category:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -30,7 +30,8 @@ def in_category(app, category):
|
|||
def apps(request):
|
||||
version = transform_version(request.GET.get('version'))
|
||||
category = request.GET.get('categories', None)
|
||||
apps = App.objects.get_compatible(version)
|
||||
compatible_apps = App.objects.get_compatible(version)
|
||||
apps = filter(lambda a: a.ocsid is not None, compatible_apps)
|
||||
if category is not None:
|
||||
apps = filter(lambda app: in_category(app, category), apps)
|
||||
return render_to_response('api/v0/apps.xml', {
|
||||
|
@ -42,7 +43,7 @@ def apps(request):
|
|||
|
||||
def app(request, id):
|
||||
version = transform_version(request.GET.get('version'))
|
||||
app = get_object_or_404(App, id=id)
|
||||
app = get_object_or_404(App, ocsid=id)
|
||||
return render_to_response('api/v0/app.xml', {
|
||||
'app': app,
|
||||
'request': request,
|
||||
|
@ -52,7 +53,7 @@ def app(request, id):
|
|||
|
||||
def download(request, id):
|
||||
version = transform_version(request.GET.get('version'))
|
||||
app = get_object_or_404(App, id=id)
|
||||
app = get_object_or_404(App, ocsid=id)
|
||||
releases = app.compatible_releases(version)
|
||||
if len(releases) == 0:
|
||||
raise Http404('No release downloads found')
|
||||
|
|
|
@ -221,7 +221,8 @@ class AppImporter(Importer):
|
|||
attribute_importer: StringAttributeImporter,
|
||||
l10n_importer: L10NImporter,
|
||||
category_importer: CategoryImporter,
|
||||
author_importer: AuthorImporter) -> None:
|
||||
author_importer: AuthorImporter,
|
||||
integer_attribute_importer: IntegerAttributeImporter) -> None:
|
||||
super().__init__({
|
||||
'release': release_importer,
|
||||
'screenshots': screenshots_importer,
|
||||
|
@ -236,7 +237,8 @@ class AppImporter(Importer):
|
|||
'summary': l10n_importer,
|
||||
'description': l10n_importer,
|
||||
'categories': category_importer,
|
||||
'authors': author_importer
|
||||
'authors': author_importer,
|
||||
'ocsid': integer_attribute_importer,
|
||||
}, {'id'})
|
||||
|
||||
def _get_object(self, key: str, value: Any, obj: Any) -> Any:
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
maxOccurs="1"/>
|
||||
<xs:element name="repository" type="repository" minOccurs="0"
|
||||
maxOccurs="1"/>
|
||||
<xs:element name="discussion" type="discussion-url" minOccurs="0"
|
||||
<xs:element name="discussion" type="discussion-url"
|
||||
minOccurs="0"
|
||||
maxOccurs="1"/>
|
||||
<xs:element name="screenshot" type="secure-url" minOccurs="0"
|
||||
maxOccurs="10"/>
|
||||
|
@ -42,10 +43,13 @@
|
|||
minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="repair-steps" type="repair-steps"
|
||||
minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="two-factor-providers" type="two-factor-providers"
|
||||
<xs:element name="two-factor-providers"
|
||||
type="two-factor-providers"
|
||||
minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="commands" type="commands"
|
||||
minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="ocsid" type="xs:int" minOccurs="0"
|
||||
maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:unique name="uniqueNameL10n">
|
||||
|
@ -441,7 +445,8 @@
|
|||
|
||||
<xs:simpleType name="php-class">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[a-zA-Z_][0-9a-zA-Z_]*(\\[a-zA-Z_][0-9a-zA-Z_]*)*"/>
|
||||
<xs:pattern
|
||||
value="[a-zA-Z_][0-9a-zA-Z_]*(\\[a-zA-Z_][0-9a-zA-Z_]*)*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
|
|
|
@ -116,6 +116,9 @@
|
|||
<discussion>
|
||||
<xsl:value-of select="discussion"/>
|
||||
</discussion>
|
||||
<ocsid type="int">
|
||||
<xsl:value-of select="ocsid"/>
|
||||
</ocsid>
|
||||
|
||||
<!-- release -->
|
||||
<release>
|
||||
|
|
|
@ -189,7 +189,7 @@ class GunZipAppMetadataExtractor:
|
|||
def element_to_dict(element: Any) -> Dict:
|
||||
type = element.get('type')
|
||||
key = element.tag.replace('-', '_')
|
||||
if type == 'int':
|
||||
if type == 'int' and element.text is not None:
|
||||
return {key: int(element.text)}
|
||||
elif type == 'list':
|
||||
return {key: list(map(element_to_dict, element.iterchildren()))}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
<xsl:apply-templates select="repair-steps"/>
|
||||
<xsl:copy-of select="two-factor-providers"/>
|
||||
<xsl:copy-of select="commands"/>
|
||||
<xsl:copy-of select="ocsid"/>
|
||||
|
||||
<!-- copy invalid elements to fail if they are present -->
|
||||
<xsl:copy-of select="standalone"/>
|
||||
|
|
|
@ -57,7 +57,8 @@ class ParserTest(TestCase):
|
|||
'shell_commands': [],
|
||||
'version': '8.8.2',
|
||||
'raw_version': '8.8.2',
|
||||
}
|
||||
},
|
||||
'ocsid': None,
|
||||
}}
|
||||
self.assertDictEqual(expected, result)
|
||||
|
||||
|
@ -453,6 +454,7 @@ class ParserTest(TestCase):
|
|||
{'screenshot': {'url': 'https://example.com/2.jpg',
|
||||
'ordering': 2}}
|
||||
],
|
||||
'ocsid': None,
|
||||
}}
|
||||
self.assertDictEqual(expected, result)
|
||||
|
||||
|
|
|
@ -155,6 +155,23 @@ class ImporterTest(TestCase):
|
|||
app = App.objects.get(pk='news')
|
||||
self.assertEqual('', app.website)
|
||||
|
||||
def test_release_import_ocsid_present(self):
|
||||
result = parse_app_metadata(self.min, self.config.info_schema,
|
||||
self.config.pre_info_xslt,
|
||||
self.config.info_xslt)
|
||||
result['app']['ocsid'] = 3
|
||||
self.importer.import_data('app', result['app'], None)
|
||||
app = App.objects.get(pk='news')
|
||||
self.assertEqual(3, app.ocsid)
|
||||
|
||||
def test_release_import_ocsid_absent(self):
|
||||
result = parse_app_metadata(self.min, self.config.info_schema,
|
||||
self.config.pre_info_xslt,
|
||||
self.config.info_xslt)
|
||||
self.importer.import_data('app', result['app'], None)
|
||||
app = App.objects.get(pk='news')
|
||||
self.assertEqual(None, app.ocsid)
|
||||
|
||||
def _assert_all_empty(self, obj, attribs):
|
||||
for attrib in attribs:
|
||||
self.assertEqual('', getattr(obj, attrib), attrib)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.2 on 2016-10-04 17:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_appownershiptransfer'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='app',
|
||||
name='ocsid',
|
||||
field=models.IntegerField(blank=True, help_text='Old store id. Deprecated', null=True, unique=True, verbose_name='OCS id'),
|
||||
),
|
||||
]
|
|
@ -5,7 +5,7 @@ from django.contrib.auth.models import User # type: ignore
|
|||
from django.db.models import ManyToManyField, ForeignKey, \
|
||||
URLField, IntegerField, CharField, CASCADE, TextField, \
|
||||
DateTimeField, Model, BooleanField, EmailField, Q, \
|
||||
FloatField, OneToOneField # type: ignore
|
||||
FloatField, OneToOneField, Max # type: ignore
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _ # type: ignore
|
||||
from parler.models import TranslatedFields, TranslatableModel, \
|
||||
|
@ -95,6 +95,8 @@ class App(TranslatableModel):
|
|||
verbose_name=_('Last release at'),
|
||||
default=timezone.now)
|
||||
certificate = TextField(verbose_name=_('Certificate'))
|
||||
ocsid = IntegerField(verbose_name=_('OCS id'), null=True, blank=True,
|
||||
help_text=_('Old store id. Deprecated'), unique=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('App')
|
||||
|
@ -431,6 +433,14 @@ class Category(TranslatableModel):
|
|||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def ocsid(self):
|
||||
"""Deprecated hack, assumes that the first two chars are unique"""
|
||||
initials = self.id[:2]
|
||||
ascii = map(ord, initials)
|
||||
chars = map(str, ascii)
|
||||
return ''.join(chars)
|
||||
|
||||
|
||||
class License(Model):
|
||||
id = CharField(max_length=256, unique=True, primary_key=True,
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
</meta>
|
||||
<data>
|
||||
<content details="full">
|
||||
<id>{{ app.id }}</id>
|
||||
<id>{{ app.ocsid }}</id>
|
||||
<name>{{ app.name }}</name>
|
||||
{% with releases=app|compatible_releases:version %}
|
||||
<version>{{ releases.0.version }}</version>
|
||||
{% endwith %}
|
||||
<changed>{{ app.last_release|date:'c' }}</changed>
|
||||
<typeid>{{ app.categories.all.0.id }}</typeid>
|
||||
<typeid>{{ app.categories.all.0.ocsid }}</typeid>
|
||||
<typename>{{ app.categories.all.0.name }}</typename>
|
||||
<personid>{{ app.owner.first_name }} {{ app.owner.last_name }}</personid>
|
||||
<profilepage>http://opendesktop.org/usermanager/search.php?username=anonymous</profilepage>
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
<data>
|
||||
{% for app in apps %}
|
||||
<content details="summary">
|
||||
<id>{{ app.id }}</id>
|
||||
<id>{{ app.ocsid }}</id>
|
||||
<name>{{ app.name }}</name>
|
||||
{% with releases=app|compatible_releases:version %}
|
||||
<version>{{ releases.0.version }}</version>
|
||||
{% endwith %}
|
||||
<changed>{{ app.last_release|date:'c' }}</changed>
|
||||
<typeid>{{ app.categories.all.0.id }}</typeid>
|
||||
<typeid>{{ app.categories.all.0.ocsid }}</typeid>
|
||||
<typename>{{ app.categories.all.0.name }}</typename>
|
||||
<personid>{{ app.owner.first_name }} {{ app.owner.last_name }}</personid>
|
||||
<profilepage>http://opendesktop.org/usermanager/search.php?username=anonymous</profilepage>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<data>
|
||||
{% for cat in categories %}
|
||||
<category>
|
||||
<id>{{ cat.id }}</id>
|
||||
<id>{{ cat.ocsid }}</id>
|
||||
<name>{{ cat.name }}</name>
|
||||
</category>
|
||||
{% endfor %}
|
||||
|
|
Загрузка…
Ссылка в новой задаче