Browse Source

Merge branch 'master' into denney-new-user-form

Conflicts:
	db/schema.rb
eperez-timeinput
John N. Milner 12 years ago
parent
commit
c5b16139f5
  1. 43
      app/assets/javascripts/login.js
  2. 14
      app/components/app_tab_panel.rb
  3. 12
      app/components/app_tab_panel/javascripts/sign_out.js
  4. 6
      app/components/bikes.rb
  5. 5
      app/components/user_logs.rb
  6. 21
      app/components/user_role_joins.rb
  7. 15
      app/components/user_roles.rb
  8. 1
      app/components/users.rb
  9. 22
      app/controllers/api/v1/base_controller.rb
  10. 22
      app/controllers/api/v1/logs_controller.rb
  11. 6
      app/models/ability.rb
  12. 16
      app/models/role.rb
  13. 58
      app/models/user.rb
  14. 11
      app/models/user_role.rb
  15. 13
      app/models/user_role_join.rb
  16. 9
      app/views/devise/sessions/new.html.erb
  17. 10
      config/initializers/devise.rb
  18. 9
      config/routes.rb
  19. 9
      db/migrate/20130423231937_alter_user_roles.rb
  20. 8
      db/migrate/20130423233228_add_roles.rb
  21. 5
      db/migrate/20130424005701_alter_user.rb
  22. 11
      db/schema.rb
  23. 5
      db/seed/fixtures/acts_as_loggable/user_actions.yml
  24. 9
      db/seed/fixtures/roles.yml
  25. 2
      db/seeds.rb
  26. 2
      spec/factories/roles.rb
  27. 16
      spec/factories/users.rb

43
app/assets/javascripts/login.js

@ -0,0 +1,43 @@
$("#checkin_menu").show();
$("#checkin").click( function(e){
var username = $("#user_email").val();
var password = $("#user_password").val();
$.ajax({
type: 'POST',
url: '/api/v1/checkin',
dataType: 'json',
contentType: 'application/json',
processData: false,
data: JSON.stringify({"username": username, "password": password }),
complete: function() { },
success: function(data) {
alert("Checked IN!");
$("#user_email").val('');
$("#user_password").val('');
},
error: function(data,textStatus) {
alert( "Error: " + JSON.parse(data.responseText)["error"]);
}
})
});
$("#checkout").click( function(e){
var username = $("#user_email").val();
var password = $("#user_password").val();
$.ajax({
type: 'POST',
url: '/api/v1/checkout',
dataType: 'json',
contentType: 'application/json',
processData: false,
data: JSON.stringify({"username": username, "password": password }),
complete: function() { },
success: function(data) {
alert("Checked OUT!");
$("#user_email").val('');
$("#user_password").val('');
},
error: function(data,textStatus) {
alert( "Error: " + JSON.parse(data.responseText)["error"]);
}
})
});

14
app/components/app_tab_panel.rb

@ -6,6 +6,11 @@ class AppTabPanel < Netzke::Basepack::TabPanel
c.text = "Exit" c.text = "Exit"
end end
action :check_out do |c|
c.icon = :door_out
c.text = "CHECK OUT" if controller.current_user
end
def configure(c) def configure(c)
#all users #all users
@ -37,7 +42,10 @@ class AppTabPanel < Netzke::Basepack::TabPanel
wrappedComponent: :transactions_border, wrappedComponent: :transactions_border,
title: "Transactions"}, title: "Transactions"},
:logs, :logs,
:user_roles] { layout: :fit,
wrappedComponent: :user_role_joins,
title: "User Roles"}
]
end end
@@app_tab_panel_items.each do |item| @@app_tab_panel_items.each do |item|
@ -47,9 +55,8 @@ class AppTabPanel < Netzke::Basepack::TabPanel
self.class.component item[:wrappedComponent] self.class.component item[:wrappedComponent]
end end
end end
c.prevent_header = true c.prevent_header = true
c.tbar = [:sign_out] c.tbar = [:sign_out, :check_out]
c.items = @@app_tab_panel_items c.items = @@app_tab_panel_items
super super
end end
@ -58,6 +65,5 @@ class AppTabPanel < Netzke::Basepack::TabPanel
#gets js from app_tab_panel/javascripts/sign_out.js #gets js from app_tab_panel/javascripts/sign_out.js
c.mixin :sign_out c.mixin :sign_out
end end
end end

