spree_bushido_auth 0.60.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +36 -0
  3. data/app/controllers/admin_controller_decorator.rb +7 -0
  4. data/app/controllers/admin_orders_controller_decorator.rb +15 -0
  5. data/app/controllers/admin_resource_controller_decorator.rb +3 -0
  6. data/app/controllers/checkout_controller_decorator.rb +42 -0
  7. data/app/controllers/orders_controller_decorator.rb +17 -0
  8. data/app/controllers/resource_controller_decorator.rb +25 -0
  9. data/app/controllers/spree/base_controller_decorator.rb +49 -0
  10. data/app/controllers/user_passwords_controller.rb +20 -0
  11. data/app/controllers/user_registrations_controller.rb +64 -0
  12. data/app/controllers/user_sessions_controller.rb +58 -0
  13. data/app/controllers/users_controller.rb +54 -0
  14. data/app/helpers/users_helper.rb +13 -0
  15. data/app/models/ability.rb +64 -0
  16. data/app/models/order_decorator.rb +12 -0
  17. data/app/models/spree_auth_configuration.rb +3 -0
  18. data/app/models/spree_current_order_decorator.rb +14 -0
  19. data/app/models/tokenized_permission.rb +3 -0
  20. data/app/models/user.rb +102 -0
  21. data/app/models/user_mailer.rb +13 -0
  22. data/app/views/checkout/registration.html.erb +20 -0
  23. data/app/views/layouts/admin/_login_nav.html.erb +8 -0
  24. data/app/views/shared/_flashes.html.erb +9 -0
  25. data/app/views/shared/_login.html.erb +20 -0
  26. data/app/views/shared/_login_bar.html.erb +6 -0
  27. data/app/views/shared/_user_form.html.erb +17 -0
  28. data/app/views/shared/unauthorized.html.erb +0 -0
  29. data/app/views/user_mailer/reset_password_instructions.text.erb +10 -0
  30. data/app/views/user_passwords/edit.html.erb +15 -0
  31. data/app/views/user_passwords/new.html.erb +13 -0
  32. data/app/views/user_registrations/new.html.erb +23 -0
  33. data/app/views/user_sessions/authorization_failure.html.erb +4 -0
  34. data/app/views/user_sessions/new.html.erb +13 -0
  35. data/app/views/users/edit.html.erb +11 -0
  36. data/app/views/users/show.html.erb +50 -0
  37. data/config/cucumber.yml +10 -0
  38. data/config/initializers/devise.rb +136 -0
  39. data/config/locales/en.yml +46 -0
  40. data/config/routes.rb +28 -0
  41. data/db/migrate/20101026184950_rename_columns_for_devise.rb +39 -0
  42. data/db/migrate/20101214150824_convert_user_remember_field.rb +11 -0
  43. data/db/migrate/20101217012656_create_tokenized_permissions.rb +18 -0
  44. data/db/migrate/20101219201531_tokens_for_legacy_orders.rb +12 -0
  45. data/db/migrate/20110825175814_add_bushido_authenticatable.rb +9 -0
  46. data/db/sample/users.rb +53 -0
  47. data/lib/spree/auth/config.rb +22 -0
  48. data/lib/spree/token_resource.rb +23 -0
  49. data/lib/spree_auth.rb +29 -0
  50. data/lib/spree_auth_hooks.rb +6 -0
  51. data/lib/tasks/auth.rake +8 -0
  52. data/lib/tasks/install.rake +23 -0
  53. metadata +143 -0
