#31 API Frontend token generating

* adds frontend settings for users to create API tokens on their user settings
pull/90/head
mpeltriaux 3 years ago
parent 25cccee5d6
commit b13e67e061

@ -7,8 +7,11 @@ Created on: 21.01.22
"""
from django.urls import path, include
from api.views.method_views import generate_new_token_view
app_name = "api"
urlpatterns = [
path("v1/", include("api.urls.v1.urls", namespace="v1")),
path("token/generate", generate_new_token_view, name="generate-new-token"),
]

@ -0,0 +1,35 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 27.01.22
"""
from django.contrib.auth.decorators import login_required
from django.http import HttpRequest, JsonResponse
from api.models import APIUserToken
@login_required
def generate_new_token_view(request: HttpRequest):
""" Handles request for fetching
Args:
request (HttpRequest): The incoming request
Returns:
"""
if request.method == "GET":
token = APIUserToken()
while APIUserToken.objects.filter(token=token.token).exists():
token = APIUserToken()
return JsonResponse(
data={
"gen_data": token.token
}
)
else:
raise NotImplementedError

@ -253,4 +253,4 @@ class EcoAccountAPIShareView(AbstractModelShareAPIView):
class EmaAPIShareView(AbstractModelShareAPIView):
model = Ema
model = Ema

@ -108,7 +108,7 @@ def new_id_view(request: HttpRequest):
identifier = tmp.generate_new_identifier()
return JsonResponse(
data={
"identifier": identifier
"gen_data": identifier
}
)

@ -118,7 +118,7 @@ def new_id_view(request: HttpRequest):
identifier = tmp.generate_new_identifier()
return JsonResponse(
data={
"identifier": identifier
"gen_data": identifier
}
)

@ -108,7 +108,7 @@ def new_id_view(request: HttpRequest):
identifier = tmp.generate_new_identifier()
return JsonResponse(
data={
"identifier": identifier
"gen_data": identifier
}
)

@ -108,7 +108,7 @@ def new_id_view(request: HttpRequest):
identifier = tmp_intervention.generate_new_identifier()
return JsonResponse(
data={
"identifier": identifier
"gen_data": identifier
}
)

