From 431879aea8fcc7e287a14258c120c381f37d6596 Mon Sep 17 00:00:00 2001 From: Kumi Date: Sun, 23 Jun 2024 15:10:44 +0200 Subject: [PATCH] feat(api): add token management and serializer endpoints Introduced endpoints for generating and managing API tokens, enabling users to manage and regenerate their tokens via a web interface. Added Django forms and templates to support these functionalities. Enhanced REST API with new endpoints for creating, updating, and retrieving identifiers and suffixes, and included necessary serializers. Updated settings to include Django REST framework and token authentication. --- freedoi/accounts/forms.py | 5 +- .../templates/accounts/generate_token.html | 12 +++ .../templates/accounts/manage_tokens.html | 12 +++ freedoi/accounts/urls.py | 14 +++- freedoi/accounts/views.py | 46 +++++++++++- freedoi/resolver/serializers.py | 23 ++++++ freedoi/resolver/templates/base_generic.html | 69 +++++++++--------- freedoi/resolver/urls.py | 36 +++++++++ freedoi/resolver/views.py | 73 +++++++++++++++++++ freedoi/settings.py | 16 +++- 10 files changed, 266 insertions(+), 40 deletions(-) create mode 100644 freedoi/accounts/templates/accounts/generate_token.html create mode 100644 freedoi/accounts/templates/accounts/manage_tokens.html create mode 100644 freedoi/resolver/serializers.py diff --git a/freedoi/accounts/forms.py b/freedoi/accounts/forms.py index 26a01b8..b5dce1a 100644 --- a/freedoi/accounts/forms.py +++ b/freedoi/accounts/forms.py @@ -1,4 +1,7 @@ from django import forms class EmailForm(forms.Form): - email = forms.EmailField() \ No newline at end of file + email = forms.EmailField() + +class GenerateTokenForm(forms.Form): + pass \ No newline at end of file diff --git a/freedoi/accounts/templates/accounts/generate_token.html b/freedoi/accounts/templates/accounts/generate_token.html new file mode 100644 index 0000000..ac93351 --- /dev/null +++ b/freedoi/accounts/templates/accounts/generate_token.html @@ -0,0 +1,12 @@ +{% extends "base_generic.html" %} +{% block title %}Generate API Token{% endblock title %} +{% block content %} +
+

Generate API Token

+
+ {% csrf_token %} + {{ form.as_p }} + +
+
+{% endblock content %} diff --git a/freedoi/accounts/templates/accounts/manage_tokens.html b/freedoi/accounts/templates/accounts/manage_tokens.html new file mode 100644 index 0000000..c3ab136 --- /dev/null +++ b/freedoi/accounts/templates/accounts/manage_tokens.html @@ -0,0 +1,12 @@ +{% extends "base_generic.html" %} +{% block title %} + Manage API Tokens +{% endblock title %} +{% block content %} +
+

Manage API Tokens

+

Your API token:

+ + Regenerate Token +
+{% endblock content %} diff --git a/freedoi/accounts/urls.py b/freedoi/accounts/urls.py index ba0bdaa..6b17a6d 100644 --- a/freedoi/accounts/urls.py +++ b/freedoi/accounts/urls.py @@ -1,6 +1,14 @@ from django.urls import path from django.views.generic import TemplateView -from .views import SendLoginEmailView, LoginView, LogoutView +from .views import ( + SendLoginEmailView, + LoginView, + LogoutView, + APICustomObtainAuthToken, + APIGenerateTokenView, + GenerateTokenView, + ManageTokensView, +) urlpatterns = [ path("login///", LoginView.as_view(), name="login"), @@ -15,4 +23,8 @@ urlpatterns = [ TemplateView.as_view(template_name="accounts/email_sent.html"), name="email_sent", ), + path("api/token-auth/", APICustomObtainAuthToken.as_view(), name="api_token_auth"), + path("api/generate-token/", APIGenerateTokenView.as_view(), name="generate_token"), + path("generate-token/", GenerateTokenView.as_view(), name="generate_token"), + path("manage-tokens/", ManageTokensView.as_view(), name="manage_tokens"), ] diff --git a/freedoi/accounts/views.py b/freedoi/accounts/views.py index 9b1d933..98ecdca 100644 --- a/freedoi/accounts/views.py +++ b/freedoi/accounts/views.py @@ -3,11 +3,19 @@ from django.core.mail import send_mail from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes, force_str from django.http import HttpResponse -from django.shortcuts import redirect +from django.shortcuts import redirect, render from django.views.generic import FormView, View from django.contrib.auth.tokens import default_token_generator from django.contrib.auth import logout -from .forms import EmailForm +from django.contrib.auth.mixins import LoginRequiredMixin + +from rest_framework.authtoken.models import Token +from rest_framework.authtoken.views import ObtainAuthToken +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.permissions import IsAuthenticated + +from .forms import EmailForm, GenerateTokenForm User = get_user_model() @@ -53,4 +61,36 @@ class LoginView(View): class LogoutView(View): def get(self, request): logout(request) - return redirect("home") \ No newline at end of file + return redirect("home") + + +class APICustomObtainAuthToken(ObtainAuthToken): + def post(self, request, *args, **kwargs): + response = super().post(request, *args, **kwargs) + token, created = Token.objects.get_or_create(user=request.user) + return Response({"token": token.key}) + + +class APIGenerateTokenView(APIView): + permission_classes = [IsAuthenticated] + + def get(self, request, *args, **kwargs): + token, created = Token.objects.get_or_create(user=request.user) + return Response({"token": token.key}) + +class GenerateTokenView(LoginRequiredMixin, View): + def get(self, request): + form = GenerateTokenForm() + return render(request, 'accounts/generate_token.html', {'form': form}) + + def post(self, request): + form = GenerateTokenForm(request.POST) + if form.is_valid(): + token, created = Token.objects.get_or_create(user=request.user) + return redirect('manage_tokens') + return render(request, 'accounts/generate_token.html', {'form': form}) + +class ManageTokensView(LoginRequiredMixin, View): + def get(self, request): + token, created = Token.objects.get_or_create(user=request.user) + return render(request, 'accounts/manage_tokens.html', {'token': token}) \ No newline at end of file diff --git a/freedoi/resolver/serializers.py b/freedoi/resolver/serializers.py new file mode 100644 index 0000000..45a70a8 --- /dev/null +++ b/freedoi/resolver/serializers.py @@ -0,0 +1,23 @@ +from rest_framework import serializers +from .models import Suffix, Identifier + + +class SuffixSerializer(serializers.ModelSerializer): + class Meta: + model = Suffix + fields = [ + "id", + "name", + "suffix", + "prefix", + "description", + "approved", + "type", + "remote_resolver", + ] + + +class IdentifierSerializer(serializers.ModelSerializer): + class Meta: + model = Identifier + fields = ["id", "suffix", "identifier", "target_url"] diff --git a/freedoi/resolver/templates/base_generic.html b/freedoi/resolver/templates/base_generic.html index f68899f..550f223 100644 --- a/freedoi/resolver/templates/base_generic.html +++ b/freedoi/resolver/templates/base_generic.html @@ -3,11 +3,11 @@ - {% block title %}FreeDOI{% endblock %} - + + {% block title %}FreeDOI{% endblock title %} + +