Allow account registration with invites.

This commit is contained in:
Adam Kelly 2020-06-01 22:34:45 +01:00
parent e0a009a0f1
commit 48f7fd34a7
8 changed files with 111 additions and 4 deletions

View file

@ -1,5 +1,5 @@
''' usin django model forms ''' ''' usin django model forms '''
from django.forms import ModelForm, PasswordInput from django.forms import ModelForm, PasswordInput, HiddenInput
from django import forms from django import forms
from fedireads import models from fedireads import models
@ -21,7 +21,7 @@ class RegisterForm(ModelForm):
fields = ['username', 'email', 'password'] fields = ['username', 'email', 'password']
help_texts = {f: None for f in fields} help_texts = {f: None for f in fields}
widgets = { widgets = {
'password': PasswordInput(), 'password': PasswordInput()
} }

View file

@ -0,0 +1,24 @@
# Generated by Django 3.0.3 on 2020-06-01 21:31
from django.db import migrations, models
import fedireads.models.site
class Migration(migrations.Migration):
dependencies = [
('fedireads', '0042_sitesettings'),
]
operations = [
migrations.CreateModel(
name='SiteInvite',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(default=fedireads.models.site.new_invite_code, max_length=32)),
('expiry', models.DateTimeField(blank=True, null=True)),
('use_limit', models.IntegerField(blank=True, null=True)),
('times_used', models.IntegerField(default=0)),
],
),
]

View file

@ -6,4 +6,4 @@ from .status import Favorite, Boost, Tag, Notification, ReadThrough
from .user import User, UserFollows, UserFollowRequest, UserBlocks from .user import User, UserFollows, UserFollowRequest, UserBlocks
from .user import FederatedServer from .user import FederatedServer
from .import_job import ImportJob, ImportItem from .import_job import ImportJob, ImportItem
from .site import SiteSettings from .site import SiteSettings, SiteInvite

View file

@ -1,4 +1,9 @@
import base64
import datetime
from Crypto import Random
from django.db import models from django.db import models
from fedireads.settings import DOMAIN from fedireads.settings import DOMAIN
class SiteSettings(models.Model): class SiteSettings(models.Model):
@ -17,3 +22,17 @@ class SiteSettings(models.Model):
default_settings = SiteSettings(id=1) default_settings = SiteSettings(id=1)
default_settings.save() default_settings.save()
return default_settings return default_settings
def new_invite_code():
return base64.b32encode(Random.get_random_bytes(5)).decode('ascii')
class SiteInvite(models.Model):
code = models.CharField(max_length=32, default=new_invite_code)
expiry = models.DateTimeField(blank=True, null=True)
use_limit = models.IntegerField(blank=True, null=True)
times_used = models.IntegerField(default=0)
def valid(self):
return (
(self.expiry is None or self.expiry > datetime.datetime.now()) and
(self.use_limit is None or self.times_used < self.use_limit))

View file

@ -0,0 +1,33 @@
{% extends 'layout.html' %}
{% block content %}
<div class="content-container">
<h2>About {{ site_settings.name }}</h2>
<p>
{{ site_settings.instance_description }}
</p>
<p>
<small>
<a href="/about/">More about this site</a>
</small>
</p>
</div>
<div class="content-container login">
<h2>Create an Account</h2>
<p><small>
With a BookWyrm account, you can track and share your reading activity with
friends here and on any other federated server, like Mastodon and PixelFed.
</small></p>
<div>
<form name="register" method="post" action="/register">
{% csrf_token %}
{{ register_form.as_p }}
<input type=hidden name="invite_code" value="{{ invite.code }}">
<button type="submit">Create account</button>
</form>
</div>
</div>
{% endblock %}

View file

@ -35,6 +35,7 @@ urlpatterns = [
# ui views # ui views
re_path(r'^login/?$', views.login_page), re_path(r'^login/?$', views.login_page),
re_path(r'^about/?$', views.about_page), re_path(r'^about/?$', views.about_page),
re_path(r'^invite/(?P<code>[A-Za-z0-9]+)/?$', views.invite_page),
path('', views.home), path('', views.home),
re_path(r'^(?P<tab>home|local|federated)/?$', views.home_tab), re_path(r'^(?P<tab>home|local|federated)/?$', views.home_tab),

View file

@ -51,7 +51,17 @@ def register(request):
return redirect('/login') return redirect('/login')
if not models.SiteSettings.get().allow_registration: if not models.SiteSettings.get().allow_registration:
raise PermissionDenied invite_code = request.POST.get('invite_code')
if not invite_code:
raise PermissionDenied
try:
invite = models.SiteInvite.objects.get(code=invite_code)
except models.SiteInvite.DoesNotExist:
raise PermissionDenied
else:
invite = None
form = forms.RegisterForm(request.POST) form = forms.RegisterForm(request.POST)
if not form.is_valid(): if not form.is_valid():
@ -62,6 +72,10 @@ def register(request):
password = form.data['password'] password = form.data['password']
user = models.User.objects.create_user(username, email, password) user = models.User.objects.create_user(username, email, password)
if invite:
invite.times_used += 1
invite.save()
login(request, user) login(request, user)
return redirect('/') return redirect('/')

View file

@ -222,6 +222,22 @@ def about_page(request):
} }
return TemplateResponse(request, 'about.html', data) return TemplateResponse(request, 'about.html', data)
def invite_page(request, code):
''' Handle invites. '''
try:
invite = models.SiteInvite.objects.get(code=code)
if not invite.valid():
raise PermissionDenied
except models.SiteInvite.DoesNotExist:
raise PermissionDenied
data = {
'site_settings': models.SiteSettings.get(),
'register_form': forms.RegisterForm(),
'invite': invite,
}
return TemplateResponse(request, 'invite.html', data)
@login_required @login_required
def notifications_page(request): def notifications_page(request):