@ -1,9 +1,9 @@
{% load i18n fontawesome_5 %}
<div class="input-group w-100" title="{{ widget.value|stringformat:'s' }}">
<input id="gen-id-input" aria-describedby="gen-id-btn" type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
<input id="gen-data-input" aria-describedby="gen-data-btn" type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
<div class="input-group-append" onclick="fetchNewIdentifier()">
<span id="gen-id-btn" class="btn btn-default" value="{% trans 'Generate new' %}" title="{% trans 'Generate new' %}">{% fa5_icon 'dice' %}</span>
<span id="gen-data-btn" class="btn btn-default" value="{% trans 'Generate new' %}" title="{% trans 'Generate new' %}">{% fa5_icon 'dice' %}</span>
</div>
</div>
<script>
@ -13,7 +13,7 @@
return response.json();
})
.then(function(data){
document.getElementById("gen-id-input").value = data["identifier"];
document.getElementById("gen-data-input").value = data["gen_data"];
})
.catch(function(error){
console.log(error);

Binary file not shown.

@ -20,13 +20,13 @@
#: konova/filters/mixins.py:385 konova/filters/mixins.py:386
#: konova/forms.py:140 konova/forms.py:241 konova/forms.py:312
#: konova/forms.py:339 konova/forms.py:349 konova/forms.py:362
#: konova/forms.py:374 konova/forms.py:392 user/forms.py:38
#: konova/forms.py:374 konova/forms.py:392 user/forms.py:42
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-20 12:30+0100\n"
"POT-Creation-Date: 2022-01-27 11:35+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -317,6 +317,7 @@ msgid "Identifier"
msgstr "Kennung"
#: compensation/forms/forms.py:35 intervention/forms/forms.py:29
#: user/forms.py:126
msgid "Generated automatically"
msgstr "Automatisch generiert"
@ -1716,11 +1717,11 @@ msgstr "Kontrolle am"
msgid "Other"
msgstr "Sonstige"
#: konova/sub_settings/django_settings.py:154
#: konova/sub_settings/django_settings.py:155
msgid "German"
msgstr ""
#: konova/sub_settings/django_settings.py:155
#: konova/sub_settings/django_settings.py:156
msgid "English"
msgstr ""
@ -2214,39 +2215,51 @@ msgid ""
" "
msgstr ""
"\n"
" Diese Daten sind noch nicht veröffentlicht und "
"können daher aktuell nicht eingesehen werden. Schauen Sie zu einem späteren "
"Zeitpunkt wieder vorbei. \n"
" Diese Daten sind noch nicht veröffentlicht und können daher "
"aktuell nicht eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt "
"wieder vorbei. \n"
" "
#: user/forms.py:23
#: user/forms.py:27
msgid "Notifications"
msgstr "Benachrichtigungen"
#: user/forms.py:25
#: user/forms.py:29
msgid "Select the situations when you want to receive a notification"
msgstr "Wann wollen Sie per E-Mail benachrichtigt werden?"
#: user/forms.py:37
#: user/forms.py:41
msgid "Edit notifications"
msgstr "Benachrichtigungen bearbeiten"
#: user/forms.py:72 user/templates/user/index.html:9
#: user/forms.py:76 user/templates/user/index.html:9
msgid "Username"
msgstr "Nutzername"
#: user/forms.py:83
#: user/forms.py:87
msgid "Person name"
msgstr "Name"
#: user/forms.py:94 user/templates/user/index.html:17
#: user/forms.py:98 user/templates/user/index.html:17
msgid "E-Mail"
msgstr ""
#: user/forms.py:108
#: user/forms.py:112
msgid "User contact data"
msgstr "Kontaktdaten"
#: user/forms.py:122
msgid "Token"
msgstr ""
#: user/forms.py:137
msgid "Create new token"
msgstr "Neuen Token generieren"
#: user/forms.py:138
msgid "A new token needs to be validated by an administrator!"
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
#: user/models/user_action.py:20
msgid "Unrecorded"
msgstr "Entzeichnet"
@ -2300,18 +2313,58 @@ msgstr "Benachrichtigungseinstellungen ändern"
msgid "Notification settings"
msgstr "Benachrichtigungen"
#: user/views.py:29
#: user/templates/user/index.html:58
msgid "See or edit your API token"
msgstr ""
#: user/templates/user/index.html:61
msgid "API"
msgstr ""
#: user/templates/user/token.html:6
msgid "API settings"
msgstr "API Einstellungen"
#: user/templates/user/token.html:10
msgid "Current token"
msgstr "Aktueller Token"
#: user/templates/user/token.html:14
msgid "Authenticated by admins"
msgstr "Von Admin freigeschaltet"
#: user/templates/user/token.html:16
msgid "Token has been verified and can be used"
msgstr "Token wurde freigeschaltet und kann verwendet werden"
#: user/templates/user/token.html:18
msgid "Token waiting for verification"
msgstr "Token noch nicht freigeschaltet"
#: user/templates/user/token.html:22
msgid "Valid until"
msgstr "Läuft ab am"
#: user/views.py:30
msgid "User settings"
msgstr "Einstellungen"
#: user/views.py:55
#: user/views.py:56
msgid "Notifications edited"
msgstr "Benachrichtigungen bearbeitet"
#: user/views.py:67
#: user/views.py:68
msgid "User notifications"
msgstr "Benachrichtigungen"
#: user/views.py:90
msgid "New token generated. Administrators need to validate."
msgstr "Neuer Token generiert. Administratoren sind informiert."
#: user/views.py:99
msgid "User API token"
msgstr "API Nutzer Token"
#: venv/lib/python3.7/site-packages/bootstrap4/components.py:17
#: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/form_errors.html:3
#: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/messages.html:4
@ -3056,7 +3109,7 @@ msgstr ""
#: venv/lib/python3.7/site-packages/django/forms/fields.py:54
msgid "This field is required."
msgstr ""
msgstr "Pflichtfeld"
#: venv/lib/python3.7/site-packages/django/forms/fields.py:247
msgid "Enter a whole number."

@ -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

@ -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

@ -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>

@ -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 %}

@ -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"),
]

@ -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

Loading…
Cancel
Save