forked from mirrors/bookwyrm
Invite views
This commit is contained in:
parent
65fa08633f
commit
fd6603ee07
8 changed files with 112 additions and 100 deletions
|
@ -27,7 +27,7 @@
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<h2 class="title is-4">Generate New Invite</h2>
|
<h2 class="title is-4">Generate New Invite</h2>
|
||||||
|
|
||||||
<form name="invite" action="/create-invite/" method="post">
|
<form name="invite" action="/invite/" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="field is-grouped">
|
<div class="field is-grouped">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
|
|
@ -274,32 +274,6 @@ class Views(TestCase):
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
def test_invite_page(self):
|
|
||||||
''' there are so many views, this just makes sure it LOADS '''
|
|
||||||
models.SiteInvite.objects.create(code='hi', user=self.local_user)
|
|
||||||
request = self.factory.get('')
|
|
||||||
request.user = AnonymousUser
|
|
||||||
# why?? this is annoying.
|
|
||||||
request.user.is_authenticated = False
|
|
||||||
with patch('bookwyrm.models.site.SiteInvite.valid') as invite:
|
|
||||||
invite.return_value = True
|
|
||||||
result = views.invite_page(request, 'hi')
|
|
||||||
self.assertIsInstance(result, TemplateResponse)
|
|
||||||
self.assertEqual(result.template_name, 'invite.html')
|
|
||||||
self.assertEqual(result.status_code, 200)
|
|
||||||
|
|
||||||
|
|
||||||
def test_manage_invites(self):
|
|
||||||
''' there are so many views, this just makes sure it LOADS '''
|
|
||||||
request = self.factory.get('')
|
|
||||||
request.user = self.local_user
|
|
||||||
request.user.is_superuser = True
|
|
||||||
result = views.manage_invites(request)
|
|
||||||
self.assertIsInstance(result, TemplateResponse)
|
|
||||||
self.assertEqual(result.template_name, 'manage_invites.html')
|
|
||||||
self.assertEqual(result.status_code, 200)
|
|
||||||
|
|
||||||
|
|
||||||
def test_notifications_page(self):
|
def test_notifications_page(self):
|
||||||
''' there are so many views, this just makes sure it LOADS '''
|
''' there are so many views, this just makes sure it LOADS '''
|
||||||
request = self.factory.get('')
|
request = self.factory.get('')
|
||||||
|
|
48
bookwyrm/tests/views/test_invite.py
Normal file
48
bookwyrm/tests/views/test_invite.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
''' test for app action functionality '''
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
from django.template.response import TemplateResponse
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.test.client import RequestFactory
|
||||||
|
|
||||||
|
from bookwyrm import models
|
||||||
|
from bookwyrm import views
|
||||||
|
|
||||||
|
|
||||||
|
class InviteViews(TestCase):
|
||||||
|
''' every response to a get request, html or json '''
|
||||||
|
def setUp(self):
|
||||||
|
''' we need basic test data and mocks '''
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.local_user = models.User.objects.create_user(
|
||||||
|
'mouse@local.com', 'mouse@mouse.mouse', 'password',
|
||||||
|
local=True, localname='mouse')
|
||||||
|
|
||||||
|
|
||||||
|
def test_invite_page(self):
|
||||||
|
''' there are so many views, this just makes sure it LOADS '''
|
||||||
|
view = views.Invite.as_view()
|
||||||
|
models.SiteInvite.objects.create(code='hi', user=self.local_user)
|
||||||
|
request = self.factory.get('')
|
||||||
|
request.user = AnonymousUser
|
||||||
|
# why?? this is annoying.
|
||||||
|
request.user.is_authenticated = False
|
||||||
|
with patch('bookwyrm.models.site.SiteInvite.valid') as invite:
|
||||||
|
invite.return_value = True
|
||||||
|
result = view(request, 'hi')
|
||||||
|
self.assertIsInstance(result, TemplateResponse)
|
||||||
|
self.assertEqual(result.template_name, 'invite.html')
|
||||||
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
def test_manage_invites(self):
|
||||||
|
''' there are so many views, this just makes sure it LOADS '''
|
||||||
|
view = views.ManageInvites.as_view()
|
||||||
|
request = self.factory.get('')
|
||||||
|
request.user = self.local_user
|
||||||
|
request.user.is_superuser = True
|
||||||
|
result = view(request)
|
||||||
|
self.assertIsInstance(result, TemplateResponse)
|
||||||
|
self.assertEqual(result.template_name, 'manage_invites.html')
|
||||||
|
self.assertEqual(result.status_code, 200)
|
|
@ -51,11 +51,11 @@ urlpatterns = [
|
||||||
views.PasswordReset.as_view()),
|
views.PasswordReset.as_view()),
|
||||||
re_path(r'^change-password/?$', views.ChangePassword),
|
re_path(r'^change-password/?$', views.ChangePassword),
|
||||||
|
|
||||||
|
#invites
|
||||||
|
re_path(r'^invite/?$', views.ManageInvites.as_view()),
|
||||||
|
re_path(r'^invite/(?P<code>[A-Za-z0-9]+)/?$', views.Invite.as_view()),
|
||||||
|
|
||||||
re_path(r'^about/?$', vviews.about_page),
|
re_path(r'^about/?$', vviews.about_page),
|
||||||
re_path(r'^invite/?$', vviews.manage_invites),
|
|
||||||
re_path(r'^invite/(?P<code>[A-Za-z0-9]+)/?$', vviews.invite_page),
|
|
||||||
|
|
||||||
path('', vviews.home),
|
path('', vviews.home),
|
||||||
re_path(r'^(?P<tab>home|local|federated)/?$', vviews.home_tab),
|
re_path(r'^(?P<tab>home|local|federated)/?$', vviews.home_tab),
|
||||||
re_path(r'^discover/?$', vviews.discover_page),
|
re_path(r'^discover/?$', vviews.discover_page),
|
||||||
|
@ -141,6 +141,5 @@ urlpatterns = [
|
||||||
|
|
||||||
re_path(r'^clear-notifications/?$', actions.clear_notifications),
|
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)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
|
@ -653,23 +653,6 @@ def retry_import(request):
|
||||||
goodreads_import.start_import(job)
|
goodreads_import.start_import(job)
|
||||||
return redirect('/import-status/%d' % job.id)
|
return redirect('/import-status/%d' % job.id)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@require_POST
|
|
||||||
@permission_required('bookwyrm.create_invites', raise_exception=True)
|
|
||||||
def create_invite(request):
|
|
||||||
''' creates a user invite database entry '''
|
|
||||||
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('/invite')
|
|
||||||
|
|
||||||
|
|
||||||
def update_readthrough(request, book=None, create=True):
|
def update_readthrough(request, book=None, create=True):
|
||||||
''' updates but does not save dates on a readthrough '''
|
''' updates but does not save dates on a readthrough '''
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
''' make sure all our nice views are available '''
|
''' make sure all our nice views are available '''
|
||||||
from .authentication import Login, Register, Logout
|
from .authentication import Login, Register, Logout
|
||||||
from .password import PasswordResetRequest, PasswordReset, ChangePassword
|
from .password import PasswordResetRequest, PasswordReset, ChangePassword
|
||||||
|
from .invite import ManageInvites, Invite
|
||||||
|
|
58
bookwyrm/views/invite.py
Normal file
58
bookwyrm/views/invite.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
''' invites when registration is closed '''
|
||||||
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.http import HttpResponseBadRequest
|
||||||
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
|
from django.template.response import TemplateResponse
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.views import View
|
||||||
|
|
||||||
|
from bookwyrm import forms, models
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable= no-self-use
|
||||||
|
@method_decorator(login_required, name='dispatch')
|
||||||
|
@method_decorator(
|
||||||
|
permission_required('bookwyrm.create_invites', raise_exception=True),
|
||||||
|
name='dispatch')
|
||||||
|
class ManageInvites(View):
|
||||||
|
''' create invites '''
|
||||||
|
def get(self, request):
|
||||||
|
''' invite management page '''
|
||||||
|
data = {
|
||||||
|
'title': 'Invitations',
|
||||||
|
'invites': models.SiteInvite.objects.filter(
|
||||||
|
user=request.user).order_by('-created_date'),
|
||||||
|
'form': forms.CreateInviteForm(),
|
||||||
|
}
|
||||||
|
return TemplateResponse(request, 'manage_invites.html', data)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
''' creates an invite database entry '''
|
||||||
|
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('/invite')
|
||||||
|
|
||||||
|
|
||||||
|
class Invite(View):
|
||||||
|
''' use an invite to register '''
|
||||||
|
def get(self, request, code):
|
||||||
|
''' endpoint for using an invites '''
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
return redirect('/')
|
||||||
|
invite = get_object_or_404(models.SiteInvite, code=code)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'title': 'Join',
|
||||||
|
'register_form': forms.RegisterForm(),
|
||||||
|
'invite': invite,
|
||||||
|
'valid': invite.valid() if invite else True,
|
||||||
|
}
|
||||||
|
return TemplateResponse(request, 'invite.html', data)
|
||||||
|
|
||||||
|
# post handling is in views.authentication.Register
|
|
@ -8,7 +8,7 @@ from django.db.models import Avg, Q, Max
|
||||||
from django.db.models.functions import Greatest
|
from django.db.models.functions import Greatest
|
||||||
from django.http import HttpResponseNotFound, JsonResponse
|
from django.http import HttpResponseNotFound, JsonResponse
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.decorators.http import require_GET
|
from django.views.decorators.http import require_GET
|
||||||
|
@ -332,57 +332,6 @@ def about_page(request):
|
||||||
return TemplateResponse(request, 'about.html', data)
|
return TemplateResponse(request, 'about.html', data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@require_GET
|
|
||||||
def password_reset(request, code):
|
|
||||||
''' endpoint for sending invites '''
|
|
||||||
if request.user.is_authenticated:
|
|
||||||
return redirect('/')
|
|
||||||
try:
|
|
||||||
reset_code = models.PasswordReset.objects.get(code=code)
|
|
||||||
if not reset_code.valid():
|
|
||||||
raise PermissionDenied
|
|
||||||
except models.PasswordReset.DoesNotExist:
|
|
||||||
raise PermissionDenied
|
|
||||||
|
|
||||||
return TemplateResponse(
|
|
||||||
request,
|
|
||||||
'password_reset.html',
|
|
||||||
{'title': 'Reset Password', 'code': reset_code.code}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@require_GET
|
|
||||||
def invite_page(request, code):
|
|
||||||
''' endpoint for sending invites '''
|
|
||||||
if request.user.is_authenticated:
|
|
||||||
return redirect('/')
|
|
||||||
invite = get_object_or_404(models.SiteInvite, code=code)
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'title': 'Join',
|
|
||||||
'register_form': forms.RegisterForm(),
|
|
||||||
'invite': invite,
|
|
||||||
'valid': invite.valid() if invite else True,
|
|
||||||
}
|
|
||||||
return TemplateResponse(request, 'invite.html', data)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required('bookwyrm.create_invites', raise_exception=True)
|
|
||||||
@require_GET
|
|
||||||
def manage_invites(request):
|
|
||||||
''' invite management page '''
|
|
||||||
data = {
|
|
||||||
'title': 'Invitations',
|
|
||||||
'invites': models.SiteInvite.objects.filter(
|
|
||||||
user=request.user).order_by('-created_date'),
|
|
||||||
'form': forms.CreateInviteForm(),
|
|
||||||
}
|
|
||||||
return TemplateResponse(request, 'manage_invites.html', data)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@require_GET
|
@require_GET
|
||||||
def notifications_page(request):
|
def notifications_page(request):
|
||||||
|
|
Loading…
Reference in a new issue