12
app/components/app_tab_panel/javascripts/sign_out.js

@ -5,5 +5,17 @@
url: '/users/sign_out', url: '/users/sign_out',
method: 'DELETE' method: 'DELETE'
}); });
},
onCheckOut: function(){
Ext.Ajax.request({
url: '/api/v1/checkout',
method: 'POST',
success: function(response, opts) {
Ext.Ajax.request({
url: '/users/sign_out',
method: 'DELETE'
});
}
});
} }
} }

6
app/components/bikes.rb

@ -18,9 +18,9 @@ class Bikes < Netzke::Basepack::Grid
}, },
:color, :color,
{ :name => :bike_style__style, :text => 'Style' }, { :name => :bike_style__style, :text => 'Style' },
:seat_tube_height, { :name => :seat_tube_height, :text => 'Seat Tube (in)'},
:top_tube_length, { :name => :top_tube_length, :text => 'Top Tube (in)'},
:wheel_size, { :name => :wheel_size, :text => 'Wheel Size (in)'},
:value, :value,
{ :name => :bike_condition__condition, :text => 'Condition'}, { :name => :bike_condition__condition, :text => 'Condition'},
{ :name => :bike_status__status, :text => 'Status'}, { :name => :bike_status__status, :text => 'Status'},

5
app/components/user_logs.rb

