django-allauth: submitting form after social login - django

The current flow for visitors with django-allauth is if the visitor fills in a form, if they are not already authenticated they are shown a login modal with option of facebook login or standard signup form, with the original form data being saved in ACCOUNT_SIGNUP_FORM_CLASS=SignupForm
class SignupForm(forms.Form):
def signup(self, request, user):
new_user = Profile()
new_user.user = user
new_user.save()
# if form data provided with signup save it.
model = self.cleaned_data['model']
if model:
# save the form
This works fine if the user signs up using the standard signup form, but if they signup using facebook social account the values from the form are now empty strings i.e. self.cleaned_data['model']. I assume the original request object is destoryed so the post data is lost? There also doesn't seem anyway to pass the form data to facebook and receive it back e.g.
<a title="{{provider.name}}" href="{% provider_login_url provider.id modal="1" process="login" next=request.path scope=scope auth_params=auth_params %}"
Is the only way to do what I want is to save the form data using local storage or the database then somehow assign it back to the visitor once registered and save it?

What I've gone with is changing the Facebook signup button to link to an intermediate view where I save the form data as session data and then redirect back to the allauth facebook login url.
I then extract the form data from the session in the signup method after the user has authenticated with facebook.

Related

Django Session Form (save form temporarily)

I have created a page for review form. All users can fill out the form, but only logged in users can submit the form. If users is not logged in, they will be redirected to the login page. After they login, they will be redirected to the profile page.
So the flow will be like this :
User fills out the form > click the submit > redirected to login page > user login and redirected to profile page (at the same time, the form they have filled in is automatically saved)
I want the form they have filled in automatically saved after they login. How to do that?
My idea is to create a session that saves the form temporarily, then save to database after they login. But I'm confused how to write the code
Can anyone explain a bit what a django session is like? and how to write code to handle this problem?
You can try something like,
1 User fills out the form and hits submit
2 in the POST view where you handle the form, use the "**is_authenticated**" function and,
a)if the user is authenticated you handle the form as usual...
b)else set the contents of the form into a session variable in the views and redirect to the login page like,
request.session['review_body'] = request.post.get(the_form_body_field)
3 as per what you've said, after login it goes to profile page and form is submitted...
a)so in views where you serve the profile page, check if the session variable containing form data's exist and has values
b)if yes, directly save the contents from your views and clear the session data

django login_required for variable urls

