* Benjamin Mako Hill <mako@atdot.cc>
* John Dong <jdong@ubuntu.com>
* Justin Sharps <jlsharps@mit.edu>
+
+07/31/07
+jlsharps: I've added a user authentication system known as
+"acts_as_authenticated" to the code. The plugin is the the vendor/plugins
+directory. The two most noticeable changes are the AccountController and a
+redone User model. I've left the UserController in place for now, but the
+AccountController works in a different manner, so am switching over to that
+gradually. I saved the 5 lines or so in the old User model, overwrote
+it with the authenticated generator and then recopied the old stuff back in:
+has_many :elections and the name() method. The generator also creates its own
+migration file, but since we are using a create.sql file I adopted the
+migration file into a new users table in the create.sql file. I have yet to
+delete the old table because I haven't fully combed through the code yet and
+determined how many of the old attributes (such as first_name, last_name) may
+need to be retained.
+http://technoweenie.stikipad.com/plugins/show/Acts+as+Authenticated is the
+best site for documentation regarding acts_as_authenticaed. Also, currently
+it only stores the user_id in the session, but i just found a guide to help
+me make it store the entire user object, so I'll do that while my battery
+charges.
\ No newline at end of file
@voter = nil
end
- # if the voter does not exist or as has been destroyed, lets
+ # if the voter does not exist or has has been destroyed, lets
# create a new one
unless @voter
# create a new voter and populate it
class SiteController < ApplicationController
layout 'hc'
- model :user, :election
+ model :user, :election, :account
def index
@quickvotes = QuickVote.find_all(["quickvote = 1"]).sort {|a,b| b.enddate <=> a.enddate}[0..1]
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
- include LoginEngine
+
end
+require 'digest/sha1'
class User < ActiveRecord::Base
has_many :elections
+ # Virtual attribute for the unencrypted password
+ attr_accessor :password
+
+ validates_presence_of :login, :email
+ validates_presence_of :password, :if => :password_required?
+ validates_presence_of :password_confirmation, :if => :password_required?
+ validates_length_of :password, :within => 4..40, :if => :password_required?
+ validates_confirmation_of :password, :if => :password_required?
+ validates_length_of :login, :within => 3..40
+ validates_length_of :email, :within => 3..100
+ validates_uniqueness_of :login, :email, :case_sensitive => false
+ before_save :encrypt_password
+
def name
- [ firstname, lastname].join(" ")
+ [ firstname, lastname].join(" ")
+ end
+
+ # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
+ def self.authenticate(login, password)
+ u = find_by_login(login) # need to get the salt
+ u && u.authenticated?(password) ? u : nil
+ end
+
+ # Encrypts some data with the salt.
+ def self.encrypt(password, salt)
+ Digest::SHA1.hexdigest("--#{salt}--#{password}--")
+ end
+
+ # Encrypts the password with the user salt
+ def encrypt(password)
+ self.class.encrypt(password, salt)
end
-end
+ def authenticated?(password)
+ crypted_password == encrypt(password)
+ end
+
+ def remember_token?
+ remember_token_expires_at && Time.now.utc < remember_token_expires_at
+ end
+
+ # These create and unset the fields required for remembering users between browser closes
+ def remember_me
+ self.remember_token_expires_at = 2.weeks.from_now.utc
+ self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
+ save(false)
+ end
+
+ def forget_me
+ self.remember_token_expires_at = nil
+ self.remember_token = nil
+ save(false)
+ end
+
+ protected
+ # before filter
+ def encrypt_password
+ return if password.blank?
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
+ self.crypted_password = encrypt(password)
+ end
+
+ def password_required?
+ crypted_password.blank? || !password.blank?
+ end
+end
<div id="links">
<% if session[:user] %>
- Welcome <strong><%= session[:user].login.capitalize %></strong>
+<% breakpoint%>
+ Welcome <strong><%= User.find(session[:user]).login.capitalize %></strong>
<% else %>
- <%= link_to("Login",:controller => "user", :action => "login")
- %>/<%= link_to("Sign up", :controller => "user", :action => "signup")%>
+ <%= link_to("Login", :controller => "account", :action => "login")
+ %>/<%= link_to("Sign up", :controller => "account", :action => "signup")%>
<% end %> |
<% if session[:user] %>
- <%= link_to("Logout", :controller => "user", :action => "logout") %> |
+ <%= link_to("Logout", :controller => "account", :action => "logout") %> |
<% end %>
<%= link_to("Help/About", :controller => "site", :action => "about") %>
<% -%>
- <%= start_form_tag :controller => 'user', :action => 'login' %>
+ <% form_tag :controller => 'account', :action => 'login' do %>
<table>
- <%= form_input :text_field, "Login ID", "login", :size => 30 %>
- <%= form_input :password_field, "Password", "password", :size => 30 %>
+ <label for="login">Login</label>
+ <%= text_field "Login", "login", :size => 30 %><br />
+ <label for="password">Password</label>
+ <%= password_field "Password", "password", :size => 30 %><br />
</table>
<div class="button-bar">
<p><%= submit_tag 'Login' %></p>
-<!-- <p><%= link_to 'Register for an account', :controller =>
-'user', :action => 'signup' %></p> -->
- <p><%= link_to 'Lost or forgot your password?', :controller => 'user', :action => 'forgot_password' %></p>
+<% end %>
+ <p><%= link_to 'Register for an account', :controller =>
+'account', :action => 'signup' %></p>
+
+ <p><%= link_to 'Lost or forgot your password?', :controller => 'account', :action => 'forgot_password' %></p>
<p>Unfortunately, Selectricity is currently being tested and new
accounts for full votes (i.e., non-<em>QuickVotes</em>) can not
href="http://mako.cc/contact.html">Benjamin Mako Hill</a>.</p>
</div>
- <%= end_form_tag %>
+
# CREATE users TABLE
#####################################
-DROP TABLE IF EXISTS `users`;
-CREATE TABLE `users` (
- `id` int(11) NOT NULL auto_increment,
- `login` varchar(80) NOT NULL default '',
- `salted_password` varchar(40) NOT NULL default '',
- `email` varchar(60) NOT NULL default '',
- `firstname` varchar(40) default NULL,
- `lastname` varchar(40) default NULL,
- `salt` varchar(40) NOT NULL default '',
- `verified` int(11) default '0',
- `role` varchar(40) default NULL,
- `security_token` varchar(40) default NULL,
- `token_expiry` datetime default NULL,
- `created_at` datetime default NULL,
- `updated_at` datetime default NULL,
- `logged_in_at` datetime default NULL,
- `deleted` int(11) default '0',
- `delete_after` datetime default NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+#DROP TABLE IF EXISTS `users`;
+#CREATE TABLE `users` (
+# `id` int(11) NOT NULL auto_increment,
+# `login` varchar(80) NOT NULL default '',
+# `salted_password` varchar(40) NOT NULL default '',
+# `email` varchar(60) NOT NULL default '',
+# `firstname` varchar(40) default NULL,
+# `lastname` varchar(40) default NULL,
+# `salt` varchar(40) NOT NULL default '',
+# `verified` int(11) default '0',
+# `role` varchar(40) default NULL,
+# `security_token` varchar(40) default NULL,
+# `token_expiry` datetime default NULL,
+# `created_at` datetime default NULL,
+# `updated_at` datetime default NULL,
+# `logged_in_at` datetime default NULL,
+# `deleted` int(11) default '0',
+# `delete_after` datetime default NULL,
+# PRIMARY KEY (`id`)
+#) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+#Following is the new users table that goes with acts_as_authenticated
+#Is simpler for now, saving the old table while in transition between
+#the two for ideas on what attributes may be helpful/necessary
+drop table if exists users;
+create table users (
+ id int not null auto_increment,
+ login text,
+ ip text not null,
+ email text,
+ crypted_password varchar(40),
+ salt varchar(40),
+ created_at datetime,
+ updated_at datetime,
+ remember_token text,
+ remember_token_expires_at datetime,
+ primary key(id)
+);
\ No newline at end of file