Add authentication and User model

* Add User model
* Add SessionsController
* Add password authentication on User
* Request authentication for all actions except sign in
* Add some helpers for ApplicationController
* Update features to work with mandatory authentication
This commit is contained in:
Thibault Jouan 2011-08-04 09:50:17 +00:00
parent 18b254e3d1
commit 7bf4d4c5f9
22 changed files with 276 additions and 3 deletions

View File

@ -1,3 +1,19 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
protect_from_forgery protect_from_forgery
before_filter :authenticate!
def current_user=(user)
session[:user_id] = user.id
end
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
protected
def authenticate!
redirect_to new_session_path if current_user.nil?
end
end end

View File

@ -0,0 +1,16 @@
class SessionsController < ApplicationController
skip_before_filter :authenticate!, :only => [:new, :create]
def create
user = User.authenticate(
params[:session][:email],
params[:session][:password]
)
if ! user
render 'new'
else
self.current_user = user
redirect_to :root
end
end
end

2
app/models/session.rb Normal file
View File

@ -0,0 +1,2 @@
class Session < ActiveRecord::Base
end

11
app/models/user.rb Normal file
View File

@ -0,0 +1,11 @@
class User < ActiveRecord::Base
validates_presence_of :email
validates_presence_of :password
def self.authenticate(email, password)
user = find_by_email(email)
return false if user.nil?
#FIXME use bcrypt
return user if user.password == password
end
end

View File

@ -0,0 +1,6 @@
= form_for(:session, :url => sessions_path) do |f|
= f.label :email
= f.text_field :email
= f.label :password
= f.password_field :password
= f.submit 'Sign in'

View File

@ -1,4 +1,6 @@
Scube::Application.routes.draw do Scube::Application.routes.draw do
resources :sessions, :only => [:new, :create]
resources :tracks do resources :tracks do
get 'stream', :on => :member get 'stream', :on => :member
end end

View File

@ -0,0 +1,14 @@
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :email
t.string :password
t.timestamps
end
end
def self.down
drop_table :users
end
end

View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20110804225816) do ActiveRecord::Schema.define(:version => 20110805201426) do
create_table "playlists", :force => true do |t| create_table "playlists", :force => true do |t|
t.string "name" t.string "name"
@ -36,4 +36,11 @@ ActiveRecord::Schema.define(:version => 20110804225816) do
t.string "sha256" t.string "sha256"
end end
create_table "users", :force => true do |t|
t.string "email"
t.string "password"
t.datetime "created_at"
t.datetime "updated_at"
end
end end

View File

@ -4,6 +4,9 @@ Feature: Home
As a listener As a listener
I want to access the main features and valuable content from the homepage I want to access the main features and valuable content from the homepage
Background:
Given I am signed in
Scenario: Playlist access Scenario: Playlist access
Given a playlist named "Electro" Given a playlist named "Electro"
When I am on the home page When I am on the home page

View File

@ -4,6 +4,9 @@ Feature: Playlists
As a listener As a listener
I want to manage some playlists I want to manage some playlists
Background:
Given I am signed in
Scenario: List playlists Scenario: List playlists
Given a playlist named "Electro" Given a playlist named "Electro"
And a playlist named "Reggae" And a playlist named "Reggae"

17
features/sessions.feature Normal file
View File

@ -0,0 +1,17 @@
Feature: User
So that I can manage my own content
As a listener
I want the application to require a valid authentication
Scenario: Unauthenticated user
Given I am not signed in
When I go to the home page
Then I should be redirected to the sign in page
Scenario: User authentication
Given I am not signed in
When I go to the home page
Then I should be redirected to the sign in page
When I submit valid credentials
Then I should be redirected to the home page

View File

@ -0,0 +1,26 @@
Given /^I am not signed in$/ do
end
Given /^I am signed in$/ do
user = Factory.create(:user)
visit new_session_path
fill_in('Email', :with => user.email)
fill_in('Password', :with => user.password)
click_button('Sign in')
end
Then /^I should be redirected to the sign in page$/ do
current_path.should == new_session_path
end
Then /^I should be redirected to the home page$/ do
current_path.should == root_path
end
When /^I submit valid credentials$/ do
user = Factory.create(:user)
fill_in('Email', :with => user.email)
fill_in('Password', :with => user.password)
click_button('Sign in')
end

View File

