Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api views from ddd #10

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,7 @@


class DoctorateAdmissionAdmin(admin.ModelAdmin):
def save_form(self, request, form, change):
"""
Set the author if the admission doctorate is being created
"""
admission_doctorate = form.save(commit=False)
if not change:
admission_doctorate.author = request.user.person
return admission_doctorate
pass


admin.site.register(DoctorateAdmission, DoctorateAdmissionAdmin)
66 changes: 66 additions & 0 deletions api/generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# ##############################################################################
#
# OSIS stands for Open Student Information System. It's an application
# designed to manage the core business of higher education institutions,
# such as universities, faculties, institutes and professional schools.
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2021 Université catholique de Louvain (http://www.uclouvain.be)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of this license - GNU General Public License - is available
# at the root of the source code of this program. If not,
# see http://www.gnu.org/licenses/.
#
# ##############################################################################
from rest_framework.schemas.openapi import SchemaGenerator


class AdmissionSchemaGenerator(SchemaGenerator):
def get_schema(self, *args, **kwargs):
schema = super().get_schema(*args, **kwargs)
schema["info"]["title"] = "Admission API"
schema["info"]["description"] = "This API delivers data for the Admission project."
schema["info"]["contact"] = {
"name": "UCLouvain - OSIS",
"url": "https://github.com/uclouvain/osis"
}
schema["servers"] = [
{
"url": "https://{environment}.osis.uclouvain.be/api/v1/admission/",
"variables": {
"environment": {
"default": "dev",
"enum": [
"dev",
"qa",
"test"
]
}
}
},
{
"url": "https://osis.uclouvain.be/api/v1/admission/",
"description": "Production server"
}
]
schema["security"] = [{"Token": []}]
schema['components']["securitySchemes"] = {
"Token": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"description": "Enter your token in the format **Token <token>**"
}
}
return schema
14 changes: 8 additions & 6 deletions api/urls_v1.py → api/url_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
# see http://www.gnu.org/licenses/.
#
# ##############################################################################
from django.urls import path

from rest_framework.routers import DefaultRouter

from admission.api.views import DoctorateAdmissionViewSet
from admission.api import views

app_name = "admission_api_v1"
router = DefaultRouter()
router.register(r'', DoctorateAdmissionViewSet, basename='doctorate')
urlpatterns = router.urls
urlpatterns = [
path('propositions', views.PropositionListViewSet.as_view()),
path('propositions/<uuid:uuid>', views.PropositionViewSet.as_view()),
path('autocomplete/sector', views.AutocompleteSectorViewSet.as_view()),
path('autocomplete/sector/<str:sigle>/doctorates', views.AutocompleteDoctoratViewSet.as_view()),
]
8 changes: 6 additions & 2 deletions api/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@
#
# ##############################################################################

from .doctorate import DoctorateAdmissionViewSet
from admission.api.views.doctorate import *
from admission.api.views.autocomplete import *

