From 942d6c5b97e90c2c9036d1ec776ca98584e5be8f Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Wed, 11 Mar 2009 12:24:28 +0000 Subject: [PATCH] Finished chapter 11 --- app/controllers/admin_controller.rb | 27 +++++++ app/controllers/application.rb | 11 +++ app/controllers/store_controller.rb | 18 +++-- app/controllers/users_controller.rb | 90 +++++++++++++++++++++++ app/helpers/admin_helper.rb | 2 + app/helpers/users_helper.rb | 2 + app/models/user.rb | 55 ++++++++++++++ app/views/admin/index.html.erb | 4 + app/views/admin/login.html.erb | 19 +++++ app/views/admin/logout.html.erb | 2 + app/views/layouts/orders.html.erb | 17 ----- app/views/layouts/products.html.erb | 17 ----- app/views/layouts/store.html.erb | 18 ++++- app/views/users/edit.html.erb | 31 ++++++++ app/views/users/index.html.erb | 20 +++++ app/views/users/new.html.erb | 30 ++++++++ app/views/users/show.html.erb | 18 +++++ config/routes.rb | 6 ++ db/migrate/20090311105014_create_users.rb | 15 ++++ db/schema.rb | 10 ++- test/fixtures/users.yml | 11 +++ test/functional/admin_controller_test.rb | 8 ++ test/functional/users_controller_test.rb | 45 ++++++++++++ test/unit/user_test.rb | 8 ++ 24 files changed, 441 insertions(+), 43 deletions(-) create mode 100644 app/controllers/admin_controller.rb create mode 100644 app/controllers/users_controller.rb create mode 100644 app/helpers/admin_helper.rb create mode 100644 app/helpers/users_helper.rb create mode 100644 app/models/user.rb create mode 100644 app/views/admin/index.html.erb create mode 100644 app/views/admin/login.html.erb create mode 100644 app/views/admin/logout.html.erb delete mode 100644 app/views/layouts/orders.html.erb delete mode 100644 app/views/layouts/products.html.erb create mode 100644 app/views/users/edit.html.erb create mode 100644 app/views/users/index.html.erb create mode 100644 app/views/users/new.html.erb create mode 100644 app/views/users/show.html.erb create mode 100644 db/migrate/20090311105014_create_users.rb create mode 100644 test/fixtures/users.yml create mode 100644 test/functional/admin_controller_test.rb create mode 100644 test/functional/users_controller_test.rb create mode 100644 test/unit/user_test.rb diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb new file mode 100644 index 0000000..ade35e4 --- /dev/null +++ b/app/controllers/admin_controller.rb @@ -0,0 +1,27 @@ +class AdminController < ApplicationController + def login + session[:user_id] = nil + if request.post? + user = User.authenticate(params[:name], params[:password]) + if user + session[:user_id] = user.id + uri = session[:original_uri] + session[:original_uri] = nil + redirect_to uri || {:action => 'index'} + else + flash.now[:notice] = "Invalid user/password combination" + end + end + end + + def logout + session[:user_id] = nil + flash[:notice] = "Logged out" + redirect_to(:action => "login") + end + + def index + @total_orders = Order.count + end + +end diff --git a/app/controllers/application.rb b/app/controllers/application.rb index fea87e2..fe5e101 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -2,6 +2,8 @@ # Likewise, all the methods added will be available for all controllers. class ApplicationController < ActionController::Base + layout "store" + before_filter :authorize, :except => :login helper :all # include all helpers, all the time # See ActionController::RequestForgeryProtection for details @@ -12,4 +14,13 @@ class ApplicationController < ActionController::Base # Uncomment this to filter the contents of submitted sensitive data parameters # from your application log (in this case, all fields with names like "password"). # filter_parameter_logging :password + + protected + def authorize + unless User.find_by_id(session[:user_id]) + session[:original_uri] = request.request_uri + flash[:notice] = "Please log in" + redirect_to :controller => 'admin', 'action' => 'login' + end + end end diff --git a/app/controllers/store_controller.rb b/app/controllers/store_controller.rb index 68939e6..4c13d34 100644 --- a/app/controllers/store_controller.rb +++ b/app/controllers/store_controller.rb @@ -1,12 +1,14 @@ class StoreController < ApplicationController + before_filter :find_cart, :except => :empty_cart + def index @products = Product.find_products_for_sale - @cart = find_cart +# @cart = find_cart end def add_to_cart product = Product.find(params[:id]) - @cart = find_cart +# @cart = find_cart @current_item = @cart.add_product(product) respond_to do |format| format.js if request.xhr? @@ -23,7 +25,7 @@ class StoreController < ApplicationController end def checkout - @cart = find_cart +# @cart = find_cart if @cart.items.empty? redirect_to_index("Your cart is empty" ) else @@ -37,7 +39,7 @@ class StoreController < ApplicationController end def save_order - @cart = find_cart +# @cart = find_cart @order = Order.new(params[:order]) # @order.add_line_items_from_cart(@cart) @cart.items.each do |item| @@ -57,10 +59,16 @@ class StoreController < ApplicationController end +protected + + # No authorization needed for the store + def authorize + end + private def find_cart - session[:cart] ||= Cart.new + @cart = (session[:cart] ||= Cart.new) end def redirect_to_index(msg = nil) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..9587740 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,90 @@ +class UsersController < ApplicationController + # GET /users + # GET /users.xml + def index + @users = User.find(:all, :order => :name) + + respond_to do |format| + format.html # index.html.erb + format.xml { render :xml => @users } + end + end + + # GET /users/1 + # GET /users/1.xml + def show + @user = User.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.xml { render :xml => @user } + end + end + + # GET /users/new + # GET /users/new.xml + def new + @user = User.new + + respond_to do |format| + format.html # new.html.erb + format.xml { render :xml => @user } + end + end + + # GET /users/1/edit + def edit + @user = User.find(params[:id]) + end + + # POST /users + # POST /users.xml + def create + @user = User.new(params[:user]) + + respond_to do |format| + if @user.save + flash[:notice] = "User #{@user.name} was successfully created." + format.html { redirect_to(:action => 'index') } + format.xml { render :xml => @user, :status => :created, :location => @user } + else + format.html { render :action => "new" } + format.xml { render :xml => @user.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /users/1 + # PUT /users/1.xml + def update + @user = User.find(params[:id]) + + respond_to do |format| + if @user.update_attributes(params[:user]) + flash[:notice] = "User #{@user.name} was successfully updated." + format.html { redirect_to(:action => 'index') } + format.xml { head :ok } + else + format.html { render :action => "edit" } + format.xml { render :xml => @user.errors, :status => :unprocessable_entity } + end + end + end + + # DELETE /users/1 + # DELETE /users/1.xml + def destroy + @user = User.find(params[:id]) + begin + flash[:notice] = "User #{@user.name} deleted" + @user.destroy + rescue Exception => e + flash[:notice] = e.message + end + + respond_to do |format| + format.html { redirect_to(users_url) } + format.xml { head :ok } + end + end +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb new file mode 100644 index 0000000..d5c6d35 --- /dev/null +++ b/app/helpers/admin_helper.rb @@ -0,0 +1,2 @@ +module AdminHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..c58f344 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,55 @@ +require 'digest/sha1' + +class User < ActiveRecord::Base + validates_presence_of :name + validates_uniqueness_of :name + + attr_accessor :password_confirmation + validates_confirmation_of :password + + validate :password_non_blank + + def password + @password + end + + def password=(passwd) + @password = passwd + return if passwd.blank? + create_new_salt + self.hashed_password = User.encrypted_password(self.password, self.salt) + end + + def self.authenticate(name, password) + user = self.find_by_name(name) + if user + expected_password = encrypted_password(password, user.salt) + if user.hashed_password != expected_password + user = nil + end + end + user + end + + def after_destroy + if User.count.zero? + raise "Can't delete last user" + end + end + +private + + def password_non_blank + errors.add(:password, "Missing password" ) if hashed_password.blank? + end + + def self.encrypted_password(password, salt) + string_to_hash = password + 'wibble' + salt + Digest::SHA1.hexdigest string_to_hash + end + + def create_new_salt + self.salt = self.object_id.to_s + rand.to_s + end + +end diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb new file mode 100644 index 0000000..ec658d4 --- /dev/null +++ b/app/views/admin/index.html.erb @@ -0,0 +1,4 @@ + +

