How to setup email verification/confirmation in Django/Pinax? - django

How to setup email confirmation in Pinax?, Do I need to setup SMTP server or something like that?, I tried to find documentation about that but failed. Can anyone redirect me to documentation or any related article explaning about this?, Pinax uses emailconfirmation app. I browsed the code of emailconfirmation, But It doesn't include any settings about host or server.

The integration of emailconfirmation is pretty straightforward. You don't have to set up any mailserver, if you have an existing mailserver that you can use to send your mails. You just have to fill in the data used for sending the mails in your standard Django settings, and emailconfirmation is going to use that:
# e-mail settings
# XXXXXXXXXXXXXXXXXXXXXXX THESE ARE NOT YET PRODUCTIONREADY!
EMAIL_HOST='mail.your_mailserver.com'
EMAIL_PORT=1025
EMAIL_HOST_USER='your_username'
EMAIL_HOST_PASSWORD='your_password'
To summarize what to do next: You have to create a form for entering an email-adress (The reason why such a form doesn't come with emailconfiguration is somewhat obscure). This can look something like this:
# email form using emailconfirmation
class AddEmailForm(forms.Form):
def __init__(self, *args, **kwargs):
try:
self.user = kwargs.pop('user')
except KeyError:
pass
super(AddEmailForm, self).__init__(*args, **kwargs)
email = forms.EmailField(label="Email",required=True, widget=forms.TextInput())
def clean_email(self):
try:
EmailAddress.objects.get(user=self.user, email=self.cleaned_data["email"])
except EmailAddress.DoesNotExist:
try:
User.objects.get(email = self.cleaned_data['email'])
except User.DoesNotExist:
return self.cleaned_data["email"]
raise forms.ValidationError(u"email address associated with another account.")
def save(self):
try:
self.user.message_set.create(message="Confirmation email sent to %s" % self.cleaned_data["email"])
except AttributeError:
pass
return EmailAddress.objects.add_email(self.user, self.cleaned_data["email"])
This will allow a user to enter an email address, check if the email-adress allready exists and is in use by another account. After that it will add the emailadress to the unconfirmed emailadresses and send an email with a link to the user. The user then can confirm the emailadress by clicking on the link.
That's all there is to it. Let's hope the Pinax guys will do a quality offensive on their docs soon ;)

Related

how to customize django jwt graphql authentication

Hi I'm trying to customize
jwt graphql Django default authentication
I need to achieve log in with username or email
normal Django we customized authentication backend.
mutation{
tokenAuth(username:"myemail#email.com"
password:"pass")
{
token
}
}
Authenticate with username
mutation{
tokenAuth(username:"myname"
password:"pass")
{
token
}
}
the normal username is working fine.
how I can authenticate the user by username or email in jwt graphql
I tried this link
https://django-graphql-jwt.domake.io/en/latest/customizing.html
I don't get any idea about that...
Does anyone have any idea about that??
You have to make the changes on the Model level not in JWT, JWT will follow, because JWT is only a presentation of what is going on behind the scenes.
Look at the link under here, maybe it will help you! :)
Multiple USERNAME_FIELD in django user model
Disclaimer - mama's answer should work. Halfway through writting an answer I realised I'm wrong, but I still wanna show you what I wanted to suggest. It shows what JWT TokenAuth mutation does and a way to tap into that completely.
change the inbuild Django authentication like mama's answer suggests
rewrite graphql_jwt.decorators.token_auth to look at both fields, not just one
write your own class for the TokenMutation that uses this decorator on it's mutate function
Something like so (untested):
def two_field_token_auth(f):
#wraps(f)
#setup_jwt_cookie
#csrf_rotation
#refresh_expiration
def wrapper(cls, root, info, password, **kwargs):
context = info.context
context._jwt_token_auth = True
username = kwargs.get('username')
email = kwargs.get('email')
user = your_auth_method(
request=context,
username=username,
email=email,
password=password,
)
if user is None:
raise exceptions.JSONWebTokenError(
_('Please enter valid credentials'),
)
if hasattr(context, 'user'):
context.user = user
result = f(cls, root, info, **kwargs)
signals.token_issued.send(sender=cls, request=context, user=user)
return maybe_thenable((context, user, result), on_token_auth_resolve)
return wrapper
class TwoFieldJWTMutation(JSONWebTokenMutation):
#classmethod
#two_field_token_auth
def mutate(cls, root, info, **kwargs):
return cls.resolve(root, info, **kwargs)
All the necessary imports you can find here and here

Django fresh login required on accessing profile page

