diff --git a/README.md b/README.md index b7fdfc3..9e78093 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ _Being an adminstrative and user-signup tool for [https://tilde.town]_. ## Features - (None of these are actually implemented yet) - - * User signup form with client-side key generation - * User account management + * User signup form (✓) + * with client-side key generation (only server-side key **validation** at this point) + * Guestbook (✓) + * Helpdesk (✓) + * User account management (admin only) * Start/stop services * Cost reporting using AWS * Status monitoring diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index bbde176..186f127 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -1,6 +1,16 @@ from django.contrib import admin -from .models import Townie +from django.contrib.auth.models import User +from django.contrib.auth.models import Group + +from .models import Townie, Pubkey + +admin.site.unregister(User) +admin.site.unregister(Group) + +class PubkeyInline(admin.TabularInline): + model = Pubkey @admin.register(Townie) class TownieAdmin(admin.ModelAdmin): + inlines = [PubkeyInline] pass diff --git a/ttadmin/users/migrations/0007_auto_20170113_2126.py b/ttadmin/users/migrations/0007_auto_20170113_2126.py new file mode 100644 index 0000000..3496fb8 --- /dev/null +++ b/ttadmin/users/migrations/0007_auto_20170113_2126.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2017-01-13 21:26 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0006_townie_reasons'), + ] + + operations = [ + migrations.AlterModelOptions( + name='townie', + options={'verbose_name': 'Townie', 'verbose_name_plural': 'Townies'}, + ), + migrations.RemoveField( + model_name='townie', + name='pubkey_type', + ), + ] diff --git a/ttadmin/users/migrations/0008_auto_20170113_2128.py b/ttadmin/users/migrations/0008_auto_20170113_2128.py new file mode 100644 index 0000000..a89c52f --- /dev/null +++ b/ttadmin/users/migrations/0008_auto_20170113_2128.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2017-01-13 21:28 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0007_auto_20170113_2126'), + ] + + operations = [ + migrations.CreateModel( + name='Pubkey', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key_type', models.CharField(choices=[('ssh-rsa', 'ssh-rsa'), ('ssh-dss', 'ssh-dss')], max_length=15)), + ('key', models.TextField()), + ], + ), + migrations.RemoveField( + model_name='townie', + name='pubkey', + ), + migrations.AddField( + model_name='pubkey', + name='townie', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.Townie'), + ), + ] diff --git a/ttadmin/users/models.py b/ttadmin/users/models.py index 3613f9d..c713288 100644 --- a/ttadmin/users/models.py +++ b/ttadmin/users/models.py @@ -1,9 +1,10 @@ import re +from django.db.models import Model from django.db.models.signals import post_save from django.dispatch import receiver from django.contrib.auth.models import User -from django.db.models import TextField, BooleanField, CharField +from django.db.models import TextField, BooleanField, CharField, ForeignKey SSH_TYPE_CHOICES = ( @@ -15,24 +16,13 @@ SSH_TYPE_CHOICES = ( class Townie(User): """Both an almost normal Django User as well as an abstraction over a system user.""" - pubkey = TextField(blank=False, null=False) + class Meta: + verbose_name = 'Townie' + verbose_name_plural = 'Townies' shell = CharField(max_length=50, default="/bin/bash") reviewed = BooleanField(default=False) reasons = TextField(blank=True, null=False, default='') displayname = CharField(max_length=100, blank=False, null=False) - pubkey_type = CharField(max_length=15, - blank=False, - null=False, - choices=SSH_TYPE_CHOICES) - - @property - def home_path(self): - return "/home/{}".format(self.username) - - def accept(self): - """Sets self.pending to False. Indicates the user has been signed up - after review.""" - self.pending = False # TODO consider a generic ensure method that syncs this model with the # system. there will likely be things besides shell that we want to keep @@ -42,6 +32,17 @@ class Townie(User): is.""" raise NotImplementedError() + +class Pubkey(Model): + key_type = CharField(max_length=15, + blank=False, + null=False, + choices=SSH_TYPE_CHOICES, + ) + key = TextField(blank=False, null=False) + townie = ForeignKey(Townie) + + @receiver(post_save, sender=Townie) def sync_system_state(sender, instance, created, **kwargs): if created: diff --git a/ttadmin/users/views.py b/ttadmin/users/views.py index a0218e5..49aa79a 100644 --- a/ttadmin/users/views.py +++ b/ttadmin/users/views.py @@ -1,6 +1,7 @@ import re from django.core.exceptions import ValidationError +from django.db import transaction from django.forms import Form, CharField, EmailField, Textarea, ChoiceField, BooleanField from django.http import HttpResponse from django.shortcuts import redirect @@ -8,21 +9,24 @@ from django.views.generic import TemplateView from django.views.generic.edit import FormView from .forms import TownieForm -from .models import Townie +from .models import Townie, Pubkey class SignupView(FormView): form_class = TownieForm template_name = 'users/signup.html' + @transaction.atomic def form_valid(self, form): - del form.cleaned_data['captcha'] del form.cleaned_data['aup'] + pubkey = Pubkey(key=form.cleaned_data.pop('pubkey'), + key_type=form.cleaned_data.pop('pubkey_type')) t = Townie(**form.cleaned_data) - t.set_unusable_password() t.save() + pubkey.townie = t + pubkey.save() return redirect('users:thanks')