This commit is contained in:
Bernhard Posselt 2016-10-04 20:06:27 +02:00
Родитель 243fdacca0
Коммит a3c3996b7e
14 изменённых файлов: 86 добавлений и 17 удалений

Просмотреть файл

@ -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 %}