diff --git a/pdfding/core/settings/base.py b/pdfding/core/settings/base.py index e3ec5232..070c1d34 100644 --- a/pdfding/core/settings/base.py +++ b/pdfding/core/settings/base.py @@ -39,6 +39,8 @@ 'allauth.socialaccount', 'allauth.socialaccount.providers.openid_connect', 'allauth.mfa', + 'rest_framework', + 'rest_framework.authtoken', 'django_htmx', 'huey.contrib.djhuey', 'admin', @@ -207,6 +209,17 @@ log_level = environ.get('LOG_LEVEL', 'ERROR') +# Django REST Framework Configuration +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.TokenAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], +} + LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/pdfding/users/api.py b/pdfding/users/api.py new file mode 100644 index 00000000..d642ac4e --- /dev/null +++ b/pdfding/users/api.py @@ -0,0 +1,37 @@ +from rest_framework import serializers, status, viewsets +from rest_framework.authtoken.models import Token +from rest_framework.decorators import action +from rest_framework.permissions import IsAuthenticated +from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer +from rest_framework.response import Response + + +class TokenSerializer(serializers.ModelSerializer): + class Meta: + model = Token + fields = ['key', 'created'] + + +class TokenViewSet(viewsets.ViewSet): + permission_classes = [IsAuthenticated] + renderer_classes = [TemplateHTMLRenderer, JSONRenderer] + serializer_class = TokenSerializer + + def list(self, request): + token = Token.objects.filter(user=request.user).first() + return Response({'token': token}, template_name='partials/token_management.html') + + def create(self, request): + token, created = Token.objects.get_or_create(user=request.user) + return Response({'token': token}, template_name='partials/token_management.html', status=status.HTTP_201_CREATED if created else status.HTTP_200_OK) + + @action(detail=False, methods=['post'], url_path='rotate') + def rotate(self, request): + Token.objects.filter(user=request.user).delete() + token = Token.objects.create(user=request.user) + return Response({'token': token}, template_name='partials/token_management.html') + + @action(detail=False, methods=['post'], url_path='delete') + def delete(self, request): + Token.objects.filter(user=request.user).delete() + return Response({'token': None}, template_name='partials/token_management.html') diff --git a/pdfding/users/templates/access_token.html b/pdfding/users/templates/access_token.html new file mode 100644 index 00000000..a0cbb5cf --- /dev/null +++ b/pdfding/users/templates/access_token.html @@ -0,0 +1,68 @@ +{% extends 'layouts/blank.html' %} +{% load i18n %} + +{% block content %} +{% trans "Edit" as edit %} +
{% trans 'Generate a single API token to authenticate your requests without sharing your password.' %}
+