diff --git a/scipost_django/api/urls.py b/scipost_django/api/urls.py index 05779e14fa8ba4bc24a98a89edbf1e9610409f54..b3fbee1594a7f60c5a9354f84ed72cc4842f50b9 100644 --- a/scipost_django/api/urls.py +++ b/scipost_django/api/urls.py @@ -8,6 +8,7 @@ from django.urls import include, path from rest_framework import routers from journals.viewsets import PublicationViewSet +from organizations.api.viewsets import OrganizationViewSet, OrganizationNAPViewSet from submissions.viewsets import SubmissionViewSet # Next two: old style, to be deprecated: @@ -21,7 +22,14 @@ app_name = 'api' router = routers.SimpleRouter() +# journals router.register('publications', PublicationViewSet) + +# organizations +router.register('organizations', OrganizationViewSet) +router.register('nap/organizations', OrganizationNAPViewSet) + +# submissions router.register('submissions', SubmissionViewSet) # Next two: old style, to be deprecated: diff --git a/scipost_django/organizations/api/serializers.py b/scipost_django/organizations/api/serializers.py index d93a1a56d73d897553f08c83b939719ff24146a0..6864e040d89179e6fcd36a2c3201f700d2fec7c6 100644 --- a/scipost_django/organizations/api/serializers.py +++ b/scipost_django/organizations/api/serializers.py @@ -2,58 +2,62 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" +import datetime + from rest_framework import serializers from ..models import Organization -from journals.api.serializers import OrgPubFractionSerializer -from journals.models import Journal, OrgPubFraction - -class OrganizationSerializer(serializers.HyperlinkedModelSerializer): +class OrganizationSerializer(serializers.ModelSerializer): + url = serializers.HyperlinkedIdentityField( + view_name='organizations:organization_detail', + lookup_field='pk' + ) class Meta: model = Organization fields = [ - 'name', 'name_original', 'acronym', 'country' + 'url', + 'orgtype', + 'status', + 'name', + 'name_original', + 'acronym', + 'country', + 'parent', + 'superseded_by', ] - read_only_fields = [ - 'name', 'name_original', 'acronym', 'country' + + +class OrganizationNAPSerializer(OrganizationSerializer): + nap = serializers.SerializerMethodField() + + class Meta: + model = Organization + fields = [ + 'url', + 'orgtype', + 'status', + 'name', + 'name_original', + 'acronym', + 'country', + 'parent', + 'superseded_by', + 'nap' ] + def get_nap(self, obj): + per_year = {} + for year in range(datetime.date.today().year, 2015, -1): + per_year[year] = obj.get_publications(year=year).count() + return { + 'total': obj.cf_nr_associated_publications, + 'per_year': per_year + } + class OrganizationBalanceSerializer(serializers.BaseSerializer): def to_representation(self, instance): return instance.get_balance_info() - - # pubfractions = OrgPubFraction.objects.filter(organization=instance) - # pubyears = range(int(timezone.now().strftime('%Y')), 2015, -1) - # rep = {} - # cumulative_balance = 0 - # for year in pubyears: - # rep[str(year)] = {} - # summed_expenditure = 0 - # rep[str(year)]['expenditures'] = {} - # pfy = pubfractions.filter(publication__publication_date__year=year) - # contribution = instance.total_subsidies_in_year(year) - # rep[str(year)]['contribution'] = contribution - # journal_labels = set([f.publication.get_journal().doi_label for f in pfy.all()]) - # for journal_label in journal_labels: - # sumpf = pfy.filter( - # publication__doi_label__istartswith=journal_label + '.' - # ).aggregate(Sum('fraction'))['fraction__sum'] - # costperpaper = get_object_or_404(Journal, - # doi_label=journal_label).cost_per_publication(year) - # expenditure = int(costperpaper* sumpf) - # if sumpf > 0: - # rep[str(year)]['expenditures'][journal_label] = { - # 'pubfractions': sumpf, - # 'costperpaper': costperpaper, - # 'expenditure': expenditure, - # } - # summed_expenditure += expenditure - # rep[str(year)]['expenditures']['total'] = summed_expenditure - # rep[str(year)]['balance'] = contribution - summed_expenditure - # cumulative_balance += contribution - summed_expenditure - # rep['cumulative'] = cumulative_balance - # return rep diff --git a/scipost_django/organizations/api/urls.py b/scipost_django/organizations/api/urls.py index 83e5a3669b6b04e806f0dcdc3b8da3cc1ec9489d..1b9442509b490d2d55d4fc7b4437a7c1528464a3 100644 --- a/scipost_django/organizations/api/urls.py +++ b/scipost_django/organizations/api/urls.py @@ -4,21 +4,24 @@ __license__ = "AGPL v3" from django.urls import path -from organizations.api import views as api_views +from rest_framework import routers +#from organizations.api import views as api_views +from . import views as api_views +from . import viewsets as api_viewsets -urlpatterns = [ - path( # /api/organizations/ - '', - api_views.OrganizationListAPIView.as_view(), - name='organizations' - ), - path( # /api/organizations/<int:pk> - '<int:pk>', - api_views.OrganizationRetrieveAPIView.as_view(), - name='organization-detail' - ), +router = routers.SimpleRouter() + +# OrganizationNAPViewSet before OrganizationViewSet, to prevent 404 +router.register('nap', api_viewsets.OrganizationNAPViewSet) +router.register('', api_viewsets.OrganizationViewSet) + + +urlpatterns = router.urls + +urlpatterns += [ + path( # /api/organizations/<int:pk>/balance '<int:pk>/balance', api_views.OrganizationBalanceAPIView.as_view(), diff --git a/scipost_django/organizations/api/views.py b/scipost_django/organizations/api/views.py index 0471fa8ba267c726e26102c30a42b6d8869836d2..2dfc6d54905337e654632fb420af35d07d5e3529 100644 --- a/scipost_django/organizations/api/views.py +++ b/scipost_django/organizations/api/views.py @@ -3,19 +3,29 @@ __license__ = "AGPL v3" from rest_framework.generics import ListAPIView, RetrieveAPIView +from rest_framework.settings import api_settings +from rest_framework_csv import renderers as r from ..models import Organization -from .serializers import OrganizationSerializer, OrganizationBalanceSerializer +from .serializers import ( + OrganizationSerializer, + OrganizationNAPSerializer, + OrganizationBalanceSerializer +) +from .viewsets import OrganizationFilterSet -class OrganizationListAPIView(ListAPIView): - queryset = Organization.objects.all().order_by('name') - serializer_class = OrganizationSerializer - - -class OrganizationRetrieveAPIView(RetrieveAPIView): +class OrganizationNAPListAPIView(ListAPIView): queryset = Organization.objects.all() - serializer_class = OrganizationSerializer + serializer_class = OrganizationNAPSerializer + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (r.PaginatedCSVRenderer, ) + search_fields = ['name', 'name_original', 'acronym',] + filterset_class = OrganizationFilterSet + default_filtering_fields = [ + 'name__icontains', + 'name_original__icontains', + 'acronym__icontains' + ] class OrganizationBalanceAPIView(RetrieveAPIView): diff --git a/scipost_django/organizations/api/viewsets.py b/scipost_django/organizations/api/viewsets.py new file mode 100644 index 0000000000000000000000000000000000000000..839e4ae985f5efa27f3d85fb43d99e696c0bb7e9 --- /dev/null +++ b/scipost_django/organizations/api/viewsets.py @@ -0,0 +1,54 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +import datetime + +from django_filters import rest_framework as df_filters + +from rest_framework import viewsets +from rest_framework.decorators import action +from rest_framework.permissions import AllowAny +from rest_framework.response import Response +from rest_framework.settings import api_settings +from rest_framework_csv import renderers as r + +from api.viewsets.mixins import FilteringOptionsActionMixin + +from ..models import Organization +from .serializers import OrganizationSerializer, OrganizationNAPSerializer + + +class OrganizationFilterSet(df_filters.FilterSet): + class Meta: + model = Organization + fields = { + 'name': ['icontains',], + 'name_original': ['icontains',], + 'acronym': ['icontains',], + 'country': ['exact',], + 'cf_nr_associated_publications': ['gte', 'lte',] + } + + +class OrganizationViewSet(FilteringOptionsActionMixin, + viewsets.ReadOnlyModelViewSet): + queryset = Organization.objects.all() + permission_classes = [AllowAny,] + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (r.PaginatedCSVRenderer, ) + serializer_class = OrganizationSerializer + search_fields = ['name', 'name_original', 'acronym',] + filterset_class = OrganizationFilterSet + default_filtering_fields = [ + 'name__icontains', + 'name_original__icontains', + 'acronym__icontains' + ] + + +class OrganizationNAPViewSet(OrganizationViewSet): + serializer_class = OrganizationNAPSerializer + ordering_fields = ['name', 'cf_nr_associated_publications'] + + def get_view_name(self): + return 'Organization NAP'