Django-allauth: Redirect users post sign-up/sing-in to a specific page depending on the page they are coming from

Viewed 174

Problem

  1. I have an invite system in my django app that allow users to invite other people (using their email) to join their team.
  2. When an invited user clicks on an invitation, they are redirected to an url that carries informations about the specific team the user was invited to.
  3. Such url calls a view called accept_invitation that handles the following use-cases:
  • a) If a user is logged-in already AND they are also the invited user (i check the email of the invite), I add the user to the team and redirect them to the team's page.

  • b) If a user is logged-in already BUT they are not the invited user, I redirect them to a page where I invite them to log-in with a different account.

  • c) If a user is logged-out, I redirect them to a page where I invite them to log-in and/or sign-up to continue.

Use-case a) works just fine but use-case b) and c) I had to figure out how to propagate the informations of the invite to the following screens and past the login.

My initial idea was to add the parameters of the invitation to the request.session so that after the login-in I could have retrieved the informations from the request inside a MyAccountAdapter(DefaultAccountAdapter) adapter I defined then send the users where they had to go.

However, I am doing something wrong and MyAccountAdapter is not getting called. I am not sure why. I think it's because of another adapter MySocialAccountAdapter I made that maybe is messing things up (and I am not even sure if it's doing what it's supposed to do honestly).

Anyway, I am lost so any help would be super appreciated.

Setup

My accept_invitation view

def accept_invitation(request, invitation_id):
    invitation = TeamMemberInvitation.objects.get(id=invitation_id)
    print('I am entering here, yes')
    print(request)

    context = {
        'project': invitation.project,
        'invitation': invitation
    }

    if invitation.key_expired():
        print('expired do something')
        return render(request, 'action/team_and_permission/invitation_expired.html', context)

    if request.user.is_authenticated:
        print('user is logged in')
        if request.user.email == invitation.invitee.email:
            print('the logged in user is also the one invited!')
            if TeamMember.objects.filter(project=invitation.project,user=request.user).exists():
                print('the logged in user is the one invited and is already a member!')
                return redirect('action:project_team', project_id=invitation.project.id)
            else:
                print('the logged in user is the one invited but is not a member, yet!')
                #accept invitation
                invitation.status = INVITATION_STATUS[1][0]
                #add to team member
                invitation.accept_invitation(request.user)
                #send him to the project
                return redirect('action:project_team', project_id=invitation.project.id)

        else:
            print('the invited user is not the user that is currently logged in, do something!')
            # accept invitation
            invitation.status = INVITATION_STATUS[1][0]
            # add to team member
            invitation.accept_invitation(request.user)
            # send him to the project
            return redirect('action:project_team', project_id=invitation.project.id)

    # if user is logged out
    else:
        print('user is logged out')
        request.session['team_membership_project_id'] = str(invitation.project.id)
        request.session['invitation_id'] = str(invitation.id)


        return redirect('myusermodel:sign_in')

    return render(request, 'action/team_and_permission/accept_invitation.html', context)

My Adapters that I hoped was going to solve my problem but didn't (so I did something wrong on them)


class MyAccountAdapter(DefaultAccountAdapter):

    def get_login_redirect_url(self, request):
        print('I am entering here')
        print(request)
        if 'team_membership_project_id' in request.session:
            parameters = {}
            #parameters['project_id'] = request.session['team_membership_project_id']
            parameters['invitation_id'] = request.session['invitation_id']

            path = reverse('action:accept_invitation', urlconf=None, args=None, kwargs=parameters)

            return path

        path = '/'

        return path

    def is_open_for_signup(self, request):
        """
        Checks whether or not the site is open for signups.Next to simply returning True/False you can also intervene the
        regular flow by raising an ImmediateHttpResponse. (Comment reproduced from the overridden method.)
        """
        return True


class MySocialAccountAdapter(DefaultSocialAccountAdapter):
    def pre_social_login(self, request, sociallogin):
        user = sociallogin.user
        if user.id:
            return
        try:
            # if user exists, connect the account to the existing account and login
            customer = CustomUser.objects.get(email=user.email)
            sociallogin.state['process'] = 'connect'
            #sociallogin.connect(request, user)
            perform_login(request, customer, 'none')
        except CustomUser.DoesNotExist:
            pass


my settings

...

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.sites',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.google',
    'whitenoise.runserver_nostatic',  # new
]

MIDDLEWARE = [
    #'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]


...


AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]



AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
    'guardian.backends.ObjectPermissionBackend',
]

SITE_ID = 3
LOGIN_REDIRECT_URL = '/'
ACCOUNT_ADAPTER = 'myusermodel.adapter.MyAccountAdapter'



# Additional configuration settings
SOCIALACCOUNT_QUERY_EMAIL = True
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
AUTH_USER_MODEL = 'myusermodel.CustomUser'



SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'SCOPE': [
            'profile',
            'email',
        ],
        'AUTH_PARAMS': {
            'access_type': 'online',
        }
    }
}

...

And my Custom user model, in case this also is doing something wrong (I don't think so though)

from django.contrib.auth.base_user import BaseUserManager
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _


class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers
    for authentication instead of usernames.
    """
    def create_user(self, email, password, **extra_fields):
        """
        Create and save a User with the given email and password.
        """
        if not email:
            raise ValueError(_('The Email must be set'))
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError(_('Superuser must have is_staff=True.'))
        if extra_fields.get('is_superuser') is not True:
            raise ValueError(_('Superuser must have is_superuser=True.'))
        return self.create_user(email, password, **extra_fields)


class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(_('email address'), unique=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email
0 Answers
Related