progress on form
parent
f1fc5f4cb8
commit
2d8abd3577
|
@ -0,0 +1,98 @@
|
||||||
|
from random import shuffle
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.forms import Form, CharField, EmailField, Textarea, ChoiceField, BooleanField
|
||||||
|
import sshpubkeys as ssh
|
||||||
|
|
||||||
|
from .models import SSH_TYPE_CHOICES
|
||||||
|
|
||||||
|
USERNAME_RE = re.compile(r'[a-z][a-z0-9_]+')
|
||||||
|
USERNAME_MIN_LENGTH = 4
|
||||||
|
DISPLAY_NAME_RE = re.compile(r"[a-zA-Z0-9_\-']+")
|
||||||
|
DISPLAY_MIN_LENGTH = 2
|
||||||
|
|
||||||
|
# >_>
|
||||||
|
CAPTCHA_CHOICES = [('two', 'zorp borp'),
|
||||||
|
('three', 'quop bop'),
|
||||||
|
('four', 'NO, I AM NOT A ROBOT'),
|
||||||
|
('five', 'crackle zop'),
|
||||||
|
('six', '*rusty screech*'),
|
||||||
|
('seven', 'mother, give me legs')]
|
||||||
|
shuffle(CAPTCHA_CHOICES)
|
||||||
|
CAPTCHA_CHOICES.insert(0, ('one', 'beep boop'),)
|
||||||
|
NOT_A_ROBOT = 'four'
|
||||||
|
# <_<
|
||||||
|
|
||||||
|
def validate_username(username):
|
||||||
|
if len(username) < USERNAME_MIN_LENGTH:
|
||||||
|
raise ValidationError('Username too short.')
|
||||||
|
if not USERNAME_RE.match(username):
|
||||||
|
raise ValidationError('Username must be all lowercase, start with a letter, and only use the _ special charcter')
|
||||||
|
|
||||||
|
def validate_displayname(display_name):
|
||||||
|
if len(display_name) < DISPLAY_MIN_LENGTH:
|
||||||
|
raise ValidationError('Display name too short.')
|
||||||
|
if not DISPLAY_NAME_RE.match(display_name):
|
||||||
|
raise ValidationError("Valid characters: a-z, A-Z, 0-9, -, _, and '.")
|
||||||
|
|
||||||
|
def validate_pubkey(pubkey):
|
||||||
|
key = ssh.SSHKey(pubkey, strict_mode=False, skip_option_parsing=True)
|
||||||
|
try:
|
||||||
|
key.parse()
|
||||||
|
except ssh.InvalidKeyException as e:
|
||||||
|
raise ValidationError('Could not validate key: {}'.format(e))
|
||||||
|
except NotImplementedError as e:
|
||||||
|
raise ValidationError('Invalid key type')
|
||||||
|
except Exception as e:
|
||||||
|
raise ValidationError('unknown error: {}'.format(e))
|
||||||
|
|
||||||
|
def validate_captcha(captcha):
|
||||||
|
if captcha != NOT_A_ROBOT:
|
||||||
|
raise ValidationError('Are you sure you are not a robot?')
|
||||||
|
|
||||||
|
|
||||||
|
class TownieForm(Form):
|
||||||
|
username = CharField(
|
||||||
|
validators=(validate_username,),
|
||||||
|
help_text='lowercase and no spaces. underscore ok',
|
||||||
|
label='username')
|
||||||
|
email = EmailField(
|
||||||
|
help_text='only used to message you about your account and nothing else.',
|
||||||
|
label='e-mail')
|
||||||
|
displayname = CharField(
|
||||||
|
validators=(validate_displayname,),
|
||||||
|
help_text='100% optional. pseudonyms welcome.',
|
||||||
|
label='display name',
|
||||||
|
required=False)
|
||||||
|
reasons = CharField(
|
||||||
|
widget=Textarea,
|
||||||
|
required=False,
|
||||||
|
label='what interests you about tilde.town?',
|
||||||
|
help_text='This is a totally optional place for you to tell us what excites you about getting a ~ account. This is mainly just so we can all feel warm fuzzies.')
|
||||||
|
captcha = ChoiceField(
|
||||||
|
choices=CAPTCHA_CHOICES,
|
||||||
|
label='are you a robot?',
|
||||||
|
help_text='pick the response that indicates whether or not you are a robot.',
|
||||||
|
validators=(validate_captcha,)
|
||||||
|
)
|
||||||
|
pubkey = CharField(
|
||||||
|
widget=Textarea,
|
||||||
|
validators=(validate_pubkey,),
|
||||||
|
label='SSH public key',
|
||||||
|
help_text='if this is not a thing you are familiar with, that\'s okay! check out <a href="https://tilde.town/~wiki/ssh.html">our guide</a> to learn how to get one of these.')
|
||||||
|
pubkey_type = ChoiceField(
|
||||||
|
choices=SSH_TYPE_CHOICES,
|
||||||
|
label='SSH public key type',
|
||||||
|
help_text="unless you know what you're doing you can leave this be.")
|
||||||
|
aup = BooleanField(
|
||||||
|
label='i super agree to our acceptable use policy',
|
||||||
|
help_text='please read our <a href="https://tilde.town/~wiki/conduct.html">code of conduct</a> and click this box if you agree.')
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
result = super().clean()
|
||||||
|
if self.errors:
|
||||||
|
raise ValidationError('oops, looks like there were some problems below.')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db.models import TextField, BooleanField, CharField
|
from django.db.models import TextField, BooleanField, CharField
|
||||||
|
|
||||||
|
|
||||||
SSH_TYPE_CHOICES = (
|
SSH_TYPE_CHOICES = (
|
||||||
('ssh-rsa', 'ssh-rsa',),
|
('ssh-rsa', 'ssh-rsa',),
|
||||||
('ssh-dss', 'ssh-dss',),
|
('ssh-dss', 'ssh-dss',),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Townie(User):
|
class Townie(User):
|
||||||
"""Both an almost normal Django User as well as an abstraction over a
|
"""Both an almost normal Django User as well as an abstraction over a
|
||||||
system user."""
|
system user."""
|
||||||
pubkey = TextField(blank=False, null=False)
|
pubkey = TextField(blank=False, null=False)
|
||||||
shell = CharField(max_length=50, default="/bin/bash")
|
shell = CharField(max_length=50, default="/bin/bash")
|
||||||
reviewed = BooleanField(default=False)
|
reviewed = BooleanField(default=False)
|
||||||
|
reasons = TextField(blank=True, null=False, default='')
|
||||||
displayname = CharField(max_length=100, blank=False, null=False)
|
displayname = CharField(max_length=100, blank=False, null=False)
|
||||||
pubkey_type = CharField(max_length=15,
|
pubkey_type = CharField(max_length=15,
|
||||||
blank=False,
|
blank=False,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from .views import UserSignupView
|
from .views import SignupView, ThanksView
|
||||||
|
|
||||||
app_name = 'users'
|
app_name = 'users'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^signup/?$', UserSignupView.as_view(), name='signup'),
|
url(r'^signup/?$', SignupView.as_view(), name='signup'),
|
||||||
|
url(r'^thanks/?$', ThanksView.as_view(), name='thanks'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,48 +1,37 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.forms import Form, CharField, EmailField, Textarea, ChoiceField, BooleanField
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
from django.shortcuts import redirect
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
from django.views.generic.edit import FormView
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from .models import Townie, SSH_TYPE_CHOICES
|
from .forms import TownieForm
|
||||||
|
from .models import Townie
|
||||||
|
|
||||||
# TODO validation functions for final request validation and live js validation
|
class SignupView(FormView):
|
||||||
# I refuse to duplicate the logic for validation on the front-end and am going
|
form_class = TownieForm
|
||||||
# to accept round-trip validation costs with long-term caching.
|
template_name = 'users/signup.html'
|
||||||
|
# TODO reverse
|
||||||
|
success_url = '/thanks'
|
||||||
|
|
||||||
class UserSignupView(TemplateView):
|
def form_valid(self, form):
|
||||||
template_name = 'ttadmin/signup.html'
|
|
||||||
|
|
||||||
def get_context_data(self):
|
#t = Townie(
|
||||||
ctx = super().get_context_data()
|
# username=username,
|
||||||
ctx['ssh_type_choices'] = SSH_TYPE_CHOICES
|
# displayname=displayname,
|
||||||
return ctx
|
# pubkey=pubkey,
|
||||||
|
# email=email,
|
||||||
|
#)
|
||||||
|
|
||||||
def post(self, request):
|
#t.set_unusable_password()
|
||||||
print(request.POST)
|
#t.save()
|
||||||
# TODO validate
|
|
||||||
username = request.POST.get('username')
|
|
||||||
|
|
||||||
displayname = request.POST.get('displayname')
|
return super().form_valid(form)
|
||||||
|
|
||||||
if displayname is None:
|
|
||||||
displayname = username
|
|
||||||
else:
|
|
||||||
# TODO validate
|
|
||||||
pass
|
|
||||||
|
|
||||||
# TODO validate
|
|
||||||
pubkey = request.POST.get('pubkey')
|
|
||||||
|
|
||||||
# TODO validate
|
|
||||||
email = request.POST.get('email')
|
|
||||||
|
|
||||||
t = Townie(
|
|
||||||
username=username,
|
|
||||||
displayname=displayname,
|
|
||||||
pubkey=pubkey,
|
|
||||||
email=email,
|
|
||||||
)
|
|
||||||
|
|
||||||
t.set_unusable_password()
|
|
||||||
t.save()
|
|
||||||
|
|
||||||
|
|
||||||
return HttpResponse('LOLOLOLOL')
|
# TODO add template for this once i've fixed template directories
|
||||||
|
class ThanksView(TemplateView):
|
||||||
|
template_name = 'users/thanks.html'
|
||||||
|
|
Loading…
Reference in New Issue