# == Schema Information # Schema version: 45 # # Table name: users # # id :integer not null, primary key # email :string(255) not null # name :string(255) not null # hashed_password :string(255) not null # salt :string(255) not null # created_at :datetime not null # updated_at :datetime not null # email_confirmed :boolean default(false), not null # url_name :text not null # # models/user.rb: # Model of people who use the site to file requests, make comments etc. # # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # # $Id: user.rb,v 1.40 2008-03-21 14:45:38 francis Exp $ require 'digest/sha1' class User < ActiveRecord::Base validates_presence_of :email, :message => "^Please enter your email address" validates_presence_of :name, :message => "^Please enter your name" validates_presence_of :url_name validates_presence_of :hashed_password, :message => "^Please enter a password" has_many :info_requests has_many :user_info_request_sent_alerts has_many :post_redirects attr_accessor :password_confirmation validates_confirmation_of :password, :message =>"^Please enter the same password twice" acts_as_solr :fields => [ {:name => { :boost => 5.0 }}, { :created_at => :date } ] def validate errors.add(:email, "doesn't look like a valid address") unless MySociety::Validate.is_valid_email(self.email) end # Return user given login email, password and other form parameters (e.g. name) # # The specific_user_login parameter says that login as a particular user is # expected, so no parallel registration form is being displayed. def self.authenticate_from_form(params, specific_user_login = false) if specific_user_login auth_fail_message = "Either the email or password was not recognised, please try again." else auth_fail_message = "Either the email or password was not recognised, please try again. Or create a new account using the form on the right." end user = self.find_user_by_email(params[:email]) if user # There is user with email, check password expected_password = encrypted_password(params[:password], user.salt) if user.hashed_password != expected_password user.errors.add_to_base(auth_fail_message) end else # No user of same email, make one (that we don't save in the database) # for the forms code to use. user = User.new(params) # deliberately same message as above so as not to leak whether registered user.errors.add_to_base(auth_fail_message) end user end # Case-insensitively find a user from their email def self.find_user_by_email(email) return self.find(:first, :conditions => [ 'email ilike ?', email ] ) # using ilike for case insensitive end # When name is changed, also change the url name def name=(name) write_attribute(:name, name) self.update_url_name end def update_url_name url_name = MySociety::Format.simplify_url_part(self.name) if url_name.size > 32 url_name = url_name[0..31] end # For request with same name as others, tag on the request numeric id while not User.find_by_url_name(url_name, :conditions => self.id.nil? ? nil : ["id <> ?", self.id] ).nil? url_name += "_" + self.id.to_s end write_attribute(:url_name, url_name) end # Virtual password attribute, which stores the hashed password, rather than plain text. def password @password end def password=(pwd) @password = pwd if pwd.blank? self.hashed_password = nil return end create_new_salt self.hashed_password = User.encrypted_password(self.password, self.salt) end # For use in to/from in email messages def name_and_email return self.name + " <" + self.email + ">" end private def self.encrypted_password(password, salt) string_to_hash = password + salt # XXX need to add a secret here too? Digest::SHA1.hexdigest(string_to_hash) end def create_new_salt self.salt = self.object_id.to_s + rand.to_s end end