Welcome, <%= User.find(session[:user_id]).name %>

+It's <%= Time.now %>. +We have <%= pluralize(@total_orders, "order" ) %>. \ No newline at end of file diff --git a/app/views/admin/login.html.erb b/app/views/admin/login.html.erb new file mode 100644 index 0000000..61c40a1 --- /dev/null +++ b/app/views/admin/login.html.erb @@ -0,0 +1,19 @@ + +
+ <% form_tag do %> +
+ Please Log In +
+ + <%= text_field_tag :name, params[:name] %> +
+
+ + <%= password_field_tag :password, params[:password] %> +
+
+ <%= submit_tag "Login" %> +
+
+ <% end %> +
\ No newline at end of file diff --git a/app/views/admin/logout.html.erb b/app/views/admin/logout.html.erb new file mode 100644 index 0000000..f3e955c --- /dev/null +++ b/app/views/admin/logout.html.erb @@ -0,0 +1,2 @@ +

Admin#logout

+

Find me in app/views/admin/logout.html.erb

diff --git a/app/views/layouts/orders.html.erb b/app/views/layouts/orders.html.erb deleted file mode 100644 index ee970df..0000000 --- a/app/views/layouts/orders.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Orders: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

<%= flash[:notice] %>

- -<%= yield %> - - - diff --git a/app/views/layouts/products.html.erb b/app/views/layouts/products.html.erb deleted file mode 100644 index 07fed7f..0000000 --- a/app/views/layouts/products.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Products: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold', 'depot' %> - - - -