I am new to django and writing authentication system for my application. Right now I have built the basic login/logout functionality.
What I want is that whenever a logged in user wants to access their profile page, they should be asked to confirm their password.
I have searched this on django docs but I was not able to find any resource on how to achieve. I know flask has a fresh_login_required decorator which does this, just wondering if it is possible to do the same thing with django as well.
I don't think there is any function for this in django. But you can write on your own with help of django session. For example:
First, we need to write a decorator:
# decorator
def require_fresh_login(function):
#wraps(function)
def wrap(request, *args, **kwargs):
has_verified_profile = request.session.pop('has_login_verified',None)
if has_verified_profile:
return function(request, *args, **kwargs)
else:
return redirect(reverse('fresh_password_view_url'))
return wrap
Then there should be a view for fresh_password_view_url, where you need to put a value against key has_login_verified in request.session. For example:
def verify_fresh_password(request):
form = SomeForm(request.POST)
if form.is_valid():
password = form.cleaned_data.get('password')
if request.user.check_password(password):
request.session['has_login_verified'] = True
return redirect('profile_view')
# else send error response

How to validate data in django forms?

I have a feature on my website where a user can share content with another user registered on the site. They do this by entering in an email belonging to another user. This is then posted, setting the desired user to as a shared owner of content in the model.
What is the best way to check that the email address belongs to a registered user of the site?
Thanks!
I think the efficient way is to search for the user with the given mail. Django User already has a mail field that is unique.
if you want to write from basic:
from django.core.validators import validate_email
class SampleForm(forms.Form):
mail = forms.CharField(max_length=50)
def clean(self):
cleaned_data = super(SampleForm, self).clean()
mail = cleaned_data.get('mail')
# validate the structure of the mail address
try:
validate_email(mail)
except validate_email.ValidationError:
raise forms.ValidationError('email is not valid')
# now find if mail has registered
try:
User.objects.get(email=mail)
except User.DoesNotExist:
raise forms.ValidationError('This mail address is not registered')
return cleaned_data

Django update user email address

I'd like to allow my users to change their emails. Is there a plugin to allow me to do this? I tried "django-change-email 0.1.2", but it doesn't appear to work. I've fixed some outdated errors, and it asked to update the database after that. I did so, but the database didn't appear to show any new tables to change the email.
Basically, I'd like for users to update their email address themselves. The server will then send a confirmation email containing a unique hash. Clicking on this will validate the change and save the email. Is this possible with some other plugin? Thank you!
The best way to allow users to change their email address is to create a separate UserProfile models which can be used to store email address. Example code is shown below.
class UserProfileForm(ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
try:
self.fields['email'].initial = self.instance.user.email
except User.DoesNotExist:
pass
email = forms.EmailField(label="Primary email")
class Meta:
model = Parent
def save(self, *args, **kwargs):
"""
Update the primary email address on the related User object as well.
"""
u = self.instance.user
u.email = self.cleaned_data['email']
u.save()
profile = super(UserProfileForm, self).save(*args,**kwargs)
return profile
This way, you can ensure that the new email address remains inactive until the user has clicked on verify email address link which you will be sending to the user. Hope I answered your question.

How to use another field for logging in with Django Allauth?

I have successfully setup django-allauth along with a custom user model which let's users sign in directly using email and password or through Facebook, in which case email is taken from Facebook and saved in the Email field of the custom user model. I have also created a mobile field which stays empty as of now.
I want to allow users to log in using their Facebook, Email or MOBILE. Unfortunately that field is not unique=True in the model. I have thought of capturing the mobile and fetching the associated email address and then use that along with the password to log in any user.
However, I don't know how to extend the SIGN IN form that comes with django-allauth or the block of code that signs a user in where I can change it to meet my need.
As of now I don't find any of my current code relevant to this problem, but if it helps I am willing to provide it upon mention.
The following solution worked for me. I put the code in the forms.py file.
from allauth.account.forms import LoginForm
from auth_project import settings
class CustomLoginForm(LoginForm):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
if settings.ACCOUNT_AUTHENTICATION_METHOD == "email":
login_widget = forms.TextInput(attrs={'type': 'text',
'placeholder':
('Mobile Number'),
'autofocus': 'autofocus'})
login_field = forms.CharField(label=("Mobile"),
widget=login_widget)
self.fields["login"] = login_field
set_form_field_order(self, ["login", "password", "remember"])
def user_credentials(self):
credentials = {}
mobile = self.cleaned_data["login"]
login = CustomUser.objects.filter(mobile=mobile).values('email')[0]['email']
if settings.ACCOUNT_AUTHENTICATION_METHOD == "email":
credentials["email"] = login
credentials["password"] = self.cleaned_data["password"]
return credentials
# this is to set the form field in order
# careful with the indentation
def set_form_field_order(form, fields_order):
if hasattr(form.fields, 'keyOrder'):
form.fields.keyOrder = fields_order
else:
# Python 2.7+
from collections import OrderedDict
assert isinstance(form.fields, OrderedDict)
form.fields = OrderedDict((f, form.fields[f])
for f in fields_order)
Thanks.