#31 API Frontend token generating

* adds frontend settings for users to create API tokens on their user settings
This commit is contained in:
2022-01-27 11:37:38 +01:00
parent fc0cd2f086
commit c9bccec1a5
16 changed files with 255 additions and 29 deletions

View File

@@ -6,8 +6,12 @@ Created on: 08.07.21
"""
from django import forms
from django.urls import reverse
from django.db import IntegrityError
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from api.models import APIUserToken
from intervention.inputs import GenerateInput
from user.models import User
from konova.forms import BaseForm, BaseModalForm
@@ -113,3 +117,45 @@ class UserContactForm(BaseModalForm):
self.initialize_form_field("mail", self.instance.email)
class UserAPITokenForm(BaseForm):
token = forms.CharField(
label=_("Token"),
label_suffix="",
max_length=255,
required=True,
help_text=_("Generated automatically"),
widget=GenerateInput(
attrs={
"class": "form-control",
"url": reverse_lazy("api:generate-new-token"),
}
)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Create new token")
self.form_caption = _("A new token needs to be validated by an administrator!")
self.action_url = reverse("user:api-token")
self.cancel_redirect = reverse("user:index")
# Make direct token editing by user impossible. Instead set the proper url for generating a new token
self.initialize_form_field("token", None)
self.fields["token"].widget.attrs["readonly"] = True
def save(self):
""" Saves the form data
Returns:
api_token (APIUserToken)
"""
user = self.instance
new_token = self.cleaned_data["token"]
user.api_token.delete()
new_token = APIUserToken.objects.create(
token=new_token
)
user.api_token = new_token
user.save()
return new_token

View File

@@ -9,6 +9,7 @@ from django.contrib.auth.models import AbstractUser
from django.db import models
from api.models import APIUserToken
from konova.settings import ZB_GROUP, DEFAULT_GROUP, ETS_GROUP
from konova.utils.mailer import Mailer
from user.enums import UserNotificationEnum
@@ -142,3 +143,19 @@ class User(AbstractUser):
if notification_set:
mailer = Mailer()
mailer.send_mail_shared_data_checked(obj_identifier, self)
def get_API_token(self):
""" Getter for an API token
Creates a new one if none exists, yet.
Returns:
token (APIUserToken)
"""
if self.api_token is None:
token = APIUserToken.objects.create()
self.api_token = token
self.save()
else:
token = self.api_token
return token

View File

@@ -54,6 +54,14 @@
</button>
</a>
</div>
<div class="row mb-2">
<a href="{% url 'user:api-token' %}" title="{% trans 'See or edit your API token' %}">
<button class="btn btn-default">
{% fa5_icon 'code' %}
<span>{% trans 'API' %}</span>
</button>
</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,31 @@
{% extends 'base.html' %}
{% load i18n fontawesome_5 %}
{% block body %}
<div class="container">
<h3>{% trans 'API settings' %}</h3>
<div class="table-container">
<table class="table table-hover">
<tr>
<th scope="row">{% trans 'Current token' %}</th>
<td>{{ user.api_token.token }}</td>
</tr>
<tr>
<th scope="row">{% trans 'Authenticated by admins' %}</th>
{% if user.api_token.is_active %}
<td class="text-success" title="{% trans 'Token has been verified and can be used' %}">{% fa5_icon 'check-circle' %}</td>
{% else %}
<td class="text-primary" title="{% trans 'Token waiting for verification' %}">{% fa5_icon 'hourglass-half' %}</td>
{% endif %}
</tr>
<tr>
<th scope="row">{% trans 'Valid until' %}</th>
<td>{{ user.api_token.valid_until|default_if_none:"-" }}</td>
</tr>
</table>
</div>
</div>
<hr>
{% include 'form/table/generic_table_form.html' %}
{% endblock %}

View File

@@ -13,6 +13,7 @@ app_name = "user"
urlpatterns = [
path("", index_view, name="index"),
path("notifications/", notifications_view, name="notifications"),
path("token/api", api_token_view, name="api-token"),
path("contact/<id>", contact_view, name="contact"),
]

View File

@@ -2,14 +2,15 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import FORM_INVALID
from user.models import User
from django.http import HttpRequest
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext
from konova.decorators import any_group_check
from user.forms import UserNotificationForm, UserContactForm
from konova.decorators import any_group_check, default_group_required
from user.forms import UserNotificationForm, UserContactForm, UserAPITokenForm
@login_required
@@ -70,6 +71,37 @@ def notifications_view(request: HttpRequest):
return render(request, template, context)
@login_required
@default_group_required
def api_token_view(request: HttpRequest):
""" Handles the request for user api frontend settings
Args:
request (HttpRequest): The incoming request
Returns:
"""
template = "user/token.html"
form = UserAPITokenForm(request.POST or None, instance=request.user)
if request.method == "POST":
if form.is_valid():
token = form.save()
messages.info(request, _("New token generated. Administrators need to validate."))
return redirect("user:api-token")
else:
messages.error(request, FORM_INVALID, extra_tags="danger")
elif request.method != "GET":
raise NotImplementedError
context = {
"user": request.user,
"form": form,
TAB_TITLE_IDENTIFIER: _("User API token"),
}
context = BaseContext(request, context).context
return render(request, template, context)
@login_required
def contact_view(request: HttpRequest, id: str):
""" Renders contact modal view of a users contact data