From 0080fe7e787fff4abcc1fe2b60902c2d475aa59e Mon Sep 17 00:00:00 2001
From: Jan Dittberner <jan@dittberner.info>
Date: Sat, 31 Jan 2015 22:26:17 +0100
Subject: [PATCH] add administration form and admin class for SshPublicKey

---
 gnuviechadmin/osusers/admin.py | 98 +++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/gnuviechadmin/osusers/admin.py b/gnuviechadmin/osusers/admin.py
index 6fec6e7..2befe02 100644
--- a/gnuviechadmin/osusers/admin.py
+++ b/gnuviechadmin/osusers/admin.py
@@ -3,7 +3,7 @@ This module contains the Django admin classes of the :py:mod:`osusers` app.
 
 """
 from django import forms
-from django.utils.translation import ugettext as _
+from django.utils.translation import ugettext_lazy as _
 from django.contrib import admin
 
 from gvawebcore.forms import (
@@ -13,9 +13,14 @@ from .models import (
     AdditionalGroup,
     Group,
     Shadow,
+    SshPublicKey,
     User,
 )
 
+INVALID_SSH_PUBLIC_KEY = _('Invalid SSH public key data format.')
+DUPLICATE_SSH_PUBLIC_KEY_FOR_USER = _(
+    'This SSH public key is already assigned to this user.')
+
 
 class AdditionalGroupInline(admin.TabularInline):
     """
@@ -216,5 +221,96 @@ class GroupAdmin(admin.ModelAdmin):
         return actions
 
 
+class SshPublicKeyCreationForm(forms.ModelForm):
+    """
+    A form for creating :py:class:`SSH public keys
+    <osusers.models.SshPublicKey>`.
+
+    """
+    publickeytext = forms.CharField(
+        label=_('Key text'), widget=forms.Textarea,
+        help_text=_('A SSH public key in either OpenSSH or RFC 4716 format'))
+
+    class Meta:
+        model = SshPublicKey
+        fields = ['user']
+
+    def clean_publickeytext(self):
+        keytext = self.cleaned_data.get('publickeytext')
+        try:
+            SshPublicKey.objects.parse_keytext(keytext)
+        except:
+            raise forms.ValidationError(INVALID_SSH_PUBLIC_KEY)
+        return keytext
+
+    def clean(self):
+        user = self.cleaned_data.get('user')
+        keytext = self.cleaned_data.get('publickeytext')
+        if user and keytext:
+            alg, data, comment = SshPublicKey.objects.parse_keytext(keytext)
+            if SshPublicKey.objects.filter(
+                user=user, algorithm=alg, data=data
+            ).exists():
+                self.add_error(
+                    'publickeytext',
+                    forms.ValidationError(DUPLICATE_SSH_PUBLIC_KEY_FOR_USER))
+
+    def save(self, commit=True):
+        """
+        Save the provided ssh public key in properly split format.
+
+        :param boolean commit: whether to save the created public key
+        :return: ssh public key instance
+        :rtype: :py:class:`osusers.models.SshPublicKey`
+
+        """
+        algorithm, keydata, comment = SshPublicKey.objects.parse_keytext(
+            self.cleaned_data.get('publickeytext'))
+        self.instance.algorithm = algorithm
+        self.instance.data = keydata
+        self.instance.comment = comment
+        return super(SshPublicKeyCreationForm, self).save(commit)
+
+
+class SshPublicKeyAdmin(admin.ModelAdmin):
+    """
+    Admin class for working with :py:class:`SSH public keys
+    <osusers.models.SshPublicKey>`.
+
+    """
+    add_form = SshPublicKeyCreationForm
+    list_display = ['user', 'algorithm', 'comment']
+
+    add_fieldsets = (
+        (None, {
+            'classes': ('wide',),
+            'fields': ('user', 'publickeytext')}),
+    )
+
+    def get_form(self, request, obj=None, **kwargs):
+        """
+        Use special form for ssh public key creation."
+
+        :param request: the current HTTP request
+        :param obj: either a :py:class:`SshPublicKey
+            <osusers.models.SshPublicKey>` instance or None for a new SSH
+            public key
+        :param kwargs: keyword arguments to be passed to
+            :py:meth:`django.contrib.admin.ModelAdmin.get_form`
+        :return: form instance
+
+        """
+        defaults = {}
+        if obj is None:
+            defaults.update({
+                'form': self.add_form,
+                'fields': admin.options.flatten_fieldsets(self.add_fieldsets),
+            })
+        defaults.update(kwargs)
+        return super(SshPublicKeyAdmin, self).get_form(
+            request, obj, **defaults)
+
+
 admin.site.register(Group, GroupAdmin)
 admin.site.register(User, UserAdmin)
+admin.site.register(SshPublicKey, SshPublicKeyAdmin)