I am trying to write a basic website in django. I need the user (i'm still using the default one) to be able to login, logout, register, etc. I have the basic functionality set up, but I want the user to be able to visit a profile page where it will display basic information about the user. Naturally, the profile page must use the login_required decorator but the way I have it set up now is that once anybody signs in they can see any profile page.
Part of the URL file:
url(r'^profile/(?P<username>[\w.#+-]+)/$',
login_required(ProfilePageView.as_view())),
As you can see, the url should consist of "profile/" follow by the username of the user. How can I set it up so that only the user with the username following the "profile/" part of the url can see that page. With this code some user could login with any username and then just change the url and resend the get request.
You can do something like this. if you have created a Profile model for each user you can also access the Profile information using profile_info=request.user.profile
def login_user(request):
username=request.POST.get('username','')
password=request.POST.get('password','')
user=auth.authenticate(username=username,password=password)
if user is not None:
auth.login(request,user)
return HttpResponseRedirect('/loggin/')
else:
return HttpResponseRedirect('/invalid/')
def loggin(request):
username=None
if request.user.is_authenticated:
#profile_info=request.user.profile
info=request.user
return render(request,'base.html',locals())
<head>
<body>
<h5>{{info.first_name}}{{info.first_name}}</h5>
</body>
</head>

Prompting registration after creating content but before save

I am trying to implement a page using Django where the user is able to create content, hit submit, and then is prompted to register or login if they are not currently logged-in. One of the fields in the model for the content references the user, so they must be logged-in to create it, however I want them to be able to input all of the data before they are prompted with logging-in. I have used the #loginrequired decorator on the view, but that forced the user to be logged-in before they create the content. Here is the view currently:
def search(request):
form = LocationInput()
if request.method == "POST":
form = LocationInput(request.POST)
if form.is_valid():
t = Trip(trip_name = form.cleaned_data['city'])
t.user = request.user
t.save()
form.save()
l = Location.objects.get(google_id=form.cleaned_data['google_id'])
l.trips.add(t)
l.save()
return HttpResponseRedirect('/trips/')
return render(request, 'frontpage/search.html', {'form': form})
It loads the form, creates an object that needs a user associated with it so I need to register the user but keep the data from LocationInput(request.POST) until after the user has registered. Any help would be greatly appreciated!
I can see two options:
Allow NULL for user reference, save the content in a state "pending user login or sign up", and store the ID of the content object in a session. Vacuum "old" contents with no user reference on a regular basis.
Save the whole data of the form in a session.
I like the first one better since you, as a superuser, have access to the content even if the user didn't login or signup, and if the user contact you later telling you he had troubles signing in, you will be able to help and recover the content he submitted. While if everything is stored in session, once the session is deleted, it's all lost.

How to redirect the login page and check for login session in Django userena

I am new to django and to userena. I have implemented django userena and the login page which is working fine. Currently after successful login the user is redirected to profile page. I want to change this and do two things:
1. Redirect the user to the home page after successful login and not profile page and second
2. The homepage and all other pages should detect the user session and use the session variables for the particular user to customize the page.
Please let me know how should I achieve this.
THanks!
To redirect use:
USERENA_SIGNIN_REDIRECT_URL = 'your_url'
the user should always be available and you could do things like self.request.user.is_authenticated() in a view or {{ user.is_authenticated }} in a template
This is how am I doing it to check if the user is signed in.
#views.py
from userena.views import signup, signin
def sign_up(request):
#if user is authenticated, redirect to user's profile page
#otherwise use userena signup view, with my own form,SignupFormExtra, instead of userena's
if request.user.is_authenticated():
username = request.user.username
return HttpResponseRedirect('/accounts/'+username)
else:
return signup(request,signup_form=SignupFormExtra)
def sign_in(request):
if request.user.is_authenticated():
username = request.user.username
return HttpResponseRedirect('/accounts/'+username)
else:
return signin(request)
and in my urls.py I have
url(r'^accounts/signup/$', 'accounts.views.sign_up'),
url(r'^accounts/signin/$', 'accounts.views.sign_in'),

How does userena with Django track if user signed in?

With normal Django user handeling, you would save a session to the user once he/she is logged in. However, after reading the userena views.py file for signin, I couldn't see how the user is tracked so that once they log in, the site would now they are logged in. I put the code from userena below:
def signin(request, auth_form=AuthenticationForm,
template_name='userena/signin_form.html',
redirect_field_name=REDIRECT_FIELD_NAME,
redirect_signin_function=signin_redirect, extra_context=None):
"""
Signin using email or username with password.
Signs a user in by combining email/username with password. If the
combination is correct and the user :func:`is_active` the
:func:`redirect_signin_function` is called with the arguments
``REDIRECT_FIELD_NAME`` and an instance of the :class:`User` whois is
trying the login. The returned value of the function will be the URL that
is redirected to.
A user can also select to be remembered for ``USERENA_REMEMBER_DAYS``.
:param auth_form:
Form to use for signing the user in. Defaults to the
:class:`AuthenticationForm` supplied by userena.
:param template_name:
String defining the name of the template to use. Defaults to
``userena/signin_form.html``.
:param redirect_field_name:
Form field name which contains the value for a redirect to the
successing page. Defaults to ``next`` and is set in
``REDIRECT_FIELD_NAME`` setting.
:param redirect_signin_function:
Function which handles the redirect. This functions gets the value of
``REDIRECT_FIELD_NAME`` and the :class:`User` who has logged in. It
must return a string which specifies the URI to redirect to.
:param extra_context:
A dictionary containing extra variables that should be passed to the
rendered template. The ``form`` key is always the ``auth_form``.
**Context**
``form``
Form used for authentication supplied by ``auth_form``.
"""
form = auth_form
if request.method == 'POST':
form = auth_form(request.POST, request.FILES)
if form.is_valid():
identification, password, remember_me = (form.cleaned_data['identification'],
form.cleaned_data['password'],
form.cleaned_data['remember_me'])
user = authenticate(identification=identification,
password=password)
if user.is_active:
login(request, user)
if remember_me:
request.session.set_expiry(userena_settings.USERENA_REMEMBER_ME_DAYS[1] * 86400)
else: request.session.set_expiry(0)
if userena_settings.USERENA_USE_MESSAGES:
messages.success(request, _('You have been signed in.'),
fail_silently=True)
# Whereto now?
redirect_to = redirect_signin_function(
request.REQUEST.get(redirect_field_name), user)
return redirect(redirect_to)
else:
return redirect(reverse('userena_disabled',
kwargs={'username': user.username}))
if not extra_context: extra_context = dict()
extra_context.update({
'form': form,
'next': request.REQUEST.get(redirect_field_name),
})
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)
The user is first authenticated using
user = authenticate(identification=identification,password=password)
which can be found here https://github.com/django/django/blob/master/django/contrib/auth/backends.py
This method checks if the user exists, and checks whether the password is correct.
If all goes well, the login method is called
login(request, user)
which can be found here
https://github.com/django/django/blob/master/django/contrib/auth/views.py
As you can see, these are two methods that are shipped with Django, and act as the sort of 'default' authentication package for Django.
Your site knows that a user is logged in because you'll probably be using Middleware (specifically SessionMiddleware and AuthenticationMiddleware), which attach a session and a user object to the request. The login method mentioned above saves the user ID to the session.
For more details see https://docs.djangoproject.com/en/dev/topics/auth/#authentication-in-web-requests
Concerning your comment:
You could render your template using RequestContext, or have your views return a TemplateResponse.
See https://docs.djangoproject.com/en/dev/ref/template-response/#using-templateresponse-and-simpletemplateresponse
This passes the user object to the template processor.
Then, in your template you could do something like this:
{% if user.is_authenticated %}
<p>Welcome {{ user.first_name }}</p>
{% else %}
<p>Please log in</p>
{% endif %}
Also see https://docs.djangoproject.com/en/dev/topics/auth/#id8
In my opinion it is indeed very well possible to put a modified version of this in your base.html. For example to show a login button if the user is not logged in, and replace it by a button that brings the user to his/her profile page when the user is logged in.