0

I am using allauth and want a user to be able to invite people via email to sign up to an account. When the new user signs up, I want to set their 'school' field to be the same as the user who invited them. In other words, they are part of the same school and I want to store that info when saving the new user.

To achieve this, I have an invite button which sends an email with the original user's school passed as a token, like so:

class AddUsers(TemplateView):
    template_name = 'schools/add-users.html'

    def get(self, request, *args, **kwargs):

        add_user_form = AddUserForm()

        context = {
            'add_user_form': add_user_form
        }

        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):

        if 'add_users' in request.POST:

            add_user_form = AddUserForm(request.POST)
            if add_user_form.is_valid():
                to_email_address = add_user_form.cleaned_data.get('email_field')
                user = request.user
                school = request.user.school

                mail_subject = 'Invitation to create an account'

                url = request.build_absolute_uri(reverse('account_signup'))
                uid = urlsafe_base64_encode(force_bytes(school.pk))
                token = account_activation_token.make_token(school)
                activation_link = "{0}?uid={1}&token{2}".format(url, uid, token)

                message = 'Hi,\n\nYour colleague ' + user.first_name + ' has invited you to sign up.\n\n'
                message += 'Click the activation link below\n\n'
                message += activation_link

                email = EmailMessage(mail_subject, message, to=[to_email_address])
                email.send()

                return HttpResponseRedirect(reverse('schools:add-users',))

        return HttpResponseRedirect(reverse('settings', ))

I override the allauth Signup form like this for a regular new user, but when the user has been invited by another user (i.e. via the email activation link with the school token), I plan to hide the school field and save the object held in the token value instead:

class SignupForm(ModelForm):
    first_name = forms.CharField(max_length=30)
    last_name = forms.CharField(max_length=150)

    class Meta:
        model = School

        fields = ['school_name', 'authority']

    def __init__(self, *args, **kwargs):
        super(SignupForm, self).__init__(*args, **kwargs)
        self.fields['first_name'].widget.attrs['class'] = 'form-control'
        self.fields['first_name'].widget.attrs['placeholder'] = 'First name'

        self.fields['last_name'].widget.attrs['class'] = 'form-control'
        self.fields['last_name'].widget.attrs['placeholder'] = 'Last name'

        self.fields['school_name'].widget.attrs['class'] = 'form-control'
        self.fields['school_name'].widget.attrs['placeholder'] = 'School name'

        self.fields['authority'].queryset = Authority.objects.get_all_authorities()
        self.fields['authority'].label = 'Local authority'
        self.fields['authority'].widget.attrs['class'] = 'form-control'
        self.fields['authority'].empty_label = 'No local authority'

    def signup(self, request, user):

        school_name = self.cleaned_data['school_name']
        first_name = self.cleaned_data['first_name']
        last_name = self.cleaned_data['last_name']
        authority = self.cleaned_data['authority']
        school = School.objects.new_school_account(school_name, authority, 28)
        user.school = school
        user.first_name = first_name
        user.last_name = last_name
        user.save()

This works and sends an email with the token which correctly redirects to the allauth account_signup page. I can see how I can use the code in this solution to convert the token back again, but I don't know how/where I can actually access the token using allauth Signup in order to save the school when saving the new user details.

So my question is - I am passing a token to the allauth account_signup page but how can I get the token so I can process it?

Mark__C
  • 825
  • 1
  • 13
  • 24
  • 1
    The `SignupView` will receive the parameters you added as query parameters to the URL as GET parameters. i.e. `request.GET.get('token')` and `request.GET.get('uid')` will contain these parameters (or not for new signups). So you need to grab those in the view, pass them as extra kwargs to your form and then process them there. – dirkgroten Aug 08 '19 at 10:50
  • @dirkgroten I think I get what you are suggesting but I don't seem to be able to get a view to get anything back. I am overriding like this: from allauth.account.views import SignupView class MySignupView(SignupView): and then I have tried overriding the get method and the signup method but it doesn't seem to call either of them? – Mark__C Aug 08 '19 at 11:40
  • 1
    Django needs to use this view instead of the allauth view. The only way is to override the url `/account/signup/` to point to your view. Put this above the allauth url include. Also, don't override `get()`, override `get_form_kwargs()` (`SignupView` is a `FormView`). – dirkgroten Aug 08 '19 at 11:49

1 Answers1

2

token = request.GET.get('token')

You can get it in de dispatch method in the SignupView like this:

class MySignupView(SignupView):
    def dispatch(self, request, *args, **kwargs):
        token = request.GET.get('token')
        return super(MySignupView, self).dispatch(request, *args, **kwargs)
Gijsriet
  • 123
  • 9
  • 1
    He probably needs them already in the `__init__()` method and I'm not sure the `request` is available there. Your answer is correct for the `signup()` method because the view adds it there, but in order to hide fields, he'd need to have access to them earlier. – dirkgroten Aug 08 '19 at 10:52