3 # A User is used to validate people trying to log in.
4 # Users can have downloads, create files and folders
5 # and belong to a group.
6 # A user's plain text password is not accessible.
7 # Therefore passwords are hashed before they are stored.
8 class User < ActiveRecord::Base
9 has_and_belongs_to_many :groups
10 has_many :usages, :dependent => :destroy
11 has_many :myfiles, :dependent => :nullify
12 has_many :folders, :dependent => :nullify
14 # The password_required field, which determines if
15 # the presence of a password has to be checked
16 attr_accessor :password_required
18 # We never allow the hashed password to be set from a form
19 attr_accessible :name, :email, :password, :password_confirmation, :password_required
21 validates_confirmation_of :password
22 validates_uniqueness_of :name, :email
23 validates_presence_of :name, :email
24 validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/
26 # Validates if the data for this user is valid.
28 # Only validate the presence of a password when it's required
29 if self.password_required and self.password.blank?
30 errors.add(:password, " can't be blank")
40 def password=(new_password)
41 @password = new_password
42 unless @password.blank?
43 salt = User.random_password(6) # whenever the password is set, a new random salt is set too
44 self.password_salt = salt
45 self.hashed_password = User.hash_password(@password + salt)
49 # Return the User with the given name and plain-text password.
50 def self.login(name, password)
51 user = User.find_by_name(name)
52 if (not user.blank?) and (user.hashed_password == User.hash_password(password + user.password_salt))
59 before_create :generate_rss_access_key
60 # Generates an access key for the RSS feeds.
61 def generate_rss_access_key
62 self.rss_access_key = User.random_password(36)
65 before_destroy :dont_destroy_admin
66 # Don't delete 'admin' from the database.
67 def dont_destroy_admin
68 raise "Can't delete admin" if self.is_the_administrator?
71 after_save :clear_plain_text_password
72 # Clear out the plain-text password. This stops it being made
73 # available in the session
74 def clear_plain_text_password
78 # Hash the given password (and return it)
79 def self.hash_password(password)
80 return Digest::SHA1.hexdigest(password)
83 # Generate a random password of <i>len</i> charachters
84 def self.random_password(len)
85 chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
87 1.upto(len) { |i| random_password << chars[rand(chars.size-1)] }
88 return random_password
91 # Returns whether or not the admin user exists
92 def self.admin_exists?
93 user = User.find_by_is_the_administrator(true)
94 return (not user.blank?)
97 # Creates the admin user (but doesn't save it!)
98 def self.create_admin(email, name, password, password_confirmation)
99 unless User.admin_exists?
103 user.password = password
104 user.password_confirmation = password_confirmation
105 user.is_the_administrator = true
106 user.password_required = true
111 # Generates a new password for the user with the given username
112 # and/or password and mails the password to the user.
113 # Returns an appriopriate error message if the given user does not exists.
114 def self.generate_and_mail_new_password(name, email)
115 # This is the hash that will be returned
118 # Check if the name and/or email are valid
119 if not name.blank? and not email.blank? # The user entered both name and email
120 user = self.find_by_name_and_email(name, email)
122 result['flash'] = 'forgotten_notice'
123 result['message'] = 'Could not find a user with this combination of username and e-mail address'
126 elsif not name.blank? # The user only entered the name
127 user = self.find_by_name(name)
129 result['flash'] = 'forgotten_notice'
130 result['message'] = 'Could not find a user with this username'
133 elsif not email.blank? # The user only entered an e-mail address
134 user = User.find_by_email(email)
136 result['flash'] = 'forgotten_notice'
137 result['message'] = 'Could not find a user with this e-mail address'
140 else # The user didn't enter anything
141 result['flash'] = 'forgotten_notice'
142 result['message'] = 'Please enter a username and/or an e-mail address'
147 # Generate a new password
148 new_password = User.random_password(8)
149 user.password = new_password
151 # Store the new password and try to mail it to the user
153 if PasswordMailer.deliver_forgotten(user.name, user.email, new_password) and user.save
154 result['flash'] = 'login_confirmation'
155 result['message'] = 'A new password has been e-mailed to ' + user.email
157 result['flash'] = 'forgotten_notice'
158 result['message'] = 'Could not create a new password'
160 rescue Exception => e
161 if e.message.match('getaddrinfo: No address associated with nodename')
162 result['flash'] = 'forgotten_notice'
163 result['message'] = "The mail server settings in the environment file are incorrect. Check the installation instructions to solve this problem. Your password hasn't changed yet."
165 result['flash'] = 'forgotten_notice'
166 result['message'] = e.message + ".<br /><br />This means either your e-mail address or Boxroom's configuration for e-mailing is invalid. Please contact the administrator or check the installation instructions. Your password hasn't changed yet."
170 # finally return the result
174 # Returns if the user is member of the admins group or not
176 unless self.groups.find_by_is_the_administrators_group(true).blank?
183 # Use this method to determine if a user is permitted to create in the given folder
184 def can_create(folder_id)
185 self.groups.each do |group|
186 group_permission = group.group_permissions.find_by_folder_id(folder_id)
187 return true unless group_permission.blank? or not group_permission.can_create
192 # Use this method to determine if a user is permitted to read in the given folder
193 def can_read(folder_id)
194 self.groups.each do |group|
195 group_permission = group.group_permissions.find_by_folder_id(folder_id)
196 return true unless group_permission.blank? or not group_permission.can_read
201 # Use this method to determine if a user is permitted to update in the given folder
202 def can_update(folder_id)
203 self.groups.each do |group|
204 group_permission = group.group_permissions.find_by_folder_id(folder_id)
205 return true unless group_permission.blank? or not group_permission.can_update
210 # Use this method to determine if a user is permitted to delete in the given folder
211 def can_delete(folder_id)
212 self.groups.each do |group|
213 group_permission = group.group_permissions.find_by_folder_id(folder_id)
214 return true unless group_permission.blank? or not group_permission.can_delete