forked from mirrors/bookwyrm
Allow account registration with invites.
This commit is contained in:
parent
e0a009a0f1
commit
48f7fd34a7
8 changed files with 111 additions and 4 deletions
|
@ -1,5 +1,5 @@
|
|||
''' usin django model forms '''
|
||||
from django.forms import ModelForm, PasswordInput
|
||||
from django.forms import ModelForm, PasswordInput, HiddenInput
|
||||
from django import forms
|
||||
|
||||
from fedireads import models
|
||||
|
@ -21,7 +21,7 @@ class RegisterForm(ModelForm):
|
|||
fields = ['username', 'email', 'password']
|
||||
help_texts = {f: None for f in fields}
|
||||
widgets = {
|
||||
'password': PasswordInput(),
|
||||
'password': PasswordInput()
|
||||
}
|
||||
|
||||
|
||||
|
|
24
fedireads/migrations/0043_siteinvite.py
Normal file
24
fedireads/migrations/0043_siteinvite.py
Normal 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)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -6,4 +6,4 @@ from .status import Favorite, Boost, Tag, Notification, ReadThrough
|
|||
from .user import User, UserFollows, UserFollowRequest, UserBlocks
|
||||
from .user import FederatedServer
|
||||
from .import_job import ImportJob, ImportItem
|
||||
from .site import SiteSettings
|
||||
from .site import SiteSettings, SiteInvite
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import base64
|
||||
import datetime
|
||||
|
||||
from Crypto import Random
|
||||
from django.db import models
|
||||
|
||||
from fedireads.settings import DOMAIN
|
||||
|
||||
class SiteSettings(models.Model):
|
||||
|
@ -17,3 +22,17 @@ class SiteSettings(models.Model):
|
|||
default_settings = SiteSettings(id=1)
|
||||
default_settings.save()
|
||||
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))
|
||||
|
|
33
fedireads/templates/invite.html
Normal file
33
fedireads/templates/invite.html
Normal 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 %}
|
|
@ -35,6 +35,7 @@ urlpatterns = [
|
|||
# ui views
|
||||
re_path(r'^login/?$', views.login_page),
|
||||
re_path(r'^about/?$', views.about_page),
|
||||
re_path(r'^invite/(?P<code>[A-Za-z0-9]+)/?$', views.invite_page),
|
||||
|
||||
path('', views.home),
|
||||
re_path(r'^(?P<tab>home|local|federated)/?$', views.home_tab),
|
||||
|
|
|
@ -51,7 +51,17 @@ def register(request):
|
|||
return redirect('/login')
|
||||
|
||||
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)
|
||||
if not form.is_valid():
|
||||
|
@ -62,6 +72,10 @@ def register(request):
|
|||
password = form.data['password']
|
||||
|
||||
user = models.User.objects.create_user(username, email, password)
|
||||
if invite:
|
||||
invite.times_used += 1
|
||||
invite.save()
|
||||
|
||||
login(request, user)
|
||||
return redirect('/')
|
||||
|
||||
|
|
|
@ -222,6 +222,22 @@ def about_page(request):
|
|||
}
|
||||
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
|
||||
def notifications_page(request):
|
||||
|
|
Loading…
Reference in a new issue