@ -16,6 +16,5 @@ end
Then /^it should provide an audio stream for "([^"]*)"$/ do |name| Then /^it should provide an audio stream for "([^"]*)"$/ do |name|
page.should have_xpath "//audio[@src='#{stream_track_path(@track)}']" page.should have_xpath "//audio[@src='#{stream_track_path(@track)}']"
get find('audio')[:src] visit find('audio')[:src]
last_response.status.should == 200
end end

View File

@ -4,6 +4,9 @@ Feature: Tracks
As a listener As a listener
I want to add, manage and listen some tracks I want to add, manage and listen some tracks
Background:
Given I am signed in
Scenario: Show track Scenario: Show track
Given a track named "Mega song" Given a track named "Mega song"
When I go to the track page for "Mega song" When I go to the track page for "Mega song"

View File

@ -0,0 +1,21 @@
require 'spec_helper'
describe ApplicationController do
let(:user) { Factory.create(:user) }
describe '#current_user=' do
it 'stores the user id in the session as :user_id' do
controller.current_user = user
session[:user_id].should == user.id
end
end
describe '#current_user' do
context 'when session[:user_id] is set' do
it 'returns the User instance from the session' do
session[:user_id] = user.id
controller.current_user.should == user
end
end
end
end

View File

@ -1,6 +1,10 @@
require 'spec_helper' require 'spec_helper'
describe HomeController do describe HomeController do
before do
controller.current_user = Factory.create(:user)
end
describe 'GET index' do describe 'GET index' do
it 'assigns all playlists as @playlists' do it 'assigns all playlists as @playlists' do
playlist = Factory.create(:playlist) playlist = Factory.create(:playlist)

View File

@ -1,6 +1,10 @@
require 'spec_helper' require 'spec_helper'
describe PlaylistsController do describe PlaylistsController do
before do
controller.current_user = Factory.create(:user)
end
describe 'GET index' do describe 'GET index' do
it 'assigns all playlists as @playlists' do it 'assigns all playlists as @playlists' do
playlist = Factory.create(:playlist) playlist = Factory.create(:playlist)

View File

@ -0,0 +1,40 @@
require 'spec_helper'
describe SessionsController do
describe 'GET new' do
it 'responds successfully' do
response.should be_success
end
end
describe 'POST create' do
context 'when the user submit invalid credentials' do
it 'renders the new template' do
User.stub(:authenticate).and_return(false)
post :create,
:session => Factory.attributes_for(:user, :password => 'WRONG')
response.should render_template('new')
end
end
context 'when the user submit valid credentials' do
let(:user) { Factory.create(:user) }
before do
User.stub(:authenticate).and_return(user)
end
it 'signs the user in' do
post :create, :session => Factory.attributes_for(:user)
controller.current_user.should == user
end
it 'redirects to the home page' do
post :create, :session => Factory.attributes_for(:user)
response.should redirect_to(:root)
end
end
end
describe 'DELETE destroy' do
end
end

View File

@ -1,6 +1,10 @@
require 'spec_helper' require 'spec_helper'
describe TracksController do describe TracksController do
before do
controller.current_user = Factory.create(:user)
end
describe 'GET show' do describe 'GET show' do
it 'assigns the requested track as @track' do it 'assigns the requested track as @track' do
track = Factory.create(:track) track = Factory.create(:track)

View File

@ -8,4 +8,9 @@ FactoryGirl.define do
mime_type 'audio/ogg' mime_type 'audio/ogg'
sha256 '94a5486a69a7261da350c57f9e5a1eaa789e08752cfc56a1989976a6ad82f7a8' sha256 '94a5486a69a7261da350c57f9e5a1eaa789e08752cfc56a1989976a6ad82f7a8'
end end
factory :user do
email 'alice@example.net'
password '733tP4s5'
end
end end

44
spec/models/user_spec.rb Normal file
View File

@ -0,0 +1,44 @@
require 'spec_helper'
describe User do
subject { user }
let(:user) { Factory.build(:user) }
context 'with valid attributes' do
it { should be_valid }
end
context 'when email empty' do
before do
user.email = ''
end
it { should_not be_valid }
end
context 'when password empty' do
before do
user.password = ''
end
it { should_not be_valid }
end
describe '.authenticate' do
let (:user) { Factory.create(:user) }
it 'returns the user with valid credentials' do
User.authenticate(
user.email,
user.password
).should == user
end
it 'returns false with invalid credentials' do
User.authenticate(
user.email,
'WRONG'
).should be_false
end
end
end

View File

@ -0,0 +1,26 @@
require 'spec_helper'
describe 'sessions/new.html.haml' do
it 'renders a form to sign in' do
render
rendered.should \
have_selector("form[method=post][action='#{sessions_path}']")
rendered.should have_selector('input[type=submit]')
end
it 'renders a text field with a label for the mail address' do
render
rendered.should \
have_selector("input[type=text][name='session[email]']")
rendered.should \
have_selector('label[for=session_email]', :text => 'Email')
end
it 'renders a password field with a label for the password' do
render
rendered.should \
have_selector("input[type=password][name='session[password]']")
rendered.should \
have_selector('label[for=session_password]', :text => 'Password')
end
end