<%= flash[:notice] %>

- -<%= yield %> - - - diff --git a/app/views/layouts/store.html.erb b/app/views/layouts/store.html.erb index b1f928e..e4845d7 100644 --- a/app/views/layouts/store.html.erb +++ b/app/views/layouts/store.html.erb @@ -14,13 +14,25 @@
- <% hidden_div_if(@cart.items.empty?, :id => "cart") do %> - <%= render(:partial => "cart" , :object => @cart) %> - <% end %> + <% if @cart %> + <% hidden_div_if(@cart.items.empty?, :id => "cart") do %> + <%= render(:partial => "cart" , :object => @cart) %> + <% end %> + <% end %> Home
Questions
News
Contact
+ + <% if session[:user_id] %> +
+ <%= link_to 'Orders', :controller => 'orders' %>
+ <%= link_to 'Products', :controller => 'products' %>
+ <%= link_to 'Users', :controller => 'users' %>
+
+ <%= link_to 'Logout', :controller => 'admin', :action => 'logout' %> + <% end %> +
<% if flash[:notice] -%> diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 0000000..52e9ee2 --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,31 @@ +
+ + <% form_for(@user) do |f| %> + <%= f.error_messages %> + +
+ Update user details + +
+ <%= f.label :name %>: + <%= f.text_field :name, :size => 40 %> +
+ +
+ <%= f.label :user_password, 'Password' %>: + <%= f.password_field :password, :size => 40 %> +
+
+ <%= f.label :user_password_confirmation, 'Confirm' %>: + <%= f.password_field :password_confirmation, :size => 40 %> +
+
+ <%= f.submit "Update" %> +
+ +
+ <% end %> + + <%= link_to 'Show', @user %> | + <%= link_to 'Back', users_path %> +
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb new file mode 100644 index 0000000..a2311a5 --- /dev/null +++ b/app/views/users/index.html.erb @@ -0,0 +1,20 @@ +

