Commit 2af3e0e8 authored by Claude Paroz's avatar Claude Paroz

Added a separate api module

parent 241d5206
Pipeline #50736 passed with stage
in 5 minutes and 51 seconds
from django.test import TestCase
from django.urls import reverse
class APITests(TestCase):
fixtures = ['sample_data.json']
def test_home(self):
response = self.client.get(reverse('api-home'))
self.assertEqual(response.json(), {
'languages': '/api/v1/languages/',
'modules': '/api/v1/modules/',
'releases': '/api/v1/releases/',
'teams': '/api/v1/teams/',
})
def test_modules(self):
response = self.client.get(reverse('api-modules'))
result = response.json()
self.assertEqual(result[0], {'name': 'gnome-hello', 'href': '/api/v1/modules/gnome-hello'})
def test_module(self):
response = self.client.get(reverse('api-module', args=['gnome-hello']))
result = response.json()
self.assertEqual(result['vcs_web'], 'https://gitlab.gnome.org/GNOME/gnome-hello/')
self.assertEqual(result['branches'], [{'name': 'master'}])
self.assertEqual(
result['domains'][1],
{'description': 'UI Translations', 'name': 'po', 'dtype': 'ui', 'layout': 'po/{lang}.po'}
)
def test_teams(self):
response = self.client.get(reverse('api-teams'))
result = response.json()
self.assertEqual(result[0], {'name': 'fr', 'href': '/api/v1/teams/fr', 'description': 'French'})
def test_team(self):
response = self.client.get(reverse('api-team', args=['fr']))
result = response.json()
self.assertEqual(result['coordinators'], [{'name': 'John Coordinator'}])
def test_languages(self):
response = self.client.get(reverse('api-languages'))
result = response.json()
self.assertEqual(result[0], {
'href': '/api/v1/teams/bem',
'locale': 'bem',
'name': 'Bemba',
'plurals': '',
'team__description': None
})
def test_releases(self):
response = self.client.get(reverse('api-releases'))
result = response.json()
self.assertEqual(result[0], {
'description': 'freedesktop.org (non-GNOME)',
'href': '/api/v1/releases/freedesktop-org',
'name': 'freedesktop-org'
})
def test_release(self):
response = self.client.get(reverse('api-release', args=['gnome-3-8']))
result = response.json()
self.assertEqual(result['description'], 'GNOME 3.8 (stable)')
self.assertEqual(
result['languages'][0],
{'href': '/api/v1/releases/gnome-3-8/languages/bem', 'locale': 'bem'}
)
self.assertEqual(result['branches'][0], 'gnome-3-8 (zenity)')
self.assertEqual(result['statistics'], '/api/v1/releases/gnome-3-8/stats')
def test_release_stats(self):
response = self.client.get(reverse('api-release-stats', args=['gnome-3-8']))
result = response.json()
self.assertEqual(result['statistics'][0]['lang_name'], 'French')
self.assertEqual(
result['statistics'][0]['ui'],
{'translated_perc': 100, 'untranslated_perc': 0, 'translated': 183,
'fuzzy_perc': 0, 'untranslated': 0, 'fuzzy': 0}
)
def test_release_language(self):
response = self.client.get(reverse('api-release-language', args=['gnome-3-8', 'fr']))
result = response.json()
self.assertEqual(len(result['modules']), 4)
def test_module_lang_stats(self):
response = self.client.get(
reverse('api-module-lang-stats', args=['gnome-hello', 'master', 'po', 'fr'])
)
result = response.json()
self.assertEqual(result['statistics'], {'untrans': 0, 'fuzzy': 0, 'trans': 47})
self.assertEqual(result['pot_file'], '/POT/gnome-hello.master/gnome-hello.master.pot')
self.assertEqual(result['po_file'], '/POT/gnome-hello.master/gnome-hello.master.fr.po')
from django.urls import path
from . import views
urlpatterns = [
path('', views.APIHomeView.as_view(), name='api-home'),
path('modules/', views.ModulesView.as_view(), name='api-modules'),
path('modules/<name:module_name>', views.ModuleView.as_view(), name='api-module'),
path('teams/', views.TeamsView.as_view(), name='api-teams'),
path('teams/<locale:team_name>', views.TeamView.as_view(), name='api-team'),
path('languages/', views.LanguagesView.as_view(), name='api-languages'),
path('releases/', views.ReleasesView.as_view(), name='api-releases'),
path('releases/<name:release>', views.ReleaseView.as_view(), name='api-release'),
path('releases/<name:release>/stats', views.ReleaseStatsView.as_view(), name='api-release-stats'),
path('releases/<name:release>/languages/<locale:lang>', views.ReleaseLanguageView.as_view(),
name='api-release-language'),
path(
'modules/<name:module_name>/branches/<name:branch_name>/domains/<name:domain_name>'
'/languages/<locale:lang>',
views.ModuleLangStatsView.as_view(),
name='api-module-lang-stats'
),
]
from django.http import Http404, JsonResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.views.generic import View
from languages.models import Language
from stats.models import Module, Release
from teams.models import Team
from vertimus.models import State
from vertimus.views import get_vertimus_state
class SerializeListView(View):
def get(self, request, *args, **kwargs):
return JsonResponse(
self.serialize_qs(self.get_queryset().values(*['pk'] + self.fields)), safe=False
)
def serialize_obj(self, obj, fields=None):
data = {field: obj[field] for field in fields}
data['href'] = self.get_href(obj)
return data
def serialize_qs(self, qs):
return [self.serialize_obj(obj, self.fields) for obj in qs]
class SerializeObjectView(SerializeListView):
def get(self, *args, **kwargs):
return JsonResponse(self.serialize_obj(self.get_object()))
def serialize_obj(self, obj, fields=None):
return serialize_instance(obj, fields or self.fields)
class APIHomeView(View):
def get(self, *args, **kwargs):
return JsonResponse({
'modules': reverse('api-modules'),
'teams': reverse('api-teams'),
'languages': reverse('api-languages'),
'releases': reverse('api-releases'),
})
class ModulesView(SerializeListView):
fields = ['name']
def get_queryset(self):
return Module.objects.filter(archived=False)
def get_href(self, obj):
return reverse('api-module', args=[obj['name']])
class ModuleView(SerializeObjectView):
@property
def fields(self):
return [
f.name for f in Module._meta.get_fields()
if not f.one_to_many and f.name not in ['id', 'archived']
]
def get_object(self):
return get_object_or_404(Module, name=self.kwargs['module_name'])
def serialize_obj(self, obj, **kwargs):
data = serialize_instance(obj, self.fields)
data['branches'] = [
serialize_instance(branch, ['name'])
for branch in obj.get_branches()
]
data['domains'] = [
serialize_instance(domain, ['name', 'description', 'dtype', 'layout'])
for domain in obj.domain_set.all().order_by('name')
]
return data
class TeamsView(SerializeListView):
fields = ['name', 'description']
def get_queryset(self):
return Team.objects.all().order_by('name')
def get_href(self, obj):
return reverse('api-team', args=[obj['name']])
class TeamView(SerializeObjectView):
@property
def fields(self):
return [
f.name for f in Team._meta.get_fields()
if not f.one_to_many and f.name not in ['id', 'members']
]
def get_object(self):
return get_object_or_404(Team, name=self.kwargs['team_name'])
def serialize_obj(self, obj, **kwargs):
data = serialize_instance(obj, self.fields)
data['coordinators'] = [
serialize_instance(coord, ['name'])
for coord in obj.get_coordinators()
]
return data
class LanguagesView(SerializeListView):
fields = ['name', 'locale', 'team__description', 'plurals']
def get_queryset(self):
return Language.objects.all().order_by('name')
def get_href(self, obj):
return reverse('api-team', args=[obj['locale']])
class ReleasesView(SerializeListView):
fields = ['name', 'description']
def get_queryset(self):
return Release.objects.all().order_by('name')
def get_href(self, obj):
return reverse('api-release', args=[obj['name']])
class ReleaseView(SerializeObjectView):
fields = ['name', 'description', 'string_frozen', 'status', 'branches']
def get_object(self):
return get_object_or_404(Release, name=self.kwargs['release'])
def serialize_obj(self, obj, **kwargs):
data = serialize_instance(obj, self.fields)
data['languages'] = [{
'locale': lang.locale,
'href': reverse('api-release-language', args=[obj.name, lang.locale])
} for lang in Language.objects.all()]
data['statistics'] = reverse('api-release-stats', args=[self.kwargs['release']])
return data
class ReleaseStatsView(View):
def get(self, *args, **kwargs):
release = get_object_or_404(Release, name=self.kwargs['release'])
lang_stats = release.get_global_stats()
return JsonResponse({
'release': serialize_instance(release, ['name', 'description', 'status']),
'statistics': lang_stats,
})
class ReleaseLanguageView(View):
def get(self, *args, **kwargs):
release = get_object_or_404(Release, name=self.kwargs['release'])
language = get_object_or_404(Language, locale=self.kwargs['lang'])
item_list = []
for branch in release.branches.all().select_related('module'):
for domain in branch.get_domains():
item_list.append({
'module': branch.module.name,
'branch': branch.name,
'stats': reverse('api-module-lang-stats', kwargs={
'module_name': branch.module.name,
'branch_name': branch.name,
'domain_name': domain,
'lang': language.locale,
}),
})
return JsonResponse({
'release': release.name,
'language': language.locale,
'modules': item_list,
})
class ModuleLangStatsView(View):
def get(self, *args, **kwargs):
module = get_object_or_404(Module, name=self.kwargs['module_name'])
branch = get_object_or_404(module.branch_set, name=self.kwargs['branch_name'])
domain = branch.get_domains().get(self.kwargs['domain_name'])
if not domain:
raise Http404
language = get_object_or_404(Language, locale=self.kwargs['lang'])
pot_stats, stats, state = get_vertimus_state(branch, domain, language)
return JsonResponse({
'module': module.name,
'branch': branch.name,
'domain': domain.name,
'language': language.locale,
'state': state.name,
'statistics': {
'trans': stats.translated(), 'fuzzy': stats.fuzzy(), 'untrans': stats.untranslated()
},
'pot_file': stats.pot_url(),
'po_file': stats.po_url(),
})
def serialize_instance(instance, field_names):
data = {}
for field in field_names:
value = getattr(instance, field)
if hasattr(value, 'all'):
value = [str(o) for o in value.all()]
data[field] = value
return data
......@@ -146,6 +146,7 @@ INSTALLED_APPS = [
'teams',
'vertimus',
'feeds',
'api',
]
AUTHENTICATION_BACKENDS = [
......
......@@ -18,6 +18,7 @@ class LocaleConverter(StringConverter):
class NameConverter(StringConverter):
"""Converter for module, branch, or domain names."""
regex = '[-~\w\+\.]+'
......@@ -75,6 +76,7 @@ urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
path('admin/', admin.site.urls),
path('rss/', include('feeds.urls')),
path('api/v1/', include('api.urls')),
path('', include('social_django.urls', namespace='social')),
]
......
......@@ -108,7 +108,7 @@ class Person(User):
@property
def name(self):
if self.first_name or self.last_name:
return self.first_name + " " + self.last_name
return " ".join([name for name in [self.first_name, self.last_name] if name])
else:
return self.username
......
......@@ -61,19 +61,7 @@ def vertimus(request, branch, domain, language, stats=None, level="0"):
grandparent, second (2) is the parent of the grandparent, etc."""
level = int(level)
pot_stats = get_object_or_404(Statistics, branch=branch, domain=domain, language=None)
if not stats:
try:
stats = Statistics.objects.get(branch=branch, domain=domain, language=language)
except Statistics.DoesNotExist:
stats = FakeLangStatistics(pot_stats, language)
# Get the state of the translation
try:
state = State.objects.get(branch=branch, domain=domain, language=language)
except State.DoesNotExist:
# No need to save the state at this stage
state = State(branch=branch, domain=domain, language=language)
pot_stats, stats, state = get_vertimus_state(branch, domain, language, stats=stats)
# Filtering on domain.name instead of domain because we can have several domains
# working on the same set of strings (e.g. when an extraction method changed,
# each extraction is mapped to a different domain with branch_from/branch_to delimitations)
......@@ -155,6 +143,23 @@ def vertimus(request, branch, domain, language, stats=None, level="0"):
return render(request, 'vertimus/vertimus_detail.html', context)
def get_vertimus_state(branch, domain, language, stats=None):
pot_stats = get_object_or_404(Statistics, branch=branch, domain=domain, language=None)
if not stats:
try:
stats = Statistics.objects.get(branch=branch, domain=domain, language=language)
except Statistics.DoesNotExist:
stats = FakeLangStatistics(pot_stats, language)
# Get the state of the translation
try:
state = State.objects.get(branch=branch, domain=domain, language=language)
except State.DoesNotExist:
# No need to save the state at this stage
state = State(branch=branch, domain=domain, language=language)
return pot_stats, stats, state
def vertimus_diff(request, action_id_1, action_id_2, level):
"""Show a diff between current action po file and previous file"""
if int(level) != 0:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment