many signup and space management fixes
This commit is contained in:
parent
bf467b1ec0
commit
3074d916dc
@ -166,7 +166,7 @@ admin.site.register(ViewLog, ViewLogAdmin)
|
|||||||
|
|
||||||
class InviteLinkAdmin(admin.ModelAdmin):
|
class InviteLinkAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'username', 'group', 'valid_until',
|
'group', 'valid_until',
|
||||||
'created_by', 'created_at', 'used_by'
|
'created_by', 'created_at', 'used_by'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -413,19 +413,11 @@ class InviteLinkForm(forms.ModelForm):
|
|||||||
|
|
||||||
return email
|
return email
|
||||||
|
|
||||||
def clean_username(self):
|
|
||||||
username = self.cleaned_data['username']
|
|
||||||
with scopes_disabled():
|
|
||||||
if username != '' and (User.objects.filter(username=username).exists() or InviteLink.objects.filter(username=username).exists()):
|
|
||||||
raise ValidationError(_('Username already taken!'))
|
|
||||||
return username
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InviteLink
|
model = InviteLink
|
||||||
fields = ('username', 'email', 'group', 'valid_until', 'space')
|
fields = ('email', 'group', 'valid_until', 'space')
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'username': _('A username is not required, if left blank the new user can choose one.'),
|
'email': _('An email address is not required but if present the invite link will be send to the user.'),
|
||||||
'email': _('An email address is not required but if present the invite link will be send to the user.')
|
|
||||||
}
|
}
|
||||||
field_classes = {
|
field_classes = {
|
||||||
'space': SafeModelChoiceField,
|
'space': SafeModelChoiceField,
|
||||||
|
@ -16,7 +16,10 @@ class ScopeMiddleware:
|
|||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
|
|
||||||
if request.path.startswith('/signup/'):
|
if request.path.startswith('/signup/') or request.path.startswith('/invite/'):
|
||||||
|
return self.get_response(request)
|
||||||
|
|
||||||
|
if request.path.startswith('/accounts/'):
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
|
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
|
17
cookbook/migrations/0127_remove_invitelink_username.py
Normal file
17
cookbook/migrations/0127_remove_invitelink_username.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.3 on 2021-06-07 14:21
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0126_alter_userpreference_theme'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='invitelink',
|
||||||
|
name='username',
|
||||||
|
),
|
||||||
|
]
|
@ -612,7 +612,6 @@ def default_valid_until():
|
|||||||
|
|
||||||
class InviteLink(ExportModelOperationsMixin('invite_link'), models.Model, PermissionModelMixin):
|
class InviteLink(ExportModelOperationsMixin('invite_link'), models.Model, PermissionModelMixin):
|
||||||
uuid = models.UUIDField(default=uuid.uuid4)
|
uuid = models.UUIDField(default=uuid.uuid4)
|
||||||
username = models.CharField(blank=True, max_length=64)
|
|
||||||
email = models.EmailField(blank=True)
|
email = models.EmailField(blank=True)
|
||||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||||
valid_until = models.DateField(default=default_valid_until)
|
valid_until = models.DateField(default=default_valid_until)
|
||||||
|
@ -141,7 +141,7 @@ class ShoppingListTable(tables.Table):
|
|||||||
|
|
||||||
class InviteLinkTable(tables.Table):
|
class InviteLinkTable(tables.Table):
|
||||||
link = tables.TemplateColumn(
|
link = tables.TemplateColumn(
|
||||||
"<input value='{{ request.scheme }}://{{ request.get_host }}{% url 'view_signup' record.uuid %}' class='form-control' />"
|
"<input value='{{ request.scheme }}://{{ request.get_host }}{% url 'view_invite' record.uuid %}' class='form-control' />"
|
||||||
)
|
)
|
||||||
delete_link = tables.TemplateColumn(
|
delete_link = tables.TemplateColumn(
|
||||||
"<a href='{% url 'delete_invite_link' record.pk %}' >" + _('Delete') + "</a>", verbose_name=_('Delete')
|
"<a href='{% url 'delete_invite_link' record.pk %}' >" + _('Delete') + "</a>", verbose_name=_('Delete')
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{{ form.email |as_crispy_field }}
|
{{ form.email |as_crispy_field }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{{ form.email2 |as_crispy_field }}
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{{ form.password1 |as_crispy_field }}
|
{{ form.password1 |as_crispy_field }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,10 +96,10 @@
|
|||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<select v-model="users['{{ u.pk }}']" class="custom-select form-control"
|
<select v-model="users['{{ u.pk }}']" class="custom-select form-control"
|
||||||
style="height: 44px">
|
style="height: 44px">
|
||||||
<option>{% trans 'admin' %}</option>
|
<option value="admin">{% trans 'admin' %}</option>
|
||||||
<option>{% trans 'user' %}</option>
|
<option value="user">{% trans 'user' %}</option>
|
||||||
<option>{% trans 'guest' %}</option>
|
<option value="guest">{% trans 'guest' %}</option>
|
||||||
<option>{% trans 'remove' %}</option>
|
<option value="remove">{% trans 'remove' %}</option>
|
||||||
</select>
|
</select>
|
||||||
<span class="input-group-append">
|
<span class="input-group-append">
|
||||||
<a class="btn btn-warning"
|
<a class="btn btn-warning"
|
||||||
|
@ -48,7 +48,8 @@ urlpatterns = [
|
|||||||
path('no-group', views.no_groups, name='view_no_group'),
|
path('no-group', views.no_groups, name='view_no_group'),
|
||||||
path('no-space', views.no_space, name='view_no_space'),
|
path('no-space', views.no_space, name='view_no_space'),
|
||||||
path('no-perm', views.no_perm, name='view_no_perm'),
|
path('no-perm', views.no_perm, name='view_no_perm'),
|
||||||
path('signup/<slug:token>', views.signup, name='view_signup'),
|
path('signup/<slug:token>', views.signup, name='view_signup'), # TODO deprecated with 0.16.2 remove at some point
|
||||||
|
path('invite/<slug:token>', views.invite_link, name='view_invite'),
|
||||||
path('system/', views.system, name='view_system'),
|
path('system/', views.system, name='view_system'),
|
||||||
path('search/', views.search, name='view_search'),
|
path('search/', views.search, name='view_search'),
|
||||||
path('search/v2/', views.search_v2, name='view_search_v2'),
|
path('search/v2/', views.search_v2, name='view_search_v2'),
|
||||||
|
@ -225,7 +225,7 @@ class InviteLinkCreate(GroupRequiredMixin, CreateView):
|
|||||||
if InviteLink.objects.filter(space=self.request.space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
|
if InviteLink.objects.filter(space=self.request.space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
|
||||||
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.request.user.username)
|
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.request.user.username)
|
||||||
message += _(' to join their Tandoor Recipes space ') + escape(self.request.space.name) + '.\n\n'
|
message += _(' to join their Tandoor Recipes space ') + escape(self.request.space.name) + '.\n\n'
|
||||||
message += _('Click the following link to activate your account: ') + self.request.build_absolute_uri(reverse('view_signup', args=[str(obj.uuid)])) + '\n\n'
|
message += _('Click the following link to activate your account: ') + self.request.build_absolute_uri(reverse('view_invite', args=[str(obj.uuid)])) + '\n\n'
|
||||||
message += _('If the link does not work use the following code to manually join the space: ') + str(obj.uuid) + '\n\n'
|
message += _('If the link does not work use the following code to manually join the space: ') + str(obj.uuid) + '\n\n'
|
||||||
message += _('The invitation is valid until ') + str(obj.valid_until) + '\n\n'
|
message += _('The invitation is valid until ') + str(obj.valid_until) + '\n\n'
|
||||||
message += _('Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub ') + 'https://github.com/vabene1111/recipes/'
|
message += _('Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub ') + 'https://github.com/vabene1111/recipes/'
|
||||||
|
@ -126,7 +126,7 @@ def no_space(request):
|
|||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
|
|
||||||
if join_form.is_valid():
|
if join_form.is_valid():
|
||||||
return HttpResponseRedirect(reverse('view_signup', args=[join_form.cleaned_data['token']]))
|
return HttpResponseRedirect(reverse('view_invite', args=[join_form.cleaned_data['token']]))
|
||||||
else:
|
else:
|
||||||
if settings.SOCIAL_DEFAULT_ACCESS:
|
if settings.SOCIAL_DEFAULT_ACCESS:
|
||||||
request.user.userpreference.space = Space.objects.first()
|
request.user.userpreference.space = Space.objects.first()
|
||||||
@ -134,7 +134,7 @@ def no_space(request):
|
|||||||
request.user.groups.add(Group.objects.get(name=settings.SOCIAL_DEFAULT_GROUP))
|
request.user.groups.add(Group.objects.get(name=settings.SOCIAL_DEFAULT_GROUP))
|
||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
if 'signup_token' in request.session:
|
if 'signup_token' in request.session:
|
||||||
return HttpResponseRedirect(reverse('view_signup', args=[request.session.pop('signup_token', '')]))
|
return HttpResponseRedirect(reverse('view_invite', args=[request.session.pop('signup_token', '')]))
|
||||||
|
|
||||||
create_form = SpaceCreateForm()
|
create_form = SpaceCreateForm()
|
||||||
join_form = SpaceJoinForm()
|
join_form = SpaceJoinForm()
|
||||||
@ -420,7 +420,7 @@ def setup(request):
|
|||||||
return render(request, 'setup.html', {'form': form})
|
return render(request, 'setup.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
def signup(request, token):
|
def invite_link(request, token):
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
try:
|
try:
|
||||||
token = UUID(token, version=4)
|
token = UUID(token, version=4)
|
||||||
@ -446,47 +446,15 @@ def signup(request, token):
|
|||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
else:
|
else:
|
||||||
request.session['signup_token'] = str(token)
|
request.session['signup_token'] = str(token)
|
||||||
|
return HttpResponseRedirect(reverse('account_signup'))
|
||||||
|
|
||||||
if request.method == 'POST':
|
messages.add_message(request, messages.ERROR, _('Invite Link not valid or already used!'))
|
||||||
updated_request = request.POST.copy()
|
return HttpResponseRedirect(reverse('index'))
|
||||||
if link.username != '':
|
|
||||||
updated_request.update({'username': link.username})
|
|
||||||
|
|
||||||
form = SignupForm(data=updated_request)
|
|
||||||
|
|
||||||
if form.is_valid():
|
# TODO deprecated with 0.16.2 remove at some point
|
||||||
if form.cleaned_data['password1'] != form.cleaned_data['password_confirm']: # noqa: E501
|
def signup(request, token):
|
||||||
form.add_error('password1', _('Passwords dont match!'))
|
return HttpResponseRedirect(reverse('view_invite', args=[token]))
|
||||||
else:
|
|
||||||
user = User(username=form.cleaned_data['username'], )
|
|
||||||
try:
|
|
||||||
validate_password(form.cleaned_data['password1'], user=user)
|
|
||||||
user.set_password(form.cleaned_data['password1'])
|
|
||||||
user.save()
|
|
||||||
messages.add_message(request, messages.SUCCESS, _('User has been created, please login!'))
|
|
||||||
|
|
||||||
link.used_by = user
|
|
||||||
link.save()
|
|
||||||
|
|
||||||
request.user.groups.clear()
|
|
||||||
user.groups.add(link.group)
|
|
||||||
|
|
||||||
user.userpreference.space = link.space
|
|
||||||
user.userpreference.save()
|
|
||||||
return HttpResponseRedirect(reverse('account_login'))
|
|
||||||
except ValidationError as e:
|
|
||||||
for m in e:
|
|
||||||
form.add_error('password', m)
|
|
||||||
else:
|
|
||||||
form = SignupForm()
|
|
||||||
|
|
||||||
if link.username != '':
|
|
||||||
form.fields['name'].initial = link.username
|
|
||||||
form.fields['name'].disabled = True
|
|
||||||
return render(request, 'account/signup.html', {'form': form, 'link': link})
|
|
||||||
|
|
||||||
messages.add_message(request, messages.ERROR, _('Invite Link not valid or already used!'))
|
|
||||||
return HttpResponseRedirect(reverse('index'))
|
|
||||||
|
|
||||||
|
|
||||||
@group_required('admin')
|
@group_required('admin')
|
||||||
|
@ -113,6 +113,11 @@ INSTALLED_APPS = [
|
|||||||
SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split(',') if os.getenv('SOCIAL_PROVIDERS') else []
|
SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split(',') if os.getenv('SOCIAL_PROVIDERS') else []
|
||||||
INSTALLED_APPS = INSTALLED_APPS + SOCIAL_PROVIDERS
|
INSTALLED_APPS = INSTALLED_APPS + SOCIAL_PROVIDERS
|
||||||
|
|
||||||
|
ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE = True
|
||||||
|
ACCOUNT_MAX_EMAIL_ADDRESSES = 3
|
||||||
|
ACCOUNT_EMAIL_REQUIRED = True
|
||||||
|
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 90
|
||||||
|
|
||||||
SOCIALACCOUNT_PROVIDERS = ast.literal_eval(
|
SOCIALACCOUNT_PROVIDERS = ast.literal_eval(
|
||||||
os.getenv('SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}')
|
os.getenv('SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user