Listing users

+ + + + + + +<% for user in @users %> + + + + + + +<% end %> +
Name
<%=h user.name %><%= link_to 'Show', user %><%= link_to 'Edit', edit_user_path(user) %><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %>
+ +
+ +<%= link_to 'New user', new_user_path %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..eaefc60 --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,30 @@ +
+ + <% form_for(@user) do |f| %> + <%= f.error_messages %> + +
+ Enter user details + +
+ <%= f.label :name %>: + <%= f.text_field :name, :size => 40 %> +
+ +
+ <%= f.label :user_password, 'Password' %>: + <%= f.password_field :password, :size => 40 %> +
+
+ <%= f.label :user_password_confirmation, 'Confirm' %>: + <%= f.password_field :password_confirmation, :size => 40 %> +
+
+ <%= f.submit "Create" %> +
+ +
+ <% end %> + + <%= link_to 'Back', users_path %> +
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 0000000..fc47069 --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,18 @@ +

+ Name: + <%=h @user.name %> +

+ +

+ Hashed password: + <%=h @user.hashed_password %> +

+ +

+ Salt: + <%=h @user.salt %> +

+ + +<%= link_to 'Edit', edit_user_path(@user) %> | +<%= link_to 'Back', users_path %> diff --git a/config/routes.rb b/config/routes.rb index 13bc70e..eef2afc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,10 @@ ActionController::Routing::Routes.draw do |map| + map.resources :users + + map.resources :line_items + + map.resources :orders + map.resources :products # The priority is based upon order of creation: first created -> highest priority. diff --git a/db/migrate/20090311105014_create_users.rb b/db/migrate/20090311105014_create_users.rb new file mode 100644 index 0000000..400d8da --- /dev/null +++ b/db/migrate/20090311105014_create_users.rb @@ -0,0 +1,15 @@ +class CreateUsers < ActiveRecord::Migration + def self.up + create_table :users do |t| + t.string :name + t.string :hashed_password + t.string :salt + + t.timestamps + end + end + + def self.down + drop_table :users + end +end diff --git a/db/schema.rb b/db/schema.rb index d017a09..6b870e1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20090304153613) do +ActiveRecord::Schema.define(:version => 20090311105014) do create_table "line_items", :force => true do |t| t.integer "product_id", :null => false @@ -53,4 +53,12 @@ ActiveRecord::Schema.define(:version => 20090304153613) do add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id" add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at" + create_table "users", :force => true do |t| + t.string "name" + t.string "hashed_password" + t.string "salt" + t.datetime "created_at" + t.datetime "updated_at" + end + end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..ccf5bd1 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +one: + name: MyString + hashed_password: MyString + salt: MyString + +two: + name: MyString + hashed_password: MyString + salt: MyString diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb new file mode 100644 index 0000000..9bbf29b --- /dev/null +++ b/test/functional/admin_controller_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class AdminControllerTest < ActionController::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb new file mode 100644 index 0000000..c4a4804 --- /dev/null +++ b/test/functional/users_controller_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' + +class UsersControllerTest < ActionController::TestCase + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:users) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create user" do + assert_difference('User.count') do + post :create, :user => { } + end + + assert_redirected_to user_path(assigns(:user)) + end + + test "should show user" do + get :show, :id => users(:one).id + assert_response :success + end + + test "should get edit" do + get :edit, :id => users(:one).id + assert_response :success + end + + test "should update user" do + put :update, :id => users(:one).id, :user => { } + assert_redirected_to user_path(assigns(:user)) + end + + test "should destroy user" do + assert_difference('User.count', -1) do + delete :destroy, :id => users(:one).id + end + + assert_redirected_to users_path + end +end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb new file mode 100644 index 0000000..a64d2d3 --- /dev/null +++ b/test/unit/user_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end -- 2.34.1