diff --git a/fedireads/forms.py b/fedireads/forms.py index c7805c4cf..4df32fc63 100644 --- a/fedireads/forms.py +++ b/fedireads/forms.py @@ -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')]) + } diff --git a/fedireads/migrations/0044_siteinvite_user.py b/fedireads/migrations/0044_siteinvite_user.py new file mode 100644 index 000000000..8a332129e --- /dev/null +++ b/fedireads/migrations/0044_siteinvite_user.py @@ -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, + ), + ] diff --git a/fedireads/models/site.py b/fedireads/models/site.py index 116398452..301202dc5 100644 --- a/fedireads/models/site.py +++ b/fedireads/models/site.py @@ -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) diff --git a/fedireads/templates/layout.html b/fedireads/templates/layout.html index 40affbd7c..027fa02de 100644 --- a/fedireads/templates/layout.html +++ b/fedireads/templates/layout.html @@ -62,7 +62,8 @@

diff --git a/fedireads/templates/manage_invites.html b/fedireads/templates/manage_invites.html new file mode 100644 index 000000000..ee62ed6ae --- /dev/null +++ b/fedireads/templates/manage_invites.html @@ -0,0 +1,32 @@ +{% extends 'layout.html' %} +{% load humanize %} +{% block content %} +
+
+

Invites

+ + + + + + + + {% for invite in invites %} + + + + + + + {% endfor %} +
LinkExpiresMax usesTimes used
{{ invite.link }}{{ invite.expiry|naturaltime }}{{ invite.use_limit }}{{ invite.times_used }}
+

Generate New Invite

+ +
+ {% csrf_token %} + {{ form.as_p }} + +
+
+
+{% endblock %} diff --git a/fedireads/urls.py b/fedireads/urls.py index 1723ae92f..b8fb83e46 100644 --- a/fedireads/urls.py +++ b/fedireads/urls.py @@ -36,6 +36,7 @@ urlpatterns = [ re_path(r'^login/?$', views.login_page), re_path(r'^about/?$', views.about_page), re_path(r'^invite/(?P[A-Za-z0-9]+)/?$', views.invite_page), + re_path(r'^manage_invites/?$', views.manage_invites), path('', views.home), re_path(r'^(?Phome|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) diff --git a/fedireads/view_actions.py b/fedireads/view_actions.py index 6b7c2ac29..db35269c5 100644 --- a/fedireads/view_actions.py +++ b/fedireads/view_actions.py @@ -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') diff --git a/fedireads/views.py b/fedireads/views.py index af9452ef8..32834842f 100644 --- a/fedireads/views.py +++ b/fedireads/views.py @@ -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):