Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 103
- Log:
The next iteration of Hub. Requires the hubssolib Gem. Stores user
login details in a secure cookie rather than the session, opening up
the potential for cross-application access. Still need to move session
expiry and last-recorded-URL stuff into a cookie, otherwise it's all
done. Many bugs fixed, though some may have been introduced in splitting
functionality into the Gem.No solution presently to whether or not the User object will be understood
or accessible in any way from other applications (not yet tried). Checking
this version in because it's reached a stage of reasonable stability,
before the next step of attempting wider integration.Remember, this won't work at all unless hubssolib 0.0.3 is installed.
- Author:
- adh
- Date:
- Fri Oct 20 19:33:17 +0100 2006
- Size:
- 4347 Bytes
1 | require 'digest/sha1' |
2 | |
3 | class User < ActiveRecord::Base |
4 | belongs_to :member |
5 | before_create :make_activation_code |
6 | |
7 | # Virtual attribute for the unencrypted password |
8 | attr_accessor :password |
9 | |
10 | # Stop mass-assignment of the User model when we do something like |
11 | # "@user = User.new(params[:user])" in the Controller. Someone could |
12 | # build a form which submitted any value for all columns in the User |
13 | # table without this - e.g. they could assign "admin" to "roles". |
14 | # The line below states which attributes are accessible to mass |
15 | # assignment - everything else must be explicitly assigned. |
16 | attr_accessible :email, :real_name, :password, :password_confirmation |
17 | |
18 | validates_presence_of :email, :real_name |
19 | validates_presence_of :password, :if => :password_required? |
20 | validates_presence_of :password_confirmation, :if => :password_required? |
21 | validates_length_of :password, :within => 4..40, :if => :password_required? |
22 | validates_confirmation_of :password, :if => :password_required? |
23 | validates_length_of :email, :within => 3..200 |
24 | validates_length_of :real_name, :within => 3..200 |
25 | validates_uniqueness_of :email, :case_sensitive => false |
26 | before_save :encrypt_password |
27 | |
28 | # Authenticates a user by e-mail address and unencrypted password. Returns the user or nil. |
29 | def self.authenticate(email, password) |
30 | # hide records with a nil activated_at |
31 | u = find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email] |
32 | u && u.authenticated?(password) ? u : nil |
33 | end |
34 | |
35 | # Encrypts some data with the salt. |
36 | def self.encrypt(password, salt) |
37 | Digest::SHA1.hexdigest("--#{salt}--#{password}--") |
38 | end |
39 | |
40 | # Encrypts the password with the user salt |
41 | def encrypt(password) |
42 | self.class.encrypt(password, salt) |
43 | end |
44 | |
45 | def authenticated?(password) |
46 | crypted_password == encrypt(password) |
47 | end |
48 | |
49 | def remember_token? |
50 | remember_token_expires_at && Time.now.utc < remember_token_expires_at |
51 | end |
52 | |
53 | # These create and unset the fields required for remembering users between browser closes |
54 | def remember_me |
55 | self.remember_token_expires_at = 2.weeks.from_now.utc |
56 | self.remember_token = encrypt("#{email}--#{remember_token_expires_at}") |
57 | save(false) |
58 | end |
59 | |
60 | def forget_me |
61 | self.remember_token_expires_at = nil |
62 | self.remember_token = nil |
63 | save(false) |
64 | end |
65 | |
66 | # Activates the user in the database. |
67 | def activate |
68 | @activated = true |
69 | self.activated_at = Time.now.utc |
70 | self.activation_code = nil |
71 | save(false) |
72 | end |
73 | |
74 | # Returns true if the user has just been activated. |
75 | def recently_activated? |
76 | activated = @activated |
77 | @activated = false |
78 | return activated |
79 | end |
80 | |
81 | # Deal with forgotten passwords |
82 | def forgot_password |
83 | self.password_reset_code_expires_at = (Time.now.utc) + RESET_TIME_LIMIT |
84 | self.make_password_reset_code |
85 | save(false) |
86 | @forgotten_password = true |
87 | end |
88 | |
89 | def reset_password |
90 | # First update the password_reset_code before setting the |
91 | # reset_password flag to avoid duplicate email notifications. |
92 | self.password_reset_code_expires_at = nil |
93 | self.password_reset_code = nil |
94 | save(false) |
95 | @reset_password = true |
96 | end |
97 | |
98 | def recently_reset_password? |
99 | reset_password = @reset_password |
100 | @reset_password = false |
101 | return reset_password |
102 | end |
103 | |
104 | def recently_forgot_password? |
105 | forgotten_password = @forgotten_password |
106 | @forgotten_password = false |
107 | return forgotten_password |
108 | end |
109 | |
110 | def destroy |
111 | UserNotifier.deliver_destruction(self) |
112 | super |
113 | end |
114 | |
115 | protected |
116 | # before filter |
117 | def encrypt_password |
118 | return if password.blank? |
119 | self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{email}--") if new_record? |
120 | self.crypted_password = encrypt(password) |
121 | end |
122 | |
123 | def password_required? |
124 | crypted_password.blank? || !password.blank? |
125 | end |
126 | |
127 | # Create a user activation code for activation e-mail messages |
128 | def make_activation_code |
129 | self.activation_code = Digest::SHA1.hexdigest(Time.now.to_s.split(//).sort_by {rand}.join) |
130 | end |
131 | |
132 | # Make a password reset code for users who've forgotten their password |
133 | def make_password_reset_code |
134 | self.password_reset_code = Digest::SHA1.hexdigest(Time.now.to_s.split(//).sort_by {rand}.join) |
135 | end |
136 | end |