@@ -0,0 +1,64 @@
1
+ # Implementation class for Cancan gem. Instead of overriding this class, consider adding new permissions
2
+ # using the special +register_ability+ method which allows extensions to add their own abilities.
3
+ #
4
+ # See http://github.com/ryanb/cancan for more details on cancan.
5
+ class Ability
6
+ include CanCan::Ability
7
+
8
+ class_attribute :abilities
9
+ self.abilities = Set.new
10
+
11
+ # Allows us to go beyond the standard cancan initialize method which makes it difficult for engines to
12
+ # modify the default +Ability+ of an application. The +ability+ argument must be a class that includes
13
+ # the +CanCan::Ability+ module. The registered ability should behave properly as a stand-alone class
14
+ # and therefore should be easy to test in isolation.
15
+ def self.register_ability(ability)
16
+ self.abilities.add(ability)
17
+ end
18
+
19
+ def initialize(user)
20
+ self.clear_aliased_actions
21
+
22
+ # override cancan default aliasing (we don't want to differentiate between read and index)
23
+ alias_action :edit, :to => :update
24
+ alias_action :new, :to => :create
25
+ alias_action :new_action, :to => :create
26
+ alias_action :show, :to => :read
27
+
28
+ user ||= User.new
29
+ if user.has_role? 'admin'
30
+ can :manage, :all
31
+ else
32
+ #############################
33
+ can :read, User do |resource|
34
+ resource == user
35
+ end
36
+ can :update, User do |resource|
37
+ resource == user
38
+ end
39
+ can :create, User
40
+ #############################
41
+ can :read, Order do |order, token|
42
+ order.user == user || order.token && token == order.token
43
+ end
44
+ can :update, Order do |order, token|
45
+ order.user == user || order.token && token == order.token
46
+ end
47
+ can :create, Order
48
+ #############################
49
+ can :read, Product
50
+ can :index, Product
51
+ #############################
52
+ can :read, Taxon
53
+ can :index, Taxon
54
+ #############################
55
+ end
56
+
57
+ #include any abilities registered by extensions, etc.
58
+ Ability.abilities.each do |clazz|
59
+ ability = clazz.send(:new, user)
60
+ @rules = rules + ability.send(:rules)
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,12 @@
1
+ Order.class_eval do
2
+ token_resource
3
+
4
+ # Associates the specified user with the order and destroys any previous association with guest user if
5
+ # necessary.
6
+ def associate_user!(user)
7
+ self.user = user
8
+ self.email = user.email
9
+ # disable validations since this can cause issues when associating an incomplete address during the address step
10
+ save(:validate => false)
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ class SpreeAuthConfiguration < Configuration
2
+ preference :registration_step, :boolean, :default => true
3
+ end
@@ -0,0 +1,14 @@
1
+ Spree::CurrentOrder.module_eval do
2
+
3
+ # Associate the new order with the currently authenticated user before saving
4
+ def before_save_new_order
5
+ @current_order.user ||= current_user
6
+ end
7
+
8
+ def after_save_new_order
9
+ # make sure the user has permission to access the order (if they are a guest)
10
+ return if current_user
11
+ session[:access_token] = @current_order.token
12
+ end
13
+
14
+ end
@@ -0,0 +1,3 @@
1
+ class TokenizedPermission < ActiveRecord::Base
2
+ belongs_to :permissable, :polymorphic => true
3
+ end
@@ -0,0 +1,102 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ if Devise::on_bushido?
4
+ devise :bushido_authenticatable, :trackable
5
+ else
6
+ devise :database_authenticatable, :token_authenticatable, :registerable, :recoverable,
7
+ :rememberable, :trackable, :validatable, :encryptable, :encryptor => "authlogic_sha512"
8
+ end
9
+
10
+ has_many :orders
11
+ has_and_belongs_to_many :roles
12
+ belongs_to :ship_address, :foreign_key => "ship_address_id", :class_name => "Address"
13
+ belongs_to :bill_address, :foreign_key => "bill_address_id", :class_name => "Address"
14
+
15
+ before_save :check_admin
16
+ before_validation :set_login
17
+
18
+ # Setup accessible (or protected) attributes for your model
19
+ attr_accessible :email, :password, :password_confirmation, :remember_me, :persistence_token
20
+
21
+ scope :admin, lambda { includes(:roles).where("roles.name" => "admin") }
22
+ scope :registered, where("users.email NOT LIKE ?", "%@example.net")
23
+
24
+ # has_role? simply needs to return true or false whether a user has a role or not.
25
+ def has_role?(role_in_question)
26
+ roles.any? { |role| role.name == role_in_question.to_s }
27
+ end
28
+
29
+ # Creates an anonymous user. An anonymous user is basically an auto-generated +User+ account that is created for the customer
30
+ # behind the scenes and its completely transparently to the customer. All +Orders+ must have a +User+ so this is necessary
31
+ # when adding to the "cart" (which is really an order) and before the customer has a chance to provide an email or to register.
32
+ def self.anonymous!
33
+ token = User.generate_token(:persistence_token)
34
+ User.create(:email => "#{token}@example.net", :password => token, :password_confirmation => token, :persistence_token => token)
35
+ end
36
+
37
+ def self.admin_created?
38
+ User.admin.count > 0
39
+ end
40
+
41
+ def anonymous?
42
+ email =~ /@example.net$/
43
+ end
44
+
45
+ def deliver_password_reset_instructions!
46
+ reset_perishable_token!
47
+ UserMailer.password_reset_instructions(self).deliver
48
+ end
49
+
50
+ protected
51
+ def password_required?
52
+ !persisted? || password.present? || password_confirmation.present?
53
+ end
54
+
55
+ private
56
+
57
+ def check_admin
58
+ return if self.class.admin_created?
59
+ admin_role = Role.find_or_create_by_name "admin"
60
+ self.roles << admin_role
61
+ end
62
+
63
+ def set_login
64
+ # for now force login to be same as email, eventually we will make this configurable, etc.
65
+ self.login ||= self.email if self.email
66
+ end
67
+
68
+ # Generate a friendly string randomically to be used as token.
69
+ def self.friendly_token
70
+ ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
71
+ end
72
+
73
+ # Generate a token by looping and ensuring does not already exist.
74
+ def self.generate_token(column)
75
+ loop do
76
+ token = friendly_token
77
+ break token unless find(:first, :conditions => { column => token })
78
+ end
79
+ end
80
+
81
+ def self.current
82
+ Thread.current[:user]
83
+ end
84
+
85
+ def self.current=(user)
86
+ Thread.current[:user] = user
87
+ end
88
+
89
+ def bushido_extra_attributes(extra_attributes)
90
+ extra_attributes.each do |name, value|
91
+ case name.to_sym
92
+ when :email
93
+ self.email = value
94
+ # when :first_name
95
+ # self.first_name = value
96
+ # when :last_name
97
+ # self.last_name = value
98
+ end
99
+ end
100
+ end
101
+
102
+ end
@@ -0,0 +1,13 @@
1
+ class UserMailer < ActionMailer::Base
2
+
3
+ def reset_password_instructions(user)
4
+ default_url_options[:host] = Spree::Config[:site_url]
5
+
6
+ @edit_password_reset_url = edit_user_password_url(:reset_password_token => user.reset_password_token)
7
+
8
+ mail(:to => user.email,
9
+ :subject => Spree::Config[:site_name] + ' ' + I18n.t("password_reset_instructions"))
10
+ end
11
+
12
+ end
13
+
@@ -0,0 +1,20 @@
1
+ <%= render "shared/error_messages", :target => @user %>
2
+ <h2><%= t("registration")%></h2>
3
+ <div id="registration">
4
+ <div id="account">
5
+ <%= render :file => 'user_sessions/new' %>
6
+ </div>
7
+ <% if Spree::Config[:allow_guest_checkout] %>
8
+ <div id="guest_checkout">
9
+ <%= render "shared/error_messages", :target => @order %>
10
+ <h2><%= t(:guest_user_account) %></h2>
11
+ <%= form_for @order, :url => update_checkout_registration_path, :html => { :method => :put, :id => "checkout_form_registration"} do |f| %>
12
+ <p>
13
+ <%= f.label :email, t("email") %><br />
14
+ <%= f.text_field :email, :class => 'title' %>
15
+ </p>
16
+ <p><%= submit_tag t("continue"), :class => 'button primary' %></p>
17
+ <% end %>
18
+ </div>
19
+ <% end %>
20
+ </div>
@@ -0,0 +1,8 @@
1
+ <% if current_user %>
2
+ <ul id="login-nav">
3
+ <li><%= t('logged_in_as') %>: <%= current_user.email %></li>
4
+ <li><%= link_to t('account'), edit_user_path(current_user) %></li>
5
+ <li><%= link_to t('logout'), destroy_user_session_path %></li>
6
+ <li><%= link_to t('store'), products_path %></li>
7
+ </ul>
8
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if flash.any? %>
2
+ <div id="flash">
3
+ <% flash.each do |key, value| %>
4
+ <p>
5
+ <%= value %>
6
+ </p>
7
+ <% end %>
8
+ </div>
9
+ <% end%>
@@ -0,0 +1,20 @@
1
+ <%= form_for(:user, :url => user_session_path) do |f| %>
2
+ <div id='password-credentials'>
3
+ <p>
4
+ <%= f.label(:email, t("email")) %><br />
5
+ <%= f.text_field('email', :class => 'title') %>
6
+ </p>
7
+ <p>
8
+ <%= f.label :password, t("password") %><br />
9
+ <%= f.password_field 'password', :class => 'title' %>
10
+ </p>
11
+ </div>
12
+ <p>
13
+ <label>
14
+ <%= f.check_box :remember_me %>
15
+ <%= f.label :remember_me, t('remember_me') %>
16
+ </label>
17
+ </p>
18
+
19
+ <p><%= submit_tag t("log_in"), :class => 'button primary'%></p>
20
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <% if current_user %>
2
+ <li><%= link_to t('my_account'), account_path %></li>
3
+ <li><%= link_to t('logout'), destroy_user_session_path %></li>
4
+ <% else %>
5
+ <li><%= link_to t('log_in'), login_path %></li>
6
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <p>
2
+ <%= f.label :email, t("email") %><br />
3
+ <%= f.text_field :email, :class => 'title' %>
4
+ </p>
5
+ <div id="password-credentials">
6
+ <p>
7
+ <%= f.label :password, t("password") %><br />
8
+ <%= f.password_field :password, :class => 'title' %>
9
+ </p>
10
+
11
+ <p>
12
+ <%= f.label :password_confirmation, t(:confirm_password) %><br />
13
+ <%= f.password_field :password_confirmation, :class => 'title' %>
14
+ </p>
15
+ </div>
16
+
17
+ <%= hook :signup_below_password_fields %>
File without changes
@@ -0,0 +1,10 @@
1
+ A request to reset your password has been made.
2
+ If you did not make this request, simply ignore this email.
3
+
4
+ If you did make this request just click the link below:
5
+
6
+ <%= @edit_password_reset_url %>
7
+
8
+ If the above URL does not work try copying and pasting it into your browser.
9
+ If you continue to have problem please feel free to contact us.
10
+
@@ -0,0 +1,15 @@
1
+ <%= render "shared/error_messages", :target => @user %>
2
+ <h1><%= t(:change_my_password) %></h1>
3
+
4
+ <%= form_for @user, :url => user_password_path, :html => {:method => :put} do |f| %>
5
+ <p>
6
+ <%= f.label :password %><br />
7
+ <%= f.password_field :password %><br />
8
+ </p>
9
+ <p>
10
+ <%= f.label :password_confirmation %><br />
11
+ <%= f.password_field :password_confirmation %><br />
12
+ </p>
13
+ <%= f.hidden_field :reset_password_token %>
14
+ <%= f.submit t("update_password") %>
15
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <h1><%= t(:forgot_password) %></h1>
2
+
3
+ <p><%= t(:instructions_to_reset_password) %></p>
4
+
5
+ <%= form_for User.new, :as => :user, :url => user_password_path do |f| %>
6
+ <p>
7
+ <label><%= t(:email) %>:</label><br />
8
+ <%= f.email_field :email %>
9
+ </p>
10
+ <p>
11
+ <%= f.submit t("reset_password") %>
12
+ </p>
13
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <% @body_id = 'signup' %>
2
+
3
+ <%= render "shared/error_messages", :target => @user %>
4
+
5
+ <div id="new-customer">
6
+ <h2><%= t("new_customer") %></h2>
7
+
8
+ <%= hook :signup do %>
9
+
10
+ <%= form_for(:user, :url => registration_path(@user)) do |f| %>
11
+
12
+ <%= hook :signup_inside_form do %>
13
+ <%= render 'shared/user_form', :f => f %>
14
+ <p><%= submit_tag t("create"), :class => 'button primary' %></p>
15
+ <% end %>
16
+
17
+ <% end %>
18
+ <%= t("or") %> <%= link_to t("login_as_existing"), login_path %>
19
+ <% end %>
20
+
21
+ </div>
22
+
23
+ <%= hook :login_extras %>
@@ -0,0 +1,4 @@
1
+ <div style="height:50px; padding-top: 20px">
2
+ <strong><%= t("authorization_failure")%></strong>
3
+ </div>
4
+ <!-- Add your own custom access denied message here if you like -->
@@ -0,0 +1,13 @@
1
+ <% if flash[:alert] %>
2
+ <div class="flash errors"><%= flash[:alert] %></div>
3
+ <% end %>
4
+
5
+ <% @body_id = 'login' %>
6
+ <div id="existing-customer">
7
+ <h2><%= t("login_as_existing") %></h2>
8
+ <%= hook :login do %>
9
+ <%= render :partial => 'shared/login' %>
10
+ <%= t("or") %> <%= link_to t("create_a_new_account"), signup_path %> | <%= link_to t("forgot_password"), new_user_password_path %>
11
+ <% end %>
12
+ </div>
13
+ <%= hook :login_extras %>
@@ -0,0 +1,11 @@
1
+ <%= render "shared/error_messages", :target => @user %>
2
+
3
+ <h1><%= t("editing_user") %></h1>
4
+
5
+ <%= form_for(@user, :html => { :method => :put }) do |f| %>
6
+ <%= render 'shared/user_form', :f => f %>
7
+ <p>
8
+ <%=submit_tag t("update") %>
9
+ </p>
10
+ <% end %>
11
+
@@ -0,0 +1,50 @@
1
+ <h1><%= t("my_account") %></h1>
2
+
3
+ <%= hook :account_summary do %>
4
+
5
+ <table>
6
+ <tr>
7
+ <td><%= t("email") %>:</td>
8
+ <td>
9
+ <%= @user.email %>
10
+ </td>
11
+ </tr>
12
+ </table>
13
+ <p><%= link_to t('edit'), edit_account_path %></p>
14
+
15
+ <% end %>
16
+
17
+ <%= hook :account_my_orders do %>
18
+
19
+ <h2><%= t("my_orders") %></h2>
20
+ <% if @orders.present? %>
21
+ <table class="order-summary" width="545">
22
+ <thead>
23
+ <tr>
24
+ <th><%= t("order_number") %></th>
25
+ <th><%= t("order_date") %></th>
26
+ <th><%= t("status") %></th>
27
+ <th><%= t("payment_state") %></th>
28
+ <th><%= t("shipment_state") %></th>
29
+ <th><%= t("total") %></th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ <% @orders.each do |order| %>
34
+ <tr class="<%= cycle('even', 'odd') %>">
35
+ <td><%= link_to order.number, order_url(order) %></td>
36
+ <td><%=order.created_at.to_date%></td>
37
+ <td><%= t(order.state).titleize %></td>
38
+ <td><%= t("payment_states.#{order.payment_state}") if order.payment_state %></td>
39
+ <td><%= t("shipment_states.#{order.shipment_state}") if order.shipment_state %></td>
40
+ <td><%= number_to_currency order.total %></td>
41
+ </tr>
42
+ <% end %>
43
+ </tbody>
44
+ </table>
45
+ <% else %>
46
+ <p><%= t(:you_have_no_orders_yet) %></p>
47
+ <% end %>
48
+ <br />
49
+
50
+ <% end %>