Add manage invites page.

This commit is contained in:
Adam Kelly 2020-06-03 17:38:30 +01:00
parent 48f7fd34a7
commit 70e69f73cb
8 changed files with 122 additions and 4 deletions

View file

@ -1,5 +1,8 @@
''' usin django model forms '''
from django.forms import ModelForm, PasswordInput, HiddenInput
import datetime
from django.core.exceptions import ValidationError
from django.forms import ModelForm, PasswordInput, widgets
from django import forms
from fedireads import models
@ -115,3 +118,35 @@ class EditionForm(ModelForm):
class ImportForm(forms.Form):
csv_file = forms.FileField()
class ExpiryWidget(widgets.Select):
def value_from_datadict(self, data, files, name):
selected_string = super().value_from_datadict(data, files, name)
if selected_string == 'day':
interval = datetime.timedelta(days=1)
elif selected_string == 'week':
interval = datetime.timedelta(days=7)
elif selected_string == 'month':
interval = datetime.timedelta(days=31) # Close enough?
elif selected_string == 'forever':
return None
else:
return selected_string # "This will raise
return datetime.datetime.now() + interval
class CreateInviteForm(ModelForm):
class Meta:
model = models.SiteInvite
exclude = ['code', 'user', 'times_used']
widgets = {
'expiry': ExpiryWidget(choices=[
('day', 'One Day'),
('week', 'One Week'),
('month', 'One Month'),
('forever', 'Does Not Expire')]),
'use_limit': widgets.Select(
choices=[(i, "%d uses" % (i,)) for i in [1, 5, 10, 25, 50, 100]]
+ [(None, 'Unlimited')])
}

View file

@ -0,0 +1,21 @@
# Generated by Django 3.0.3 on 2020-06-02 15:46
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('fedireads', '0043_siteinvite'),
]
operations = [
migrations.AddField(
model_name='siteinvite',
name='user',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

View file

@ -1,10 +1,11 @@
import base64
import datetime
from Crypto import Random
from django.db import models
from django.utils import timezone
from fedireads.settings import DOMAIN
from .user import User
class SiteSettings(models.Model):
name = models.CharField(default=DOMAIN, max_length=100)
@ -31,8 +32,13 @@ class SiteInvite(models.Model):
expiry = models.DateTimeField(blank=True, null=True)
use_limit = models.IntegerField(blank=True, null=True)
times_used = models.IntegerField(default=0)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def valid(self):
return (
(self.expiry is None or self.expiry > datetime.datetime.now()) and
(self.expiry is None or self.expiry > timezone.now()) and
(self.use_limit is None or self.times_used < self.use_limit))
@property
def link(self):
return "https://{}/invite/{}".format(DOMAIN, self.code)

View file

@ -62,7 +62,8 @@
<ul class="pulldown">
<li><a href="/user/{{ request.user }}">Your profile</a></li>
<li><a href="/user-edit/">Settings</a></li>
<li><a href="/import">Import Books</a><li>
<li><a href="/import">Import Books</a></li>
<li><a href="/manage_invites/">Invites</a></li>
<li><a href="/logout/">Log out</a></li>
</ul>
</p>

View file

@ -0,0 +1,32 @@
{% extends 'layout.html' %}
{% load humanize %}
{% block content %}
<div class="content-container">
<div class="manage-invites">
<h2>Invites</h2>
<table>
<tr>
<th>Link</th>
<th>Expires</th>
<th>Max uses</th>
<th>Times used</th>
</tr>
{% for invite in invites %}
<tr>
<td><a href="{{ invite.link }}">{{ invite.link }}</td>
<td>{{ invite.expiry|naturaltime }}</td>
<td>{{ invite.use_limit }}</td>
<td>{{ invite.times_used }}</td>
</tr>
{% endfor %}
</table>
<h2>Generate New Invite</h2>
<form name="avatar" action="/create_invite/" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Create Invite</button>
</form>
</div>
</div>
{% endblock %}

View file

@ -36,6 +36,7 @@ urlpatterns = [
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),
re_path(r'^manage_invites/?$', views.manage_invites),
path('', views.home),
re_path(r'^(?P<tab>home|local|federated)/?$', views.home_tab),
@ -104,4 +105,6 @@ urlpatterns = [
re_path(r'^clear-notifications/?$', actions.clear_notifications),
re_path(r'^create_invite/?$', actions.create_invite),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -431,3 +431,15 @@ def import_data(request):
goodreads_import.start_import(job)
return redirect('/import_status/%d' % (job.id,))
return HttpResponseBadRequest()
@login_required
def create_invite(request):
form = forms.CreateInviteForm(request.POST)
if not form.is_valid():
return HttpResponseBadRequest("ERRORS : %s" % (form.errors,))
invite = form.save(commit=False)
invite.user = request.user
invite.save()
return redirect('/manage_invites')

View file

@ -238,6 +238,14 @@ def invite_page(request, code):
}
return TemplateResponse(request, 'invite.html', data)
@login_required
def manage_invites(request):
data = {
'invites': models.SiteInvite.objects.filter(user=request.user),
'form': forms.CreateInviteForm(),
}
return TemplateResponse(request, 'manage_invites.html', data)
@login_required
def notifications_page(request):