__all__ = [
"DoctorateAdmissionViewSet",
"PropositionViewSet",
"PropositionListViewSet",
"AutocompleteDoctoratViewSet",
"AutocompleteSectorViewSet",
]
63 changes: 63 additions & 0 deletions api/views/autocomplete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ##############################################################################
#
# OSIS stands for Open Student Information System. It's an application
# designed to manage the core business of higher education institutions,
# such as universities, faculties, institutes and professional schools.
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2021 Université catholique de Louvain (http://www.uclouvain.be)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of this license - GNU General Public License - is available
# at the root of the source code of this program. If not,
# see http://www.gnu.org/licenses/.
#
# ##############################################################################
from django.db.models import F
from rest_framework.generics import ListAPIView
from rest_framework.response import Response

from admission.contrib import serializers
from admission.contrib.models import EntityProxy
from base.models.enums.entity_type import SECTOR
from ddd.logic.admission.preparation.projet_doctoral.commands import SearchDoctoratCommand
from infrastructure.messages_bus import message_bus_instance


class AutocompleteSectorViewSet(ListAPIView):
pagination_class = None
filter_backends = None
serializer_class = serializers.SectorDTOSerializer

def list(self, request, **kwargs):
# TODO revert to command once it's in the shared kernel
qs = EntityProxy.objects.with_acronym().with_title().with_type().filter(type=SECTOR).annotate(
sigle=F('acronym'),
intitule_fr=F('title'),
intitule_en=F('title'),
).values('sigle', 'intitule_fr', 'intitule_en')
serializer = serializers.SectorDTOSerializer(instance=qs, many=True)
return Response(serializer.data)


class AutocompleteDoctoratViewSet(ListAPIView):
pagination_class = None
filter_backends = None
serializer_class = serializers.DoctoratDTOSerializer

def list(self, request, **kwargs):
doctorat_list = message_bus_instance.invoke(
SearchDoctoratCommand(sigle_secteur_entite_gestion=kwargs.get('sigle'))
)
serializer = serializers.DoctoratDTOSerializer(instance=doctorat_list, many=True)
return Response(serializer.data)
130 changes: 109 additions & 21 deletions api/views/doctorate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,121 @@
# see http://www.gnu.org/licenses/.
#
# ##############################################################################

from rest_framework import viewsets, status
from rest_framework.authentication import SessionAuthentication
from rest_framework import mixins, status
from rest_framework.generics import GenericAPIView, ListCreateAPIView
from rest_framework.response import Response
from rest_framework.schemas.openapi import AutoSchema
from rest_framework.serializers import Serializer

from admission.contrib.models import DoctorateAdmission
from admission.contrib.serializers import (
DoctorateAdmissionReadSerializer, DoctorateAdmissionWriteSerializer
from admission.contrib import serializers
from ddd.logic.admission.preparation.projet_doctoral.commands import (
CompleterPropositionCommand, GetPropositionCommand,
InitierPropositionCommand,
SearchPropositionsCommand,
)
from infrastructure.messages_bus import message_bus_instance


class DetailedAutoSchema(AutoSchema):
def get_request_body(self, path, method):
if method not in ('PUT', 'PATCH', 'POST'):
return {}

self.request_media_types = self.map_parsers(path, method)

serializer = self.get_serializer(path, method, for_response=False)

if not isinstance(serializer, Serializer):
item_schema = {}
else:
item_schema = self._get_reference(serializer)

return {
'content': {
ct: {'schema': item_schema}
for ct in self.request_media_types
}
}

def get_components(self, path, method):
if method.lower() == 'delete':
return {}

components = {}
for with_response in [True, False]:
serializer = self.get_serializer(path, method, for_response=with_response)
if not isinstance(serializer, Serializer):
return {}
component_name = self.get_component_name(serializer)
content = self.map_serializer(serializer)
components[component_name] = content

return components

def get_serializer(self, path, method, for_response=True):
raise NotImplementedError


class PropositionListSchema(DetailedAutoSchema):
def get_operation_id_base(self, path, method, action):
return '_proposition' if method == 'POST' else '_propositions'

class DoctorateAdmissionViewSet(viewsets.ModelViewSet):
queryset = DoctorateAdmission.objects.all()
authentication_classes = [SessionAuthentication, ]
lookup_field = "uuid"
def get_serializer(self, path, method, for_response=True):
if method == 'POST':
if for_response:
return serializers.PropositionIdentityDTOSerializer()
return serializers.InitierPropositionCommandSerializer()
return serializers.PropositionSearchDTOSerializer()

def get_serializer_class(self):
if self.action in ["create", "update", "partial_update"]:
return DoctorateAdmissionWriteSerializer
return DoctorateAdmissionReadSerializer

def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
class PropositionListViewSet(ListCreateAPIView):
schema = PropositionListSchema()
pagination_class = None
filter_backends = None

def list(self, request, **kwargs):
proposition_list = message_bus_instance.invoke(
SearchPropositionsCommand(matricule_candidat=request.user.person.global_id)
)
serializer = serializers.PropositionSearchDTOSerializer(instance=proposition_list, many=True)
return Response(serializer.data)

def create(self, request, **kwargs):
serializer = serializers.InitierPropositionCommandSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
serializer = DoctorateAdmissionReadSerializer(instance=serializer.instance)
headers = self.get_success_headers(serializer.data)
return Response(
serializer.data, status=status.HTTP_201_CREATED, headers=headers
result = message_bus_instance.invoke(InitierPropositionCommand(**serializer.data))
serializer = serializers.PropositionIdentityDTOSerializer(instance=result)
return Response(serializer.data, status=status.HTTP_201_CREATED)


class PropositionSchema(DetailedAutoSchema):
def get_operation_id_base(self, path, method, action):
return '_proposition'

def get_serializer(self, path, method, for_response=True):
if method == 'PUT':
if for_response:
return serializers.PropositionIdentityDTOSerializer()
return serializers.CompleterPropositionCommandSerializer()
return serializers.PropositionDTOSerializer()


class PropositionViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView):
SebCorbin marked this conversation as resolved.
Show resolved Hide resolved
schema = PropositionSchema()
pagination_class = None
filter_backends = None

def get(self, request, *args, **kwargs):
# TODO call osis_role perm for this object
proposition = message_bus_instance.invoke(
GetPropositionCommand(uuid_proposition=kwargs.get('uuid'))
)
serializer = serializers.PropositionDTOSerializer(instance=proposition)
return Response(serializer.data)

def put(self, request, *args, **kwargs):
serializer = serializers.CompleterPropositionCommandSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
result = message_bus_instance.invoke(CompleterPropositionCommand(**serializer.data))
serializer = serializers.PropositionIdentityDTOSerializer(instance=result)
return Response(serializer.data, status=status.HTTP_200_OK)
2 changes: 1 addition & 1 deletion auth/predicates.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

@predicate
def is_admission_request_author(user: User, obj: BaseAdmission):
return obj.author == user.person
return obj.candidate == user.person


@predicate
Expand Down
4 changes: 2 additions & 2 deletions contrib/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
#
# ##############################################################################

from .doctorate import DoctorateAdmissionCreateOrUpdateForm
from .doctorate import DoctorateAdmissionProjectForm

__all__ = [
"DoctorateAdmissionCreateOrUpdateForm",
"DoctorateAdmissionProjectForm",
]
Loading