Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Try adding guest user library #3

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion adhocracy-plus/config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"allauth",
"allauth.account",
"allauth.socialaccount",
"guest_user",
"rules.apps.AutodiscoverRulesConfig",
"easy_thumbnails",
"parler",
Expand Down Expand Up @@ -276,6 +277,7 @@
"rules.permissions.ObjectPermissionBackend",
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
"guest_user.backends.GuestBackend",
)

ACCOUNT_ADAPTER = "apps.users.adapters.AccountAdapter"
Expand All @@ -300,7 +302,8 @@
SOCIALACCOUNT_EMAIL_AUTHENTICATION = True
SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT = True

LOGIN_URL = "account_login"
# LOGIN_URL = "account_login"
LOGIN_URL = "guest_create"
LOGIN_REDIRECT_URL = "/"

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
Expand Down Expand Up @@ -705,3 +708,7 @@
},
},
}

GUEST_USER = {
"NAME_GENERATOR": "guest_user.functions.generate_uuid_username", # Default option
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this in the fork of the django-guest, because the long uuid appears on the menu tab and it's ugly. So I switched to the numbered version. But maybe we deploy this one, and PM can let us know.

3 changes: 3 additions & 0 deletions adhocracy-plus/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from apps.userdashboard.routers import ModerationDetailDefaultRouter
from apps.users.api import UserViewSet
from apps.users.decorators import user_is_project_admin
from apps.users.views import GuestCreateView
from apps.users.views import set_language_overwrite

router = routers.DefaultRouter()
Expand Down Expand Up @@ -95,6 +96,8 @@
re_path(r"^django-admin/", admin.site.urls),
path("admin/", include("wagtail.admin.urls")),
path("documents/", include(wagtaildocs_urls)),
# path("convert/", include("guest_user.urls")),
path("accounts/guests/login", GuestCreateView.as_view(), name="guest_create"),
path("accounts/", include("allauth.urls")),
path("account/", include("apps.account.urls")),
path("profile/", include("apps.users.urls")),
Expand Down
16 changes: 11 additions & 5 deletions adhocracy-plus/templates/account/login.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
{% extends "account/base.html" %}
{% load i18n account %}
{% load i18n account %}

{% block head_title %}{% translate "Login" %}{% endblock %}
{% block head_title %}{% translate "Login" %}{% endblock head_title %}

{% block content %}
<h1>{% translate "Login" %}</h1>

<p>{% blocktranslate %}If you have not created an account yet, then please <a href="{{ signup_url }}">register</a> first.{% endblocktranslate %}</p>

<form method="POST" action="{% url 'account_login' %}" class="u-spacer-bottom-double">
{% url 'guest_create' as guest_create_url %}
{% with next_param=request.GET.next %}
{% with guest_url=guest_create_url|add:"?next="|add:next_param %}
<p>{% blocktranslate %}Sie wollen als Gast fortfahren? Dann klicken Sie <a href="{{ guest_url }}">hier</a>.{% endblocktranslate %}</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the english version here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asked Janek for english text yesterday, so waiting to add the content of these pages until I have that and can just do everything at once

{% endwith %}
{% endwith %}

<form method="post" action="{% url 'account_login' %}" class="u-spacer-bottom-double">
{{ form.non_field_errors }}
{% csrf_token %}

Expand All @@ -33,4 +39,4 @@ <h1>{% translate "Login" %}</h1>
</form>

{% include "socialaccount/snippets/provider_list.html" with process="login" %}
{% endblock %}
{% endblock content %}
13 changes: 11 additions & 2 deletions adhocracy-plus/templates/account/signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% load i18n %}
{% block head_title %}
{% translate "Register" %}
{% endblock %}
{% endblock head_title %}
{% block content %}
<h1>{% translate "Register" %}</h1>
{% with page=settings.a4_candy_cms_settings.ImportantPages.registration %}
Expand All @@ -14,6 +14,15 @@ <h1>{% translate "Register" %}</h1>
{% blocktranslate %}Already have an account? Then please
<a href="{{ login_url }}">login</a>.{% endblocktranslate %}
</p>
{% url 'guest_create' as guest_create_url %}
{% with next_param=request.GET.next %}
{% with guest_url=guest_create_url|add:"?next="|add:next_param %}
<p>
{% blocktranslate %}Sie wollen als Gast fortfahren? Dann klicken Sie
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

