require 'digest/sha1' # = The User class # # This is actually based on the user class that is generated # automatically by the Login Generator, but I suspect only software # historians need to know that. The Login Generator is pretty much # universally adapted by anyone writing a Rails application that has # users, and this one is no different. # # From the schema, the data elements of the User class (because # otherwise, they wouldn't be described anywhere). # # +domain+:: The Domain that the user belongs to. # +login+:: The user's username. This is also the name used # for their Sugoi-Mail address. # +password+:: A SHA1-encrypted password hash. # +mailinglist+:: The user's Mailinglist. The addresses listed in # this Mailinglist are the address that any message # sent to +login@domain+ is then forwarded to. # +domainadmin+:: Whether the user is a domain administrator or not. # This mainly controls the ability to create new # users. # +mailinglistadmin+:: Whether they can create, delete, or modify # mailing lists. # # The User's email address is actually provided by the Mailinglist that # belongs to the user. By adding at least one Address to this Mailinglist, # you can forward messages sent to user@sugoi-domain to their real email # address. Any message sent from the user's real address via # sugoi-domain has that real email address rewritten to be the # sugoi-domain address. class User < ActiveRecord::Base #---------------------------------------- # First of all, email address stuff #---------------------------------------- has_many :mailinglists belongs_to :mailinglist belongs_to :domain # The list of addresses that mail sent to the user will be forwarded # to. def addresses; mailinglist.addresses end # The mail proxy email address def address; "#{mailinglist.name}@#{domain.name}" end # def address=(addr); addresses[0]=addr end # The user's "description"--if the user's a person, this would be # their real name. def description if new_record? @description else mailinglist.description end end # Change the user's description. (Actually changes the user's # Mailinglist's description.) def description=(new_description) if new_record? @description = new_description else m=mailinglist m.description = new_description m.save end end # Please change the salt to something else, # Every application should use a different one @@salt = 'thuchpog10.?guf' cattr_accessor :salt # Authenticate a user. # # Example: # @user = User.authenticate('bob', 'bobpass') # def self.authenticate(login, pass) find_by_login_and_password login, sha1(pass) end validates_uniqueness_of :login, :on => :create, :scope => :domain_id # XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX # This really needs to be put *back*, with the proviso that I need to # figure out whether it belongs or not (or whether the mailing list # creation should handle it instead, which is likely the case.) # XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX # validates_each :login, :on => :create do |model, attr, value| # if Mailinglist.find(:first, :conditions => [ "name = ?", value ]) # model.errors.add(attr, "Address already exists: #{value}" ) # end # end validates_confirmation_of :password validates_length_of :login, :within => 2..40 validates_length_of :password, :within => 5..40 validates_presence_of :login, :password, :password_confirmation, :domain, :on => :create def after_create ml=Mailinglist.new ml.name=self.login ml.user_id=self.id ml.mailinglist_class=MailinglistClass.find 1 # XXX MAGIC CONSTANT XXX if @description then ml.description = @description end if ml.save then self.mailinglist=ml return true end end def before_destroy ml=self.mailinglist if ml ml.destroy end self.mailinglist_id = nil end protected # Apply SHA1 encryption to the supplied password. # We will additionally surround the password with a salt # for additional security. def self.sha1(pass) Digest::SHA1.hexdigest("#{salt}--#{pass}--") end before_create :crypt_password # Before saving the record to database we will crypt the password # using SHA1. # We never store the actual password in the DB. def crypt_password write_attribute "password", self.class.sha1(password) end before_update :crypt_unless_empty # If the record is updated we will check if the password is empty. # If its empty we assume that the user didn't want to change his # password and just reset it to the old value. def crypt_unless_empty if password.empty? user = self.class.find(self.id) self.password = user.password else write_attribute "password", self.class.sha1(password) end end end