зеркало из https://github.com/nextcloud/appstore.git
Make changelogs translatable (#333)
* merge migrations * revert ocs change * add migrations * initialize english changelogs
This commit is contained in:
Родитель
3bd46b131b
Коммит
b5e81ae899
|
@ -481,6 +481,8 @@ The version has to be equal to the version in your info.xml. If the parser can't
|
|||
|
||||
The changelog for nightlies will be taken from the **## [Unreleased]** block
|
||||
|
||||
Changelogs can be translated as well. To add a changelog for a specific translation, use **CHANGELOG.code.md**, e.g.: **CHANGELOG.fr.md**
|
||||
|
||||
.. _info-schema:
|
||||
|
||||
Schema Integration
|
||||
|
|
|
@ -301,7 +301,11 @@ This route will return all releases to display inside Nextcloud's apps admin are
|
|||
],
|
||||
"lastModified": "2016-06-25T16:49:25.319425Z",
|
||||
"signature": "909377e1a695bbaa415c10ae087ae1cc48e88066d20a5a7a8beed149e9fad3d5",
|
||||
"changelog": "* **Bugfix**: Pad API last modified timestamp to milliseconds in updated items API to return only new items. API users however need to re-sync their complete contents, #24\n* **Bugfix**: Do not pad milliseconds for non millisecond timestamps in API"
|
||||
"translations": {
|
||||
"en": {
|
||||
"changelog": "* **Bugfix**: Pad API last modified timestamp to milliseconds in updated items API to return only new items. API users however need to re-sync their complete contents, #24\n* **Bugfix**: Do not pad milliseconds for non millisecond timestamps in API"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"screenshots": [
|
||||
|
|
|
@ -13,7 +13,7 @@ class PhpExtensionDependencyInline(admin.TabularInline):
|
|||
extra = 1
|
||||
|
||||
|
||||
class AppReleaseAdmin(admin.ModelAdmin):
|
||||
class AppReleaseAdmin(TranslatableAdmin):
|
||||
inlines = (DatabaseDependencyInline, PhpExtensionDependencyInline)
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ def apps(request):
|
|||
if category is not None:
|
||||
apps = filter(lambda app: in_category(app, category), apps)
|
||||
return render_to_response('api/v0/apps.xml', {
|
||||
'apps': apps,
|
||||
'apps': list(apps),
|
||||
'request': request,
|
||||
'version': version
|
||||
}, content_type='application/xml')
|
||||
|
|
|
@ -12,3 +12,4 @@ class ReleaseConfig:
|
|||
self.info_schema = read_relative_file(__file__, 'info.xsd')
|
||||
self.info_xslt = read_relative_file(__file__, 'info.xslt')
|
||||
self.pre_info_xslt = read_relative_file(__file__, 'pre-info.xslt')
|
||||
self.languages = settings.LANGUAGES
|
||||
|
|
|
@ -161,7 +161,8 @@ class AppReleaseImporter(Importer):
|
|||
license_importer: LicenseImporter,
|
||||
shell_command_importer: ShellCommandImporter,
|
||||
string_attribute_importer: StringAttributeImporter,
|
||||
integer_attribute_importer: IntegerAttributeImporter) -> None:
|
||||
integer_attribute_importer: IntegerAttributeImporter,
|
||||
l10n_importer: L10NImporter) -> None:
|
||||
super().__init__({
|
||||
'php_extensions': php_extension_importer,
|
||||
'databases': database_importer,
|
||||
|
@ -174,7 +175,7 @@ class AppReleaseImporter(Importer):
|
|||
'shell_commands': shell_command_importer,
|
||||
'signature': string_attribute_importer,
|
||||
'download': string_attribute_importer,
|
||||
'changelog': string_attribute_importer,
|
||||
'changelog': l10n_importer,
|
||||
}, {
|
||||
'version',
|
||||
'raw_version',
|
||||
|
|
|
@ -35,6 +35,9 @@ class XMLSyntaxError(APIException):
|
|||
pass
|
||||
|
||||
|
||||
Metadata = Tuple[str, str, Dict[str, str]]
|
||||
|
||||
|
||||
class GunZipAppMetadataExtractor:
|
||||
def __init__(self, config: ReleaseConfig) -> None:
|
||||
"""
|
||||
|
@ -43,7 +46,7 @@ class GunZipAppMetadataExtractor:
|
|||
self.config = config
|
||||
self.app_folder_regex = re.compile(r'^[a-z]+[a-z_]*(?:/.*)*$')
|
||||
|
||||
def extract_app_metadata(self, archive_path: str) -> Tuple[str, str, str]:
|
||||
def extract_app_metadata(self, archive_path: str) -> Metadata:
|
||||
"""
|
||||
Extracts the info.xml from an tar.gz archive
|
||||
:argument archive_path: the path to the tar.gz archive
|
||||
|
@ -60,10 +63,19 @@ class GunZipAppMetadataExtractor:
|
|||
result = self._parse_archive(tar)
|
||||
return result
|
||||
|
||||
def _parse_archive(self, tar: Any) -> Tuple[str, str, str]:
|
||||
def _parse_archive(self, tar: Any) -> Metadata:
|
||||
app_id = self._find_app_id(tar)
|
||||
info = self._get_contents('%s/appinfo/info.xml' % app_id, tar)
|
||||
changelog = self._get_contents('%s/CHANGELOG.md' % app_id, tar, '')
|
||||
changelog = {} # type: Dict[str, str]
|
||||
changelog['en'] = self._get_contents('%s/CHANGELOG.md' % app_id, tar,
|
||||
'')
|
||||
for code, _ in self.config.languages:
|
||||
trans_changelog = self._get_contents(
|
||||
'%s/CHANGELOG.%s.md' % (app_id, code), tar, ''
|
||||
)
|
||||
if trans_changelog:
|
||||
changelog[code] = trans_changelog
|
||||
|
||||
return info, app_id, changelog
|
||||
|
||||
def _get_contents(self, path: str, tar: Any, default: Any = None) -> str:
|
||||
|
|
|
@ -38,11 +38,13 @@ class AppReleaseProvider:
|
|||
% (app_id, info_app_id)
|
||||
raise InvalidAppDirectoryException(msg)
|
||||
|
||||
version = info['app']['release']['version']
|
||||
release = info['app']['release']
|
||||
version = release['version']
|
||||
if is_nightly:
|
||||
version += '-nightly'
|
||||
info['app']['release']['changelog'] = parse_changelog(changelog,
|
||||
version)
|
||||
release['changelog'] = changelog
|
||||
for code, value in changelog.items():
|
||||
release['changelog'][code] = parse_changelog(value, version)
|
||||
|
||||
with open(download.filename, 'rb') as f:
|
||||
data = f.read()
|
||||
|
|
|
@ -67,6 +67,7 @@ class AppReleaseSerializer(serializers.ModelSerializer):
|
|||
raw_platform_version_spec = SerializerMethodField()
|
||||
version = SerializerMethodField()
|
||||
nightly = SerializerMethodField()
|
||||
translations = TranslatedFieldsField(shared_model=AppRelease)
|
||||
|
||||
class Meta:
|
||||
model = AppRelease
|
||||
|
@ -75,7 +76,7 @@ class AppReleaseSerializer(serializers.ModelSerializer):
|
|||
'php_version_spec', 'platform_version_spec', 'min_int_size',
|
||||
'download', 'created', 'licenses', 'last_modified', 'nightly',
|
||||
'raw_php_version_spec', 'raw_platform_version_spec', 'signature',
|
||||
'changelog',
|
||||
'translations',
|
||||
)
|
||||
|
||||
def get_platform_version_spec(self, obj):
|
||||
|
|
|
@ -168,7 +168,7 @@ class ParserTest(TestCase):
|
|||
extractor = GunZipAppMetadataExtractor(self.config)
|
||||
full_extracted, app_id, changes = extractor.extract_app_metadata(path)
|
||||
self.assertEqual('contacts', app_id)
|
||||
self.assertEqual('', changes)
|
||||
self.assertEqual('', changes['en'])
|
||||
|
||||
def test_extract_gunzip_info(self):
|
||||
path = self.get_path('data/archives/full.tar.gz')
|
||||
|
@ -176,7 +176,7 @@ class ParserTest(TestCase):
|
|||
full_extracted, app_id, changes = extractor.extract_app_metadata(path)
|
||||
full = self._get_contents('data/infoxmls/full.xml')
|
||||
self.assertEqual(full, full_extracted)
|
||||
self.assertEqual('', changes)
|
||||
self.assertEqual('', changes['en'])
|
||||
|
||||
def test_extract_changelog(self):
|
||||
path = self.get_path('data/archives/changelog.tar.gz')
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.2 on 2016-10-05 14:24
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def create_default_changelogs(apps, schema_editor):
|
||||
model = apps.get_model('core', 'AppRelease')
|
||||
for release in model.objects.all():
|
||||
release.set_current_language('en')
|
||||
release.changelog = ''
|
||||
release.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0006_apprelease_changelog'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AppReleaseTranslation',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')),
|
||||
('changelog', models.TextField(default='', help_text='The release changelog. Can contain Markdown', verbose_name='Changelog')),
|
||||
],
|
||||
options={
|
||||
'default_permissions': (),
|
||||
'verbose_name': 'App release Translation',
|
||||
'db_table': 'core_apprelease_translation',
|
||||
'db_tablespace': '',
|
||||
'managed': True,
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='apprelease',
|
||||
name='changelog',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='appreleasetranslation',
|
||||
name='master',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='core.AppRelease'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='appreleasetranslation',
|
||||
unique_together=set([('language_code', 'master')]),
|
||||
),
|
||||
migrations.RunPython(create_default_changelogs, migrations.RunPython.noop)
|
||||
]
|
|
@ -32,6 +32,7 @@ class AppManager(TranslatableManager):
|
|||
def get_compatible(self, platform_version, inclusive=False):
|
||||
apps = App.objects.prefetch_related(
|
||||
'releases',
|
||||
'releases__translations',
|
||||
'releases__databases',
|
||||
'releases__licenses',
|
||||
'releases__phpextensiondependencies__php_extension',
|
||||
|
@ -298,7 +299,7 @@ class AppAuthor(Model):
|
|||
verbose_name_plural = _('App authors')
|
||||
|
||||
|
||||
class AppRelease(Model):
|
||||
class AppRelease(TranslatableModel):
|
||||
version = CharField(max_length=256, verbose_name=_('Version'),
|
||||
help_text=_('Version follows Semantic Versioning'))
|
||||
app = ForeignKey('App', on_delete=CASCADE, verbose_name=_('App'),
|
||||
|
@ -335,8 +336,10 @@ class AppRelease(Model):
|
|||
verbose_name=_('Updated at'))
|
||||
signature = TextField(verbose_name=_('Signature'), help_text=_(
|
||||
'A signature using SHA512 and the app\'s certificate'))
|
||||
changelog = TextField(verbose_name=_('Changelog'), help_text=_(
|
||||
'The release changelog. Can contain Markdown'), default='')
|
||||
translations = TranslatedFields(
|
||||
changelog=TextField(verbose_name=_('Changelog'), help_text=_(
|
||||
'The release changelog. Can contain Markdown'), default='')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('App release')
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<statuscode>100</statuscode>
|
||||
<message></message>
|
||||
<totalitems>{{ apps|length }}</totalitems>
|
||||
<itemsperpage>1000000</itemsperpage>
|
||||
<itemsperpage>{{ apps|length }}</itemsperpage>
|
||||
</meta>
|
||||
<data>
|
||||
{% for app in apps %}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<statuscode>100</statuscode>
|
||||
<message></message>
|
||||
<totalitems>{{ categories|length }}</totalitems>
|
||||
<itemsperpage>{{ categories|length }}</itemsperpage>
|
||||
</meta>
|
||||
<data>
|
||||
{% for cat in categories %}
|
||||
|
|
Загрузка…
Ссылка в новой задаче