Custom Form Validation in Django-Allauth - django-allauth

I want to do some extra validation on fields in django-allauth. For example I want to prevent using free email addresses. So I want to run this method on signup
def clean_email(self):
email_domain = self.cleaned_data['email'].split('#')[1]
if email_domain in self.bad_domains:
raise forms.ValidationError(_("Registration using free email addresses is prohibited. Please supply a different email address."))
Similarly I want to run custom validation on different fields other than email address. How can I perform this?

There are some adapters on the allauth configuration. For example this one:
ACCOUNT_ADAPTER (="allauth.account.adapter.DefaultAccountAdapter")
Specifies the adapter class to use, allowing you to alter certain default behaviour.
You can specify a new adapter by overriding the default one. Just override the clean_email method.
class MyCoolAdapter(DefaultAccountAdapter):
def clean_email(self, email):
"""
Validates an email value. You can hook into this if you want to
(dynamically) restrict what email addresses can be chosen.
"""
*** here goes your code ***
return email
Then modify the ACCOUNT_ADAPTER on the settings.py
ACCOUNT_ADAPTER = '**app**.MyCoolAdapter'
Check the default behavior on:
https://github.com/pennersr/django-allauth/blob/master/allauth/account/adapter.py

Related

custom validation on django-allauth

I'm using dj-allauth on my django app. When people sign up to my django project/app, I want to check that the domain on their email matches mydomain.com. Is this possible? I think I can do it by changing the signup form. I've tried the following which doesn't seem to do anything when I submit the signup form. There aren't any errors. It isn't checking for the domain, it's prompting for the user's nickname and then appending the domain automatically.
forms.py
class VSBSignupForm(SignupForm):
def save(self, request):
# Ensure you call the parent classes save.
# .save() returns a User object.
user = super(VSBSignupForm, self).save(request)
user.email_address = user.username + "#mydomain.com"
user.save()
# You must return the original result.
return user
settings.py
ACCOUNT_FORMS = {'signup': 'myapp.forms.VSBSignupForm'}
I changed the template for the signup.html such that it asks for the nickname and password, but not the email address.
edit I tried putting a print statement in the form save method and it didn't print anything in the shell, which makes me think the form isn't being used.

Ruby on Rails: How to validate if on specific page?

In my Ruby on Rails application I am trying to add in validations that will ensure the user has entered a value in a text box. In my system I have a table called Account which stores users' email account information, when they go onto the views/accounts/_form.html.erb page to add a new email account I want to validate the presence of a port number. I can do this through the following code:
validates :port, presence: true
This successfully ensures that users enter their port number, but when a user signs up through the views/users/_new.html.erb page they have to enter only an email address (e.g example#example.com) and the users_controller will then create a record in the Account table for this email address. My problem is that on the views/accounts/_form.html.erb page the port number is required but on the views/users/_new.html.erb it is not.
Is there a way of validating that the user enters the port number if they are on the views/accounts/_form.html.erb page or invoking the create method in the accounts_controller?
I am aware that I could do this through the HTML required validation like so: <%= f.text_field :port, :required => true %> but I need to add in further validation as well as presence, so this is not suitable.
You can create an attr_accessor field that determines if the validation should occur...
class Account < ActiveRecord:Base
attr_accessor :port_needs_validation
validates :port, presence: true, if: -> {port_needs_validation}
Then just set the accessor in your create method...
def create
#account = Account.new
#account.assign_attributes(account_params)
#account.port_needs_validation = true
if #account.save
...
Extract that part of the logic into a form object, check out the legendary 2012 blog entry from CodeClimate. Things have changed since then, the author uses Virtus to build form objects, more popular & up-to-date gems these days are:
reform
dry-rb
active type
but really you can make anything behave like an ActiveModel object
if it's a one-off thing, just do what Steve said in the other answer but that is a sure way to hell, safe-hate and divorce (at least from personal experience) in any slightly teeny weeny bigger project (i.e. you mean to spend some hours more working on it, it's not like you just finished everything and want to go home).
Actually, just use form classes everywhere and avoid model validations & other callbacks at all. You don't want things sending account activation mails or validating your password complexity when you're writing tests and just need a "post" that belongs to "user".
My own favorite personal fuckup due to model callbacks is sending 240.000 "your account has been upgraded/downgraded" emails because of an innocent spelling change update in an account_type attribute migration just because account_type_changed? was true.
So.. Form classes for ever, model callbacks never.
I would not recommend you have model aware of views. In #SteveTurczyn 's solution, an abstract field is introduced into model to identified the which page it come from, which is an good solution.
As from Ruby on Rail MVC, both View and Model talk to the controller, another solution will be have controller handle validation of params before passing the value to create account.

Don't allow a user to change email address using devise with Rails

I'm using devise to allow users to log in to a site. The authentication key is set to a username, which is to be unique. Also to be unique is the email address provided. It seems that somehow devise has already figured out that the email address should be unique. So that's good.
Now I want to let people change their passwords. I link over to my edit_user_registration_path, but notice that the user is allowed to change their email address. One option is to set reconfirmable to false... but I don't think I want to allow users to change their email addresses at all.
I think I could just remove the field from the devise view, but theoretically a carefully crafted PUT method could still let them change their email address. Is there a way to stop this field from being mutable? Or is it better to just let the email address be reconfirmable?
See http://trak3r.blogspot.com/2007/03/immutable-activerecord-attributes.html
So
class User
def email=(address)
if new_record?
write_attribute(:email, address)
else
raise 'email is immutable!'
end
end
end
In my case, the "answer" was to simply allow people to edit their email addresses. There are enough use cases in which somebody could legitimately want to change their email address that I figured there was no harm in trying to stop it.

How can I use devise invitable when my app allows many logins via the same email address?

My website allows people to register multiple accounts with the same email address, separated by domain name. This is done with an additional column domain_id in the user table.
In order to be able to use devise_invitable, I need it to check for existing users by email and domain_id. Currently the initializer will only allow me to specify a single key. Is there any way to override this? The following is what I would like to use in the initializer, but it throws up the error underneath.
config.invite_key = :email, :domain_id
undefined method `[:email, :domain_id]=' for #<User:0x0blah0> (NoMethodError)
This feature has now been added to Devise Invitable.
https://github.com/scambra/devise_invitable/issues/185

Using custom authlogic error messages

I am using the authlogic gem for user validation on one of my sites. All is going well, but I am wondering if it's possible to change the error message that gets returned when the user types in an invalid email address.
Thanks!
authlogic has a special setting for this purpose:
class UserSession < Authlogic::Session::Base
generalize_credentials_error_messages true
end
The error message will be the same: "Email/Password combination is not valid", whether the password or email is bad. You can change the text of the message specifying a string instead of true:
generalize_credentials_error_messages "Try again"
You can override the settings for email validation with validates_format_of_email_field_options. However, if you only want to change the message you can merge options with merge_validates_format_of_email_field_options so that only the options you specify are overridden. You specify settings in your User controller like so:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.merge_validates_format_of_email_field_options :message => 'My message'
end
end
You can also change the settings for length and uniqueness validations. There are also a lot more other settings, take a look at the documentation, in the ::Config sections of each module you can find settings and their default values and how to override them.
Alternatively you can use localization and set error_messages.email_invalid (that's what the plugin looks for before setting it to the default English sentence, also useful if you are building an international application).
Override Authlogic error messages by changing in en.yml file
It works for me.
en:
authlogic:
error_messages:
login_blank: "Please enter the email address."
login_not_found: "This email address is already in the system. Please choose a different email address."
login_invalid: "Please enter a valid email address."

Resources