@ -37,7 +37,7 @@ class UserLogs < Netzke::Basepack::Grid
{ :name => :end_date, :hidden => true, :default_value => Time.now.to_formatted_s(:db) }, { :name => :end_date, :hidden => true, :default_value => Time.now.to_formatted_s(:db) },
{ :name => :hours, :getter => lambda { |rec| (rec.end_date - rec.start_date)/3600 }, :sorting_scope => :sort_by_duration}, { :name => :hours, :getter => lambda { |rec| (rec.end_date - rec.start_date)/3600 }, :sorting_scope => :sort_by_duration},
:description, :description,
{ :name => :user_action__action, :text => 'Action' }, { :name => :user_action__action, :text => 'Action', :default_value => ::ActsAsLoggable::UserAction.all.first.id },
:created_at, :created_at,
:updated_at, :updated_at,
{ :name => :logged_by, :getter => lambda{ |rec| { :name => :logged_by, :getter => lambda{ |rec|
@ -53,13 +53,12 @@ class UserLogs < Netzke::Basepack::Grid
bike_store = Bike.all.map { |b| [b.id, b.shop_id] } bike_store = Bike.all.map { |b| [b.id, b.shop_id] }
current_user ||= User.find_by_id(session[:selected_user_id]) || controller.current_user current_user ||= User.find_by_id(session[:selected_user_id]) || controller.current_user
bike_id = current_user.bike.nil? ? nil : current_user.bike.id bike_id = current_user.bike.nil? ? nil : current_user.bike.id
action_id = current_user.user_role.id
[ [
{ :name => :start_date}, { :name => :start_date},
{ :name => :end_date}, { :name => :end_date},
{ :name => :description}, { :name => :description},
#had to hack acts_as_loggable/log.rb to get this to work #had to hack acts_as_loggable/log.rb to get this to work
{ :name => :user_action__action, :field_label => 'Action', :value => action_id}, { :name => :user_action__action, :field_label => 'Action'},
{ :name => :for_bike, :checkboxName => :copy_log, :inputValue => true, :title => "Copy description to a Bike's History?", :xtype => 'fieldset', :checkboxToggle => true, :collapsed => true, :items => [ { :name => :for_bike, :checkboxName => :copy_log, :inputValue => true, :title => "Copy description to a Bike's History?", :xtype => 'fieldset', :checkboxToggle => true, :collapsed => true, :items => [
{:xtype => 'combo', :no_binding => true, :name => :copy_id, :title => 'Bike', :fieldLabel => 'Bike', :store => bike_store, :value => bike_id} {:xtype => 'combo', :no_binding => true, :name => :copy_id, :title => 'Bike', :fieldLabel => 'Bike', :store => bike_store, :value => bike_id}
] ]

21
app/components/user_role_joins.rb

@ -0,0 +1,21 @@
class UserRoleJoins < Netzke::Basepack::Grid
def configure(c)
super
c.model = "UserRoleJoin"
c.header = false
c.title = "User Roles"
c.columns = [
{ :name => :user__first_name, :text => "First"},
{ :name => :user__last_name, :text => "Last"},
{ :name => :role__role, :text => "Role"},
:created_at,
:updated_at,
:ends ]
end
#override with nil to remove actions
def default_bbar
[ :apply, :add_in_form, :search ]
end
end

15
app/components/user_roles.rb

@ -1,15 +0,0 @@
class UserRoles < Netzke::Basepack::Grid
def configure(c)
super
c.model = "UserRole"
c.title = "User Roles"
c.columns = [ :role, :created_at, :updated_at, :ends ]
end
#override with nil to remove actions
def default_bbar
[ :apply, :add_in_form, :search ]
end
end

1
app/components/users.rb

@ -10,7 +10,6 @@ class Users < Netzke::Basepack::Grid
:last_name, :last_name,
:nickname, :nickname,
:email, :email,
:user_role__role,
:bike__shop_id :bike__shop_id
] ]
end end

22
app/controllers/api/v1/base_controller.rb

@ -0,0 +1,22 @@
class Api::V1::BaseController < ActionController::Base
respond_to :json
before_filter :authenticate_user
private
def authenticate_user
if params[:username]
user = User.find_for_database_authentication( :email => params[:username] )
@current_user = user if user && user.valid_password?( params[:password] )
if @current_user.nil?
msg = "Username/Password/Token invalid"
render :json => {:error => msg }, :status => 403 and return
end
else
authenticate_user!
@current_user = current_user
end
end
end

22
app/controllers/api/v1/logs_controller.rb

@ -0,0 +1,22 @@
class Api::V1::LogsController < Api::V1::BaseController
def checkin
#must use @current_user since user may not have signed in
if @current_user.checked_in?
render :json => { "error" => "You are already checked in."}, :status => 404 and return
else
@current_user.checkin
render :nothing => true, :status => 204 and return
end
end
def checkout
#must use @current_user since user may not have signed in
if !@current_user.checked_in?
render :json => { "error" => "You were not even checked in."}, :status => 404 and return
else
@current_user.checkout
render :nothing => true, :status => 204 and return
end
end
end

6
app/models/ability.rb

@ -3,7 +3,9 @@ class Ability
def initialize(current_user) def initialize(current_user)
@current_user = current_user @current_user = current_user
self.send(current_user.role.to_sym) current_user.roles.each do |role|
self.send(role.role.to_sym)
end
end end
def admin def admin
@ -21,7 +23,7 @@ class Ability
def user def user
can :read, :all can :read, :all
can :update, Bike, :id => @current_user.bike_id unless @current_user.bike.nil? can :manage, Bike, :id => @current_user.bike_id unless @current_user.bike.nil?
can :manage, ::ActsAsLoggable::Log, { :loggable_type => "Bike", :loggable_id => @current_user.bike_id } can :manage, ::ActsAsLoggable::Log, { :loggable_type => "Bike", :loggable_id => @current_user.bike_id }
can :manage, ::ActsAsLoggable::Log, { :loggable_type => "User", :loggable_id => @current_user.id } can :manage, ::ActsAsLoggable::Log, { :loggable_type => "User", :loggable_id => @current_user.id }
end end

16
app/models/role.rb

@ -0,0 +1,16 @@
class Role < ActiveRecord::Base
attr_accessible :role
has_many :user_role_joins
has_many :users, through: :user_role_joins
validates_uniqueness_of :role
def to_s
self.role
end
def ==(other)
self.role == other.role
end
end

58
app/models/user.rb

@ -7,14 +7,16 @@ class User < ActiveRecord::Base
# Setup accessible (or protected) attributes for your model # Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, attr_accessible :email, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :nickname, :user_role_id, :bike_id, :first_name, :last_name, :nickname, :bike_id,
:user_profiles_attributes :user_profiles_attributes, :username
has_many :transactions has_many :transactions
has_many :user_profiles has_many :user_profiles
accepts_nested_attributes_for :user_profiles, allow_destroy: false accepts_nested_attributes_for :user_profiles, allow_destroy: false
has_one :user_role has_many :user_role_joins, :conditions => ["ends IS NULL OR ends > ?", Time.now]
has_many :roles, through: :user_role_joins
belongs_to :bike belongs_to :bike
validates :first_name, :presence => true validates :first_name, :presence => true
@ -24,29 +26,65 @@ class User < ActiveRecord::Base
"#{first_name} #{last_name}" "#{first_name} #{last_name}"
end end
def full_name def email_required?
to_s false
end end
def role def full_name
user_role.role to_s
end end
def role?(role) def role?(role)
user_role.to_s == role.to_s if role.kind_of?(String) or role.kind_of?(Symbol)
role = Role.find_by_role(role.to_s)
end
roles.include?(role)
end end
### TODO methods below probably belong somewhere else
def total_hours def total_hours
ActsAsLoggable::Log.where( :loggable_type => self.class.to_s, :loggable_id => self.id).sum { |l| (l.end_date - l.start_date)/3600 }.round(2) log_action = ::ActsAsLoggable::UserAction.find_by_action("CHECKIN")
logs.where("log_action_id != ? AND log_action_type = ?", log_action.id, log_action.class.to_s).sum { |l| (l.end_date - l.start_date)/3600 }.round(2)
end end
def current_month_hours def current_month_hours
log_action = ::ActsAsLoggable::UserAction.find_by_action("CHECKIN")
#TODO need to prevent users from saving logs across months, force to create a new log if crossing month #TODO need to prevent users from saving logs across months, force to create a new log if crossing month
current_month_range = (Time.now.beginning_of_month..Time.now.end_of_month) current_month_range = (Time.now.beginning_of_month..Time.now.end_of_month)
ActsAsLoggable::Log.where( :loggable_type => self.class.to_s, :loggable_id => self.id) logs.where("log_action_id != ? AND log_action_type = ?", log_action.id, log_action.class.to_s)
.where( :start_date => current_month_range) .where( :start_date => current_month_range)
.where( :end_date => current_month_range) .where( :end_date => current_month_range)
.sum { |l| (l.end_date - l.start_date)/3600 } .sum { |l| (l.end_date - l.start_date)/3600 }
.round(2) .round(2)
end end
def checked_in?
log_action = ::ActsAsLoggable::UserAction.find_by_action("CHECKIN")
checked = logs.where( log_action_id: log_action.id).
where("start_date >= ?", Time.zone.now.beginning_of_day).
where("start_date = end_date")
!checked.empty?
end
def checkin
log_action = ::ActsAsLoggable::UserAction.find_by_action("CHECKIN")
time = Time.now
logs.create( logger_id: self.id,
logger_type: self.class.to_s,
start_date: time,
end_date: time,
log_action_id: log_action.id,
log_action_type: log_action.class.to_s)
save
end
def checkout
log_action = ::ActsAsLoggable::UserAction.find_by_action("CHECKIN")
checked = logs.where( log_action_id: log_action.id).
where("start_date >= ?", Time.zone.now.beginning_of_day).
where("start_date = end_date").first
checked.end_date = Time.now
checked.save
end
end end

11
app/models/user_role.rb

@ -1,11 +0,0 @@
class UserRole < ActiveRecord::Base
attr_accessible :role
belongs_to :user
self.per_page = 15
def to_s
self.role
end
end

13
app/models/user_role_join.rb

@ -0,0 +1,13 @@
class UserRoleJoin < ActiveRecord::Base
self.table_name = :user_role_joins
attr_accessible :role_id, :user_id, :ends
belongs_to :user
belongs_to :role
validate :role_id, presence: true, numericality: true
validate :user_id, presence: true, numericality: true
validates_uniqueness_of :user_id, :scope => :role_id
self.per_page = 15
end

9
app/views/devise/sessions/new.html.erb

@ -1,6 +1,6 @@
<%= stylesheet_link_tag "bootstrap_and_overrides", :media => "all" %> <%= stylesheet_link_tag "bootstrap_and_overrides", :media => "all" %>
<h2>Sign in</h2> <h2>Velocipede</h2>
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %> <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
<div><%= f.label :username%><br /> <div><%= f.label :username%><br />
@ -14,8 +14,15 @@
<% end -%> <% end -%>
<div><%= f.submit "Sign in" %></div> <div><%= f.submit "Sign in" %></div>
<div id="checkin_menu"style="display:none;">
<input id="checkin" name="checkin" type="button" value="CHECK IN">
<input id="checkout" name="checkout" type="button" value="CHECK OUT">
</div>
<% end %> <% end %>
<%= render "links" %> <%= render "links" %>
<% if Rails.env.development? %> <% if Rails.env.development? %>

10
config/initializers/devise.rb

@ -38,12 +38,12 @@ Devise.setup do |config|
# Configure which authentication keys should be case-insensitive. # Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used # These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email. # to authenticate or find a user. Default is :email.
config.case_insensitive_keys = [ :email ] config.case_insensitive_keys = [ :username ]
# Configure which authentication keys should have whitespace stripped. # Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or # These keys will have whitespace before and after removed upon creating or
# modifying a user and when used to authenticate or find a user. Default is :email. # modifying a user and when used to authenticate or find a user. Default is :email.
config.strip_whitespace_keys = [ :email ] config.strip_whitespace_keys = [ :username ]
# Tell if authentication through request.params is enabled. True by default. # Tell if authentication through request.params is enabled. True by default.
# It can be set to an array that will enable params authentication only for the # It can be set to an array that will enable params authentication only for the
@ -221,3 +221,9 @@ Devise.setup do |config|
# manager.default_strategies(:scope => :user).unshift :some_external_strategy # manager.default_strategies(:scope => :user).unshift :some_external_strategy
# end # end
end end
#Check in the user if they sign in. (Devise uses Warden)
Warden::Manager.after_authentication do |user,auth,opts|
user.checkin unless user.checked_in?
end

9
config/routes.rb

@ -4,4 +4,13 @@ Velocipede::Application.routes.draw do
netzke netzke
root :to => 'site#index' root :to => 'site#index'
###########################
# API Routes
scope 'api', :module => :api do
scope 'v1', :module => :v1 do
post 'checkin' => "logs#checkin", :as => "api_checkin"
post 'checkout' => "logs#checkout", :as => "api_checkout"
end
end
end end

9
db/migrate/20130423231937_alter_user_roles.rb

@ -0,0 +1,9 @@
class AlterUserRoles < ActiveRecord::Migration
def change
rename_table :user_roles, :user_role_joins
change_table :user_role_joins do |t|
t.rename :role, :role_id
t.change :role_id, :integer
end
end
end

8
db/migrate/20130423233228_add_roles.rb

@ -0,0 +1,8 @@
class AddRoles < ActiveRecord::Migration
def change
create_table(:roles) do |t|
t.string :role
t.timestamps
end
end
end

5
db/migrate/20130424005701_alter_user.rb

@ -0,0 +1,5 @@
class AlterUser < ActiveRecord::Migration
def change
remove_column :users, :user_role_id
end
end

11
db/schema.rb

@ -97,6 +97,12 @@ ActiveRecord::Schema.define(:version => 20130525143240) do
add_index "logs", ["loggable_id", "loggable_type", "context"], :name => "index_logs_on_loggable_id_and_loggable_type_and_context" add_index "logs", ["loggable_id", "loggable_type", "context"], :name => "index_logs_on_loggable_id_and_loggable_type_and_context"
create_table "roles", :force => true do |t|
t.string "role"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "task_lists", :force => true do |t| create_table "task_lists", :force => true do |t|
t.integer "item_id", :null => false t.integer "item_id", :null => false
t.string "item_type", :null => false t.string "item_type", :null => false
@ -148,8 +154,8 @@ ActiveRecord::Schema.define(:version => 20130525143240) do
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
end end
create_table "user_roles", :force => true do |t| create_table "user_role_joins", :force => true do |t|
t.string "role" t.integer "role_id", :limit => 255
t.datetime "created_at", :null => false t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
t.datetime "ends" t.datetime "ends"
@ -167,7 +173,6 @@ ActiveRecord::Schema.define(:version => 20130525143240) do
t.datetime "last_sign_in_at" t.datetime "last_sign_in_at"
t.string "current_sign_in_ip" t.string "current_sign_in_ip"
t.string "last_sign_in_ip" t.string "last_sign_in_ip"
t.integer "user_role_id", :default => 1, :null => false
t.integer "bike_id" t.integer "bike_id"
t.datetime "created_at", :null => false t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false

5
db/seed/fixtures/acts_as_loggable/user_actions.yml

@ -13,3 +13,8 @@ staff:
action: STAFF action: STAFF
created_at: <%= Time.now %> created_at: <%= Time.now %>
updated_at: <%= Time.now %> updated_at: <%= Time.now %>
checkin:
id: 4
action: CHECKIN
created_at: <%= Time.now %>
updated_at: <%= Time.now %>

9
db/seed/fixtures/roles.yml

@ -0,0 +1,9 @@
user:
id: 1
role: user
staff:
id: 2
role: staff
admin:
id: 3
role: admin

2
db/seeds.rb

@ -21,7 +21,7 @@ end
if Rails.env.development? if Rails.env.development?
#create default admin user #create default admin user
if UserRole.all.empty? and User.all.empty? if User.all.empty?
FactoryGirl.create(:user) FactoryGirl.create(:user)
FactoryGirl.create(:staff) FactoryGirl.create(:staff)
FactoryGirl.create(:admin) FactoryGirl.create(:admin)

2
spec/factories/user_roles.rb → spec/factories/roles.rb

@ -1,5 +1,5 @@
FactoryGirl.define do FactoryGirl.define do
factory :user_role do factory :role do
factory :role_staff do factory :role_staff do
role 'staff' role 'staff'
end end

16
spec/factories/users.rb

@ -7,24 +7,32 @@ FactoryGirl.define do
first_name 'Michael' first_name 'Michael'
last_name 'Scott' last_name 'Scott'
sequence(:bike_id) { |n| n } sequence(:bike_id) { |n| n }
association :user_role, factory: :role_user after_build do |r|
r.roles << (Role.find_by_role("user") || FactoryGirl.create(:role_user))
end
factory :staff do factory :staff do
username "staff" username "staff"
first_name 'Staff' first_name 'Staff'
association :user_role, factory: :role_staff after_build do |r|
r.roles << (Role.find_by_role("staff") || FactoryGirl.create(:role_staff))
end
end end
factory :admin do factory :admin do
username "admin" username "admin"
first_name 'Admin' first_name 'Admin'
association :user_role, factory: :role_admin after_build do |r|
r.roles << (Role.find_by_role("admin") || FactoryGirl.create(:role_admin))
end
end end
factory :bike_admin do factory :bike_admin do
username "bike_admin" username "bike_admin"
first_name 'BikeAdmin' first_name 'BikeAdmin'
association :user_role, factory: :role_bike_admin after_build do |r|
r.roles << (Role.find_by_role("bike_admin") || FactoryGirl.create(:role_bike_admin))
end
end end
end end

Loading…
Cancel
Save