spree_bushido_auth 0.60.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 %>