<a href="{{ guest_url }}">hier</a>.{% endblocktranslate %}
</p>
{% endwith %}
{% endwith %}
<form id="signup_form" method="post" action="{% url 'account_signup' %}">
{{ form.non_field_errors }}
{{ form.media }}
Expand Down Expand Up @@ -71,4 +80,4 @@ <h1>{% translate "Register" %}</h1>
</div>
</form>
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
{% endblock %}
{% endblock content %}
26 changes: 26 additions & 0 deletions apps/account/templates/a4_candy_account/guest_convert.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% extends "a4_candy_account/account_dashboard.html" %}

{% load i18n %}

{% block title %}{% translate 'Your user profile' %} &mdash; {{ block.super }}{% endblock %}
{% block dashboard_content %}
<h1 class="mt-0">{% translate 'Convert to regular account' %}</h1>

<form enctype="multipart/form-data" action="{{ request.path }}" method="post">
{% csrf_token %}

{% for field in form %}
{% if not field.name == 'get_notifications' and not field.name == 'get_newsletters' %}
{% include 'a4_candy_contrib/includes/form_field.html' with field=field %}
{% endif %}
{% endfor %}

{% include 'a4_candy_contrib/includes/form_checkbox_field.html' with field=form.get_notifications %}
{% include 'a4_candy_contrib/includes/form_checkbox_field.html' with field=form.get_newsletters %}

<div class="d-flex justify-content-end mb-3">
<button type="submit" class="btn btn--primary">{% translate 'Register'%}</button>
</div>
</form>
{{ form.media }}
{% endblock %}
5 changes: 5 additions & 0 deletions apps/account/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@
views.OrganisationTermsOfUseUpdateView.as_view(),
name="user_agreements",
),
path(
"convert/",
views.GuestConvertView.as_view(),
name="guest_convert",
),
]
72 changes: 71 additions & 1 deletion apps/account/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import ValidationError
from django.db import transaction
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.shortcuts import get_object_or_404, redirect
from django.utils.translation import gettext_lazy as _
from django.views import generic
from django.views.generic.base import RedirectView

from apps.users.models import User
from apps.users.forms import GuestConvertForm
from apps.users.utils import set_session_language

from guest_user.views import ConvertFormView
from guest_user.models import Guest

from . import forms
from .emails import AccountDeletionEmail

Expand Down Expand Up @@ -46,6 +51,71 @@ def render_to_response(self, context, **response_kwargs):
return response


# def dispatch(self, request, *args, **kwargs):
# if request.user.is_anonymous:
# return redirect(self.get_anonymous_redirect())

# if not is_guest_user(request.user):
# return redirect(self.get_user_redirect())

# return super().dispatch(request, *args, **kwargs)

# def get_anonymous_redirect(self):
# """Return the URL to redirect anonymous users to."""
# return self.anonymous_redirect or django_settings.LOGIN_URL

# def get_user_redirect(self):
# """Return the URL to redirect regular users to."""
# return self.user_redirect or django_settings.LOGIN_REDIRECT_URL

# @guestusersonly decorator
class GuestConvertView(SuccessMessageMixin, ConvertFormView, generic.FormView):
template_name = "a4_candy_account/guest_convert.html" # TODO make template
# TODO do i still need to set this class, perhaps instead of
form_class = GuestConvertForm
success_message = _("Your guest account has been successfully converted to a regular account.") # TODO still works on redirect?

# TODO add guest user checks, guest user delete

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user # Pass the guest user to the form
# Ensure 'instance' is not passed
if 'instance' in kwargs:
del kwargs['instance']
return kwargs

def get_initial(self):
"""Return the initial data to use for forms on this view."""
print("got initial")
return super().get_initial()

def form_valid(self, form):
# Convert the guest user to a regular user
user = form.save(self.request)
Guest.objects.filter(user=user).delete()

# Optionally, you can log the user in again or perform other actions
return redirect(self.get_success_url())

# def form_valid(self, form):
# # Convert the guest user to a regular user using the GuestManager's convert method
# user = Guest.objects.convert(form)

# # Optionally, you can log the user in again or perform other actions
# return redirect(self.get_success_url())

def get_success_url(self):
return reverse('account_profile')

def render_to_response(self, context, **response_kwargs):
# Set the session language and cookie
# set_session_language(self.request.user.email, self.request.user.language)
response = super().render_to_response(context, **response_kwargs)
# response.set_cookie(settings.LANGUAGE_COOKIE_NAME, self.request.user.language)
return response


