# 456 Rework API key creation

* removes frontend input field holding generated API key
* replaces with modal form
* reworks tests on API token form
This commit is contained in:
mpeltriaux 2025-01-08 16:03:26 +01:00
parent 123a470006
commit 9b63307f01
11 changed files with 214 additions and 389 deletions

View File

@ -91,3 +91,6 @@ INTERVENTION_HAS_REVOCATIONS_TEMPLATE = _("This intervention has {} revocations"
DATA_CHECKED_ON_TEMPLATE = _("Checked on {} by {}")
DATA_CHECKED_PREVIOUSLY_TEMPLATE = _("Data has changed since last check on {} by {}")
DATA_IS_UNCHECKED = _("Current data not checked yet")
# API TOKEN SETTINGS
NEW_API_TOKEN_GENERATED = _("New token generated. Administrators need to validate.")

View File

@ -5,7 +5,6 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 19.08.22
"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.gis.geos import MultiPolygon
from django.http import HttpResponse, HttpRequest
from django.shortcuts import get_object_or_404

Binary file not shown.

View File

@ -38,13 +38,14 @@
#: konova/forms/modals/remove_form.py:23
#: konova/forms/modals/resubmission_form.py:22
#: konova/forms/modals/resubmission_form.py:38 konova/forms/remove_form.py:25
#: konova/tests/unit/test_forms.py:59 user/forms/user.py:39
#: konova/tests/unit/test_forms.py:59 user/forms/modals/api_token.py:17
#: user/forms/user.py:39
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-19 10:32+0200\n"
"POT-Creation-Date: 2025-01-08 15:26+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"
@ -373,7 +374,6 @@ msgid "Identifier"
msgstr "Kennung"
#: compensation/forms/compensation.py:33 intervention/forms/intervention.py:33
#: user/forms/user.py:77
msgid "Generated automatically - not editable"
msgstr "Automatisch generiert - nicht bearbeitbar"
@ -1795,8 +1795,7 @@ msgstr "Bearbeitender Nutzer"
msgid ""
"Search for entries where this person has been participated according to log "
"history"
msgstr ""
"Sucht nach Einträgen, an denen diese Person gearbeitet hat"
msgstr "Sucht nach Einträgen, an denen diese Person gearbeitet hat"
#: konova/forms/base_form.py:23 templates/form/collapsable/form.html:62
msgid "Save"
@ -1858,6 +1857,7 @@ msgstr ""
"Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen."
#: konova/forms/modals/remove_form.py:22 konova/forms/remove_form.py:24
#: user/forms/modals/api_token.py:16
msgid "Confirm"
msgstr "Bestätige"
@ -2283,6 +2283,10 @@ msgstr ""
msgid "Current data not checked yet"
msgstr "Momentane Daten noch nicht geprüft"
#: konova/utils/message_templates.py:96
msgid "New token generated. Administrators need to validate."
msgstr "Neuer Token generiert. Administratoren sind informiert."
#: konova/utils/messenger.py:70
msgid "{} checked"
msgstr "{} geprüft"
@ -2321,7 +2325,7 @@ msgstr "Home"
msgid "Log"
msgstr "Log"
#: konova/views/map_proxy.py:70
#: konova/views/map_proxy.py:84
msgid ""
"The external service is currently unavailable.<br>Please try again in a few "
"moments..."
@ -2831,10 +2835,8 @@ msgid "Reports"
msgstr "Berichte"
#: templates/navbars/navbar.html:57
#, fuzzy
#| msgid "Admins"
msgid "Admin"
msgstr "Administratoren"
msgstr ""
#: templates/navbars/navbar.html:59 user/templates/user/index.html:31
msgid "Settings"
@ -2873,6 +2875,21 @@ msgstr ""
"Falls die Geometrie nicht leer ist, werden die Flurstücke aktuell berechnet. "
"Bitte laden Sie diese Seite in ein paar Augenblicken erneut..."
#: user/forms/modals/api_token.py:25
msgid "Generate API Token"
msgstr "API Token generieren"
#: user/forms/modals/api_token.py:29
msgid ""
"You are about to create a new API token. The existing one will not be usable "
"afterwards."
msgstr ""
"Wenn Sie fortfahren, generieren Sie einen neuen API Token. Ihren existierenden werden Sie dann nicht länger nutzen können."
#: user/forms/modals/api_token.py:31
msgid "A new token needs to be validated by an administrator!"
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
#: user/forms/modals/team.py:20 user/forms/modals/team.py:24
#: user/forms/team.py:17 user/forms/team.py:22
msgid "Team name"
@ -2895,11 +2912,11 @@ msgstr ""
"Mehrfachauswahl möglich - Sie können nur Nutzer wählen, die noch nicht "
"Mitglieder dieses Teams sind. Geben Sie den ganzen Nutzernamen an."
#: user/forms/modals/team.py:56 user/tests/unit/test_forms.py:31
#: user/forms/modals/team.py:56 user/tests/unit/test_forms.py:29
msgid "Create new team"
msgstr "Neues Team anlegen"
#: user/forms/modals/team.py:57 user/tests/unit/test_forms.py:32
#: user/forms/modals/team.py:57 user/tests/unit/test_forms.py:30
msgid ""
"You will become the administrator for this group by default. You do not need "
"to add yourself to the list of members."
@ -2928,11 +2945,11 @@ msgid "There must be at least one admin on this team."
msgstr "Es muss mindestens einen Administrator für das Team geben."
#: user/forms/modals/team.py:160 user/templates/user/team/index.html:60
#: user/tests/unit/test_forms.py:88
#: user/tests/unit/test_forms.py:86
msgid "Edit team"
msgstr "Team bearbeiten"
#: user/forms/modals/team.py:187 user/tests/unit/test_forms.py:165
#: user/forms/modals/team.py:187 user/tests/unit/test_forms.py:163
msgid ""
"ATTENTION!\n"
"\n"
@ -2949,7 +2966,7 @@ msgstr ""
"Sind Sie sicher, dass Sie dieses Team löschen möchten?"
#: user/forms/modals/team.py:197 user/templates/user/team/index.html:56
#: user/tests/unit/test_forms.py:198
#: user/tests/unit/test_forms.py:196
msgid "Leave team"
msgstr "Team verlassen"
@ -2981,22 +2998,10 @@ msgstr "Benachrichtigungen"
msgid "Select the situations when you want to receive a notification"
msgstr "Wann wollen Sie per E-Mail benachrichtigt werden?"
#: user/forms/user.py:38 user/tests/unit/test_forms.py:234
#: user/forms/user.py:38 user/tests/unit/test_forms.py:232
msgid "Edit notifications"
msgstr "Benachrichtigungen bearbeiten"
#: user/forms/user.py:73
msgid "Token"
msgstr ""
#: user/forms/user.py:88 user/tests/unit/test_forms.py:260
msgid "Create new token"
msgstr "Neuen Token generieren"
#: user/forms/user.py:89 user/tests/unit/test_forms.py:261
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:23
msgid "Unrecorded"
msgstr "Entzeichnet"
@ -3051,7 +3056,7 @@ msgid "Manage teams"
msgstr ""
#: user/templates/user/index.html:53 user/templates/user/team/index.html:19
#: user/views/views.py:171
#: user/views/views.py:135
msgid "Teams"
msgstr ""
@ -3087,270 +3092,58 @@ msgstr "API Einstellungen"
msgid "Current token"
msgstr "Aktueller Token"
#: user/templates/user/token.html:14
#: user/templates/user/token.html:15
msgid "Create new token"
msgstr "Neuen Token generieren"
#: user/templates/user/token.html:23
msgid "Authenticated by admins"
msgstr "Von Admin freigeschaltet"
#: user/templates/user/token.html:18
#: user/templates/user/token.html:27
msgid "Token has been verified and can be used"
msgstr "Token wurde freigeschaltet und kann verwendet werden"
#: user/templates/user/token.html:20
#: user/templates/user/token.html:29
msgid "Token waiting for verification"
msgstr "Token noch nicht freigeschaltet"
#: user/templates/user/token.html:24
#: user/templates/user/token.html:33
msgid "Valid until"
msgstr "Läuft ab am"
#: user/views/views.py:35
msgid "User settings"
msgstr "Einstellungen"
#: user/views/views.py:61
msgid "Notifications edited"
msgstr "Benachrichtigungen bearbeitet"
#: user/views/views.py:73
msgid "User notifications"
msgstr "Benachrichtigungen"
#: user/views/views.py:96
msgid "New token generated. Administrators need to validate."
msgstr "Neuer Token generiert. Administratoren sind informiert."
#: user/views/views.py:107
#: user/views/api_token.py:33
msgid "User API token"
msgstr "API Nutzer Token"
#: user/views/views.py:183
#: user/views/views.py:33
msgid "User settings"
msgstr "Einstellungen"
#: user/views/views.py:59
msgid "Notifications edited"
msgstr "Benachrichtigungen bearbeitet"
#: user/views/views.py:71
msgid "User notifications"
msgstr "Benachrichtigungen"
#: user/views/views.py:147
msgid "New team added"
msgstr "Neues Team hinzugefügt"
#: user/views/views.py:198
#: user/views/views.py:162
msgid "Team edited"
msgstr "Team bearbeitet"
#: user/views/views.py:213
#: user/views/views.py:177
msgid "Team removed"
msgstr "Team gelöscht"
#: user/views/views.py:228
#: user/views/views.py:192
msgid "You are not a member of this team"
msgstr "Sie sind kein Mitglied dieses Teams"
#: user/views/views.py:235
#: user/views/views.py:199
msgid "Left Team"
msgstr "Team verlassen"
#~ msgid "close"
#~ msgstr "Schließen"
#~ msgid "Options"
#~ msgstr "Optionen"
#~ msgid "Commands"
#~ msgstr "Befehle"
#~ msgid "Missing command."
#~ msgstr "Befehl fehlt"
#~ msgid "Missing argument"
#~ msgstr "Argument fehlt"
#~ msgid "Missing option"
#~ msgstr "Option fehlt"
#~ msgid "Missing parameter"
#~ msgstr "Parameter fehlt"
#~ msgid "Messages"
#~ msgstr "Nachrichten"
#~ msgid "This field is required."
#~ msgstr "Pflichtfeld"
#~ msgid "Monday"
#~ msgstr "Montag"
#~ msgid "Tuesday"
#~ msgstr "Dienstag"
#~ msgid "Wednesday"
#~ msgstr "Mittwoch"
#~ msgid "Thursday"
#~ msgstr "Donnerstag"
#~ msgid "Friday"
#~ msgstr "Freitag"
#~ msgid "Saturday"
#~ msgstr "Samstag"
#~ msgid "Sunday"
#~ msgstr "Sonntag"
#~ msgid "Mon"
#~ msgstr "Mo"
#~ msgid "Tue"
#~ msgstr "Di"
#~ msgid "Wed"
#~ msgstr "Mi"
#~ msgid "Thu"
#~ msgstr "Do"
#~ msgid "Fri"
#~ msgstr "Fr"
#~ msgid "Sat"
#~ msgstr "Sa"
#~ msgid "Sun"
#~ msgstr "So"
#~ msgid "January"
#~ msgstr "Januar"
#~ msgid "February"
#~ msgstr "Februar"
#~ msgid "March"
#~ msgstr "März"
#~ msgid "May"
#~ msgstr "Mai"
#~ msgid "June"
#~ msgstr "Juni"
#~ msgid "July"
#~ msgstr "Juli"
#~ msgid "October"
#~ msgstr "Oktober"
#~ msgid "December"
#~ msgstr "Dezember"
#~ msgid "mar"
#~ msgstr "mär"
#~ msgid "may"
#~ msgstr "mai"
#~ msgid "oct"
#~ msgstr "okt"
#~ msgid "dec"
#~ msgstr "dez"
#~ msgctxt "abbrev. month"
#~ msgid "March"
#~ msgstr "Mär"
#~ msgctxt "abbrev. month"
#~ msgid "May"
#~ msgstr "Mai"
#~ msgctxt "abbrev. month"
#~ msgid "June"
#~ msgstr "Juni"
#~ msgctxt "abbrev. month"
#~ msgid "July"
#~ msgstr "Juli"
#~ msgctxt "abbrev. month"
#~ msgid "Oct."
#~ msgstr "Okt."
#~ msgctxt "abbrev. month"
#~ msgid "Dec."
#~ msgstr "Dez."
#~ msgctxt "alt. month"
#~ msgid "January"
#~ msgstr "Januar"
#~ msgctxt "alt. month"
#~ msgid "February"
#~ msgstr "Februar"
#~ msgctxt "alt. month"
#~ msgid "March"
#~ msgstr "März"
#~ msgctxt "alt. month"
#~ msgid "May"
#~ msgstr "Mai"
#~ msgctxt "alt. month"
#~ msgid "June"
#~ msgstr "Juni"
#~ msgctxt "alt. month"
#~ msgid "July"
#~ msgstr "Juli"
#~ msgctxt "alt. month"
#~ msgid "October"
#~ msgstr "Oktober"
#~ msgctxt "alt. month"
#~ msgid "December"
#~ msgstr "Dezember"
#~ msgid "or"
#~ msgstr "oder"
#~ msgid ""
#~ "Deductable surface can not be larger than existing surfaces in after "
#~ "states"
#~ msgstr ""
#~ "Die abbuchbare Fläche darf die Gesamtfläche der Zielzustände nicht "
#~ "überschreiten"
#~ msgid ""
#~ "Deductable surface can not be smaller than the sum of already existing "
#~ "deductions. Please contact the responsible users for the deductions!"
#~ msgstr ""
#~ "Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar "
#~ "einstellen wollen. Kontaktieren Sie die für die Abbuchungen "
#~ "verantwortlichen Nutzer!"
#~ msgid "Added deadline"
#~ msgstr "Frist/Termin hinzugefügt"
#~ msgid "Change default configuration for your KSP map"
#~ msgstr "Karteneinstellungen ändern"
#~ msgid "Map settings"
#~ msgstr "Karte"
#~ msgid "There are errors on this intervention:"
#~ msgstr "Es liegen Fehler in diesem Eingriff vor:"
#~ msgid "Before"
#~ msgstr "Vor"
#~ msgid "Groups"
#~ msgstr "Gruppen"
#~ msgid "Show more..."
#~ msgstr "Mehr anzeigen..."
#~ msgid "Kreis"
#~ msgstr "Kreis"
#~ msgid "Gemarkung"
#~ msgstr "Gemarkung"
#~ msgid "Loading..."
#~ msgstr "Lade..."
#~ msgid "Who handles the eco-account"
#~ msgstr "Wer für die Herrichtung des Ökokontos verantwortlich ist"

View File

@ -0,0 +1,49 @@
"""
Author: Michel Peltriaux
Created on: 08.01.25
"""
from django import forms
from django.utils.translation import gettext_lazy as _
from api.models import APIUserToken
from konova.forms.modals import BaseModalForm
from konova.utils.mailer import Mailer
class NewAPITokenModalForm(BaseModalForm):
confirm = forms.BooleanField(
label=_("Confirm"),
label_suffix=_(""),
widget=forms.CheckboxInput(),
required=True,
)
def __init__(self, *args, **kwargs):
self.template = "modal/modal_form.html"
super().__init__(*args, **kwargs)
self.form_title = _("Generate API Token")
self.form_caption = ""
if self.__user_has_api_token():
self.form_caption = _("You are about to create a new API token. The existing one will not be usable afterwards.")
self.form_caption += "\n"
self.form_caption += _("A new token needs to be validated by an administrator!")
# Disable automatic w-100 setting for this type of modal form. Looks kinda strange
self.fields["confirm"].widget.attrs["class"] = ""
def __user_has_api_token(self):
return self.instance.api_token is not None
def save(self):
user = self.instance
if user.api_token is not None:
user.api_token.delete()
user.api_token = APIUserToken.objects.create()
user.save()
mailer = Mailer()
mailer.send_mail_verify_api_token(user)
return user.api_token

View File

@ -66,48 +66,3 @@ class UserNotificationForm(BaseForm):
id__in=selected_notification_ids,
)
self.user.notifications.set(notifications)
class UserAPITokenForm(BaseForm):
token = forms.CharField(
label=_("Token"),
label_suffix="",
max_length=255,
required=True,
help_text=_("Generated automatically - not editable"),
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"]
if user.api_token is not None:
user.api_token.delete()
new_token = APIUserToken.objects.create(
token=new_token
)
user.api_token = new_token
user.save()
return new_token

View File

@ -8,7 +8,16 @@
<table class="table table-hover">
<tr>
<th scope="row">{% trans 'Current token' %}</th>
<td>{{ user.api_token.token }}</td>
<td>
<div class="row">
<div class="col-10">{{ user.api_token.token }}</div>
<div class="col-2">
<button class="btn btn-default btn-modal" data-form-url="{% url 'user:api-token-new' %}" title="{% trans 'Create new token' %}">
{% fa5_icon 'dice' %}
</button>
</div>
</div>
</td>
</tr>
<tr>
<th scope="row">{% trans 'Authenticated by admins' %}</th>
@ -27,7 +36,9 @@
</table>
</div>
</div>
<hr>
{% include 'form/table/generic_table_form.html' %}
{% with 'btn-modal' as btn_class %}
{% include 'modal/modal_form_script.html' %}
{% endwith %}
{% endblock %}

View File

@ -5,15 +5,14 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 12.09.23
"""
from django.core.exceptions import ObjectDoesNotExist
from django.test import RequestFactory
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from api.models import APIUserToken
from konova.tests.test_views import BaseTestCase
from user.forms.modals.api_token import NewAPITokenModalForm
from user.forms.modals.team import NewTeamModalForm, EditTeamModalForm, RemoveTeamModalForm, LeaveTeamModalForm
from user.forms.user import UserNotificationForm, UserAPITokenForm
from user.forms.user import UserNotificationForm
from user.models import Team, UserAction, UserNotification
@ -252,35 +251,28 @@ class UserNotificationFormTestCase(BaseTestCase):
self.assertIn(selected_notification, self.user.notifications.all())
class UserAPITokenFormTestCase(BaseTestCase):
def test_init(self):
form = UserAPITokenForm(
instance=self.user
)
self.assertEqual(form.form_title, str(_("Create new token")))
self.assertEqual(form.form_caption, str(_("A new token needs to be validated by an administrator!")))
self.assertEqual(form.action_url, reverse("user:api-token"))
self.assertEqual(form.cancel_redirect, reverse("user:index"))
self.assertIsNone(form.fields["token"].initial)
self.assertTrue(form.fields["token"].widget.attrs["readonly"])
def test_save(self):
data = {
"token": APIUserToken().token
class ApiTokenFormTestCase(BaseTestCase):
def test_new_token_and_recreating_token(self):
request = RequestFactory().request()
request.user = self.user
request.POST = {
"confirm": True
}
form = UserAPITokenForm(
data,
instance=self.user
)
self.assertTrue(form.is_valid(), msg=form.errors)
self.assertIsNone(self.user.api_token)
token = form.save()
self.assertEqual(self.user.api_token, token)
new_token = form.save()
self.assertEqual(self.user.api_token, new_token)
try:
token.refresh_from_db()
self.fail("Token should be deleted and not be fetchable anymore")
except ObjectDoesNotExist:
pass
form = NewAPITokenModalForm(request.POST, instance=self.user)
form.save()
self.user.refresh_from_db()
token = self.user.api_token
self.assertFalse(token.is_active)
self.assertIsNone(token.valid_until)
self.assertIsNotNone(token.token)
old_token = token.token
form.save()
self.user.refresh_from_db()
new_token = self.user.api_token
self.assertNotEqual(new_token.token, old_token)
self.assertFalse(new_token.is_active)
self.assertIsNone(new_token.valid_until)

View File

@ -9,6 +9,7 @@ from django.urls import path
from user.autocomplete.share import ShareUserAutocomplete, ShareTeamAutocomplete
from user.autocomplete.team import TeamAdminAutocomplete
from user.views.api_token import APITokenView, new_api_token_view
from user.views.propagate import PropagateUserView
from user.views.views import *
@ -17,7 +18,8 @@ urlpatterns = [
path("", index_view, name="index"),
path("propagate/", PropagateUserView.as_view(), name="propagate"),
path("notifications/", notifications_view, name="notifications"),
path("token/api", api_token_view, name="api-token"),
path("token/api", APITokenView.as_view(), name="api-token"),
path("token/api/new", new_api_token_view, name="api-token-new"),
path("contact/<id>", contact_view, name="contact"),
path("team/", index_team_view, name="team-index"),
path("team/new", new_team_view, name="team-new"),
@ -30,4 +32,4 @@ urlpatterns = [
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
path("atcmplt/share/t", ShareTeamAutocomplete.as_view(), name="share-team-autocomplete"),
path("atcmplt/team/admin", TeamAdminAutocomplete.as_view(), name="team-admin-autocomplete"),
]
]

57
user/views/api_token.py Normal file
View File

@ -0,0 +1,57 @@
"""
Author: Michel Peltriaux
Created on: 08.01.25
"""
from django.contrib.auth.decorators import login_required
from django.http import HttpRequest
from django.shortcuts import render
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views import View
from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext
from konova.decorators import default_group_required
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import NEW_API_TOKEN_GENERATED
from user.forms.modals.api_token import NewAPITokenModalForm
class APITokenView(View):
@method_decorator(login_required)
@method_decorator(default_group_required)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request: HttpRequest):
template = "user/token.html"
user = request.user
context = {
"user": user,
TAB_TITLE_IDENTIFIER: _("User API token"),
}
context = BaseContext(request, context).context
return render(request, template, context)
def new_api_token_view(request: HttpRequest):
""" Function based view for processing ModalForm
(Currently ModalForms only work properly with function based views)
Args:
request ():
Returns:
"""
user = request.user
form = NewAPITokenModalForm(request.POST or None, instance=user, request=request)
return form.process_request(
request=request,
msg_success=NEW_API_TOKEN_GENERATED,
redirect_url=reverse("user:api-token"),
)

View File

@ -3,19 +3,17 @@ from django.contrib.auth.decorators import login_required
from django.urls import reverse
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.mailer import Mailer
from konova.utils.message_templates import FORM_INVALID
from user.forms.modals.team import NewTeamModalForm, EditTeamModalForm, RemoveTeamModalForm, LeaveTeamModalForm
from user.forms.modals.user import UserContactForm
from user.forms.team import TeamDataForm
from user.forms.user import UserNotificationForm, UserAPITokenForm
from user.forms.user import UserNotificationForm
from user.models import User, Team
from django.http import HttpRequest, Http404
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, default_group_required, login_required_modal
from konova.decorators import any_group_check, login_required_modal
@login_required
@ -76,40 +74,6 @@ 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"
user = request.user
form = UserAPITokenForm(request.POST or None, instance=user)
if request.method == "POST":
if form.is_valid():
token = form.save()
messages.info(request, _("New token generated. Administrators need to validate."))
mailer = Mailer()
mailer.send_mail_verify_api_token(user)
return redirect("user:api-token")
else:
messages.error(request, FORM_INVALID, extra_tags="danger")
elif request.method != "GET":
raise NotImplementedError
context = {
"user": user,
"form": form,
TAB_TITLE_IDENTIFIER: _("User API token"),
}
context = BaseContext(request, context).context
return render(request, template, context)
@login_required_modal
@login_required
def contact_view(request: HttpRequest, id: str):