diff --git a/med/settings.py b/med/settings.py index b9be185..eef8207 100644 --- a/med/settings.py +++ b/med/settings.py @@ -34,6 +34,7 @@ INSTALLED_APPS = [ # External apps 'reversion', + 'rest_framework', # Django contrib 'django.contrib.admin', @@ -150,6 +151,13 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static_files') # Example: "http://example.com/static/", "http://static.example.com/" STATIC_URL = '/static/' +# Django REST Framework +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.DjangoModelPermissions', + ] +} + # Med configuration PAGINATION_NUMBER = 25 diff --git a/med/urls.py b/med/urls.py index b422376..6cf18ff 100644 --- a/med/urls.py +++ b/med/urls.py @@ -2,21 +2,42 @@ # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from django.contrib.auth.decorators import login_required from django.contrib.auth.views import PasswordResetView from django.urls import include, path -from django.views.generic import RedirectView +from django.views.generic import RedirectView, TemplateView +from rest_framework import routers +from rest_framework.schemas import get_schema_view -from media.views import index +import media.views +import users.views from .admin import admin_site +# API router +router = routers.DefaultRouter() +router.register(r'authors', media.views.AuteurViewSet) +router.register(r'media', media.views.MediaViewSet) +router.register(r'borrowed_items', media.views.EmpruntViewSet) +router.register(r'games', media.views.JeuViewSet) +router.register(r'users', users.views.UserViewSet) +router.register(r'groups', users.views.GroupViewSet) + urlpatterns = [ - path('', index, name='index'), + path('', media.views.index, name='index'), # Include project routers path('users/', include('users.urls')), path('media/', include('media.urls')), path('logs/', include('logs.urls')), + # REST API + path('api/', include(router.urls)), + path('api-auth/', include('rest_framework.urls')), + path('openapi', login_required(get_schema_view()), name='openapi-schema'), + path('redoc/', + login_required(TemplateView.as_view(template_name='redoc.html')), + name='redoc'), + # Include Django Contrib and Core routers path('accounts/password_reset/', PasswordResetView.as_view(), name='admin_password_reset'), diff --git a/media/serializers.py b/media/serializers.py new file mode 100644 index 0000000..2972599 --- /dev/null +++ b/media/serializers.py @@ -0,0 +1,31 @@ +from rest_framework import serializers + +from .models import Auteur, Media, Emprunt, Jeu + + +class AuteurSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Auteur + fields = ['url', 'name'] + + +class MediaSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Media + fields = ['url', 'isbn', 'title', 'subtitle', 'external_url', + 'side_identifier', 'authors', 'number_of_pages', + 'publish_date'] + + +class EmpruntSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Emprunt + fields = ['url', 'media', 'user', 'date_emprunt', 'date_rendu', + 'permanencier_emprunt', 'permanencier_rendu'] + + +class JeuSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Jeu + fields = ['url', 'name', 'proprietaire', 'duree', 'nombre_joueurs_min', + 'nombre_joueurs_max', 'comment'] diff --git a/media/views.py b/media/views.py index fb420c2..c8a4459 100644 --- a/media/views.py +++ b/media/views.py @@ -8,9 +8,12 @@ from django.db import transaction from django.shortcuts import redirect, render from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from rest_framework import viewsets from reversion import revisions as reversion -from .models import Emprunt +from .models import Auteur, Media, Emprunt, Jeu +from .serializers import AuteurSerializer, MediaSerializer, \ + EmpruntSerializer, JeuSerializer @login_required @@ -40,3 +43,35 @@ def index(request): return render(request, 'admin/index.html', { 'title': _('Welcome to the Mediatek database'), }) + + +class AuteurViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows authors to be viewed or edited. + """ + queryset = Auteur.objects.all() + serializer_class = AuteurSerializer + + +class MediaViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows media to be viewed or edited. + """ + queryset = Media.objects.all() + serializer_class = MediaSerializer + + +class EmpruntViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows borrowed items to be viewed or edited. + """ + queryset = Emprunt.objects.all() + serializer_class = EmpruntSerializer + + +class JeuViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows games to be viewed or edited. + """ + queryset = Jeu.objects.all() + serializer_class = JeuSerializer diff --git a/requirements.txt b/requirements.txt index e6c3d57..c30b5b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,7 @@ pytz==2019.1 six==1.12.0 sqlparse==0.2.4 django-reversion==3.0.3 -python-stdnum==1.10 \ No newline at end of file +python-stdnum==1.10 +djangorestframework==3.9.2 +pyyaml==3.13 +coreapi==2.3.3 \ No newline at end of file diff --git a/theme/static/css/admin.css b/theme/static/css/admin.css index 7e43d06..1a7d9ed 100644 --- a/theme/static/css/admin.css +++ b/theme/static/css/admin.css @@ -152,4 +152,14 @@ img.poulpy { max-width: 100%; width: 1000px; height: auto; +} + +/* No padding content for special pages */ +#content.nopadding { + padding: 0; +} + +/* Fix Redoc */ +svg.search-icon { + display: none; } \ No newline at end of file diff --git a/theme/templates/admin/base_site.html b/theme/templates/admin/base_site.html index b46f09f..aebccad 100644 --- a/theme/templates/admin/base_site.html +++ b/theme/templates/admin/base_site.html @@ -93,9 +93,12 @@ SPDX-License-Identifier: GPL-3.0-or-later - Mediatek 2017-2020 — - Nous contactez +

+ Mediatek 2017-2020 — + Nous contactez — + Explorer l'API +

{% endif %} diff --git a/theme/templates/redoc.html b/theme/templates/redoc.html new file mode 100644 index 0000000..80e3107 --- /dev/null +++ b/theme/templates/redoc.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n static %} + +{% block coltype %}nopadding{% endblock %} + +{% block content %} + + +{% endblock %} diff --git a/users/serializers.py b/users/serializers.py new file mode 100644 index 0000000..e1b5faf --- /dev/null +++ b/users/serializers.py @@ -0,0 +1,18 @@ +from django.contrib.auth.models import Group +from rest_framework import serializers + +from .models import User + + +class UserSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = User + fields = ['url', 'username', 'first_name', 'last_name', 'email', + 'groups', 'telephone', 'address', 'maxemprunt', 'comment', + 'date_joined'] + + +class GroupSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Group + fields = ['url', 'name'] diff --git a/users/views.py b/users/views.py index e32fe51..cddbb1f 100644 --- a/users/views.py +++ b/users/views.py @@ -4,14 +4,17 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.models import User, Group from django.db import transaction from django.shortcuts import redirect, render from django.template.context_processors import csrf from django.utils.translation import ugettext_lazy as _ +from rest_framework import viewsets from reversion import revisions as reversion from users.forms import BaseInfoForm from users.models import Adhesion, User +from .serializers import UserSerializer, GroupSerializer def form(ctx, template, request): @@ -60,3 +63,19 @@ def adherer(request, userid): reversion.set_comment("Adhesion de %s" % users) messages.success(request, "Adhesion effectuee") return redirect("admin:users_user_changelist") + + +class UserViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows users to be viewed or edited. + """ + queryset = User.objects.all() + serializer_class = UserSerializer + + +class GroupViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows groups to be viewed or edited. + """ + queryset = Group.objects.all() + serializer_class = GroupSerializer