class AccountDeletionView(LoginRequiredMixin, SuccessMessageMixin, generic.DeleteView):
template_name = "a4_candy_account/account_deletion.html"
form_class = forms.AccountDeletionForm
Expand Down
72 changes: 60 additions & 12 deletions apps/users/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from django.contrib.auth import forms as auth_forms
from django.utils.translation import get_language
from django.utils.translation import gettext_lazy as _

# from guest_user.functions import maybe_create_guest_user
from zeep import Client

from apps.captcha.fields import CaptcheckCaptchaField
Expand Down Expand Up @@ -36,8 +38,26 @@ def __init__(self, *args, **kwargs):
self.fields["password"].widget.attrs["autocomplete"] = "current-password"


class DefaultSignupForm(SignupForm):
terms_of_use = forms.BooleanField(label=_("Terms of use"))
class TermsAndCaptchaMixin:
def __init__(self, *args, **kwargs):
# First, call the parent class's __init__ to ensure self.fields is populated
super().__init__(*args, **kwargs)

if "terms_of_use" not in self.fields:
self.fields["terms_of_use"] = forms.BooleanField(label=_("Terms of use"))
if "captcha" not in self.fields:
self.fields["captcha"] = CaptcheckCaptchaField(label=_("I am not a robot"))

# Remove captcha if not configured
if not (hasattr(settings, "CAPTCHA_URL") and settings.CAPTCHA_URL):
del self.fields["captcha"]
else:
self.fields["captcha"].help_text = helpers.add_email_link_to_helptext(
self.fields["captcha"].help_text, CAPTCHA_HELP
)


class DefaultSignupForm(TermsAndCaptchaMixin, SignupForm):
get_newsletters = forms.BooleanField(
label=_("I would like to receive further information"),
help_text=_(
Expand All @@ -46,10 +66,22 @@ class DefaultSignupForm(SignupForm):
),
required=False,
)
captcha = CaptcheckCaptchaField(label=_("I am not a robot"))

def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None) # Accept an existing user instance
super().__init__(*args, **kwargs)

# needs an extra check for guest here? or would be checked elsewhere before?
if self.user:
# Populate the form with the existing user's data
# self.fields['email'].initial = self.user.email
# self.fields['username'].initial = self.user.username
# self.fields['get_newsletters'].initial = self.user.get_newsletters
self.fields['email'].required = True
self.fields['username'].required = True
self.fields['password1'].required = True
self.fields['password2'].required = True

self.fields["username"].help_text = _(
"Your username will appear publicly next to your posts."
)
Expand All @@ -61,20 +93,36 @@ def __init__(self, *args, **kwargs):
self.fields["email"].widget.attrs["autocomplete"] = "username"
self.fields["password1"].widget.attrs["autocomplete"] = "new-password"
self.fields["password2"].widget.attrs["autocomplete"] = "new-password"
if not (hasattr(settings, "CAPTCHA_URL") and settings.CAPTCHA_URL):
del self.fields["captcha"]
else:
self.fields["captcha"].help_text = helpers.add_email_link_to_helptext(
self.fields["captcha"].help_text, CAPTCHA_HELP
)

def save(self, request):
user = super().save(request)
if user:
if self.user:
# Update the existing guest user
user = self.user
user.email = self.cleaned_data["email"]
user.username = self.cleaned_data["username"]
user.get_newsletters = self.cleaned_data["get_newsletters"]
user.language = get_language()
# user.language = get_language()
user.set_password(self.cleaned_data["password1"]) # Set the new password
user.is_guest = False # Mark the user as a regular user
user.save()
return user
else:
# Create a new user (original behavior)
user = super().save(request)
if user:
user.get_newsletters = self.cleaned_data["get_newsletters"]
user.language = get_language()
user.save()
return user

class GuestCreateForm(TermsAndCaptchaMixin, forms.Form):
pass


class GuestConvertForm(DefaultSignupForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
del self.fields["captcha"]


class IgbceSignupForm(DefaultSignupForm):
Expand Down
1 change: 1 addition & 0 deletions apps/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class User(auth_models.AbstractBaseUser, auth_models.PermissionsMixin):
objects = auth_models.UserManager()

USERNAME_FIELD = "username"
PASSWORD_FIELD = "username"
REQUIRED_FIELDS = ["email"]

def get_projects_follow_list(self, exclude_private_projects=False):
Expand Down
Loading
Loading