mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Finished user control panel for tokens
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm
|
||||
from django import forms
|
||||
|
||||
from utilities.forms import BootstrapMixin
|
||||
from .models import Token
|
||||
|
||||
|
||||
class LoginForm(BootstrapMixin, AuthenticationForm):
|
||||
@@ -14,3 +16,14 @@ class LoginForm(BootstrapMixin, AuthenticationForm):
|
||||
|
||||
class PasswordChangeForm(BootstrapMixin, DjangoPasswordChangeForm):
|
||||
pass
|
||||
|
||||
|
||||
class TokenForm(BootstrapMixin, forms.ModelForm):
|
||||
key = forms.CharField(required=False, help_text="If no key is provided, one will be generated automatically.")
|
||||
|
||||
class Meta:
|
||||
model = Token
|
||||
fields = ['key', 'write_enabled', 'expires', 'description']
|
||||
help_texts = {
|
||||
'expires': 'YYYY-MM-DD [HH:MM:SS]'
|
||||
}
|
||||
|
@@ -1,8 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.6 on 2017-03-08 03:52
|
||||
# Generated by Django 1.10.6 on 2017-03-08 15:32
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
@@ -22,7 +23,7 @@ class Migration(migrations.Migration):
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('expires', models.DateTimeField(blank=True, null=True)),
|
||||
('key', models.CharField(max_length=40, unique=True)),
|
||||
('key', models.CharField(max_length=40, unique=True, validators=[django.core.validators.MinLengthValidator(40)])),
|
||||
('write_enabled', models.BooleanField(default=True, help_text=b'Permit create/update/delete operations using this key')),
|
||||
('description', models.CharField(blank=True, max_length=100)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tokens', to=settings.AUTH_USER_MODEL)),
|
||||
|
@@ -2,6 +2,7 @@ import binascii
|
||||
import os
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.validators import MinLengthValidator
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils import timezone
|
||||
@@ -16,7 +17,7 @@ class Token(models.Model):
|
||||
user = models.ForeignKey(User, related_name='tokens', on_delete=models.CASCADE)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
expires = models.DateTimeField(blank=True, null=True)
|
||||
key = models.CharField(max_length=40, unique=True)
|
||||
key = models.CharField(max_length=40, unique=True, validators=[MinLengthValidator(40)])
|
||||
write_enabled = models.BooleanField(default=True, help_text="Permit create/update/delete operations using this key")
|
||||
description = models.CharField(max_length=100, blank=True)
|
||||
|
||||
@@ -24,7 +25,8 @@ class Token(models.Model):
|
||||
default_permissions = []
|
||||
|
||||
def __str__(self):
|
||||
return u"API key for {}".format(self.user)
|
||||
# Only display the last 24 bits of the token to avoid accidental exposure.
|
||||
return u"{} ({})".format(self.key[-6:], self.user)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.key:
|
||||
|
@@ -8,7 +8,10 @@ urlpatterns = [
|
||||
# User profiles
|
||||
url(r'^profile/$', views.profile, name='profile'),
|
||||
url(r'^profile/password/$', views.change_password, name='change_password'),
|
||||
url(r'^profile/api-tokens/$', views.TokenList.as_view(), name='api_tokens'),
|
||||
url(r'^profile/api-tokens/$', views.TokenListView.as_view(), name='token_list'),
|
||||
url(r'^profile/api-tokens/add/$', views.TokenEditView.as_view(), name='token_add'),
|
||||
url(r'^profile/api-tokens/(?P<pk>\d+)/edit/$', views.TokenEditView.as_view(), name='token_edit'),
|
||||
url(r'^profile/api-tokens/(?P<pk>\d+)/delete/$', views.TokenDeleteView.as_view(), name='token_delete'),
|
||||
url(r'^profile/user-key/$', views.userkey, name='userkey'),
|
||||
url(r'^profile/user-key/edit/$', views.userkey_edit, name='userkey_edit'),
|
||||
url(r'^profile/recent-activity/$', views.recent_activity, name='recent_activity'),
|
||||
|
@@ -4,13 +4,14 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.http import is_safe_url
|
||||
from django.views.generic import View
|
||||
|
||||
from secrets.forms import UserKeyForm
|
||||
from secrets.models import UserKey
|
||||
from .forms import LoginForm, PasswordChangeForm
|
||||
from utilities.forms import ConfirmationForm
|
||||
from .forms import LoginForm, PasswordChangeForm, TokenForm
|
||||
from .models import Token
|
||||
|
||||
|
||||
@@ -136,7 +137,7 @@ def recent_activity(request):
|
||||
# API tokens
|
||||
#
|
||||
|
||||
class TokenList(LoginRequiredMixin, View):
|
||||
class TokenListView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
|
||||
@@ -146,3 +147,74 @@ class TokenList(LoginRequiredMixin, View):
|
||||
'tokens': tokens,
|
||||
'active_tab': 'api_tokens',
|
||||
})
|
||||
|
||||
|
||||
class TokenEditView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request, pk=None):
|
||||
|
||||
if pk is not None:
|
||||
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
|
||||
else:
|
||||
token = Token(user=request.user)
|
||||
|
||||
form = TokenForm(instance=token)
|
||||
|
||||
return render(request, 'utilities/obj_edit.html', {
|
||||
'obj': token,
|
||||
'obj_type': token._meta.verbose_name,
|
||||
'form': form,
|
||||
'return_url': reverse('users:token_list'),
|
||||
})
|
||||
|
||||
def post(self, request, pk=None):
|
||||
|
||||
if pk is not None:
|
||||
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
|
||||
form = TokenForm(request.POST, instance=token)
|
||||
else:
|
||||
form = TokenForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
token = form.save(commit=False)
|
||||
token.user = request.user
|
||||
token.save()
|
||||
|
||||
msg = "Token updated" if pk else "New token created"
|
||||
messages.success(request, msg)
|
||||
|
||||
return redirect('users:token_list')
|
||||
|
||||
|
||||
class TokenDeleteView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request, pk):
|
||||
|
||||
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
|
||||
initial_data = {
|
||||
'return_url': reverse('users:token_list'),
|
||||
}
|
||||
form = ConfirmationForm(initial=initial_data)
|
||||
|
||||
return render(request, 'utilities/obj_delete.html', {
|
||||
'obj': token,
|
||||
'obj_type': token._meta.verbose_name,
|
||||
'form': form,
|
||||
'return_url': reverse('users:token_list'),
|
||||
})
|
||||
|
||||
def post(self, request, pk):
|
||||
|
||||
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
|
||||
form = ConfirmationForm(request.POST)
|
||||
if form.is_valid():
|
||||
token.delete()
|
||||
messages.success(request, "Token deleted")
|
||||
return redirect('users:token_list')
|
||||
|
||||
return render(request, 'utilities/obj_delete.html', {
|
||||
'obj': token,
|
||||
'obj_type': token._meta.verbose_name,
|
||||
'form': form,
|
||||
'return_url': reverse('users:token_list'),
|
||||
})
|
||||
|
Reference in New Issue
Block a user