mirror of
https://github.com/fspc/BikeShed-1.git
synced 2025-02-28 16:53:23 -05:00
merging master
This commit is contained in:
commit
b450baa3dc
@ -12,5 +12,4 @@
|
|||||||
//
|
//
|
||||||
//= require jquery
|
//= require jquery
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
//= require twitter/bootstrap
|
//= require custom_netzke_helpers
|
||||||
//= require_tree .
|
|
||||||
|
@ -3,3 +3,150 @@ Ext.Ajax.on('requestexception', function(conn, response, options) {
|
|||||||
if (response.status === 401) { window.location = '/users/sign_in'; }
|
if (response.status === 401) { window.location = '/users/sign_in'; }
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
Ext.define('Ext.ux.form.field.ColorCombo', {
|
||||||
|
extend:'Ext.form.FieldContainer',
|
||||||
|
mixins:{
|
||||||
|
field:'Ext.form.field.Field'
|
||||||
|
},
|
||||||
|
alias: 'widget.xcolorcombo',
|
||||||
|
|
||||||
|
//configurables
|
||||||
|
combineErrors: true,
|
||||||
|
msgTarget: 'under',
|
||||||
|
layout: 'hbox',
|
||||||
|
readOnly: false,
|
||||||
|
|
||||||
|
// properties
|
||||||
|
colorValue: null,
|
||||||
|
/**
|
||||||
|
* @property dateField
|
||||||
|
* @type Ext.form.field.Date
|
||||||
|
*/
|
||||||
|
colorField: null,
|
||||||
|
|
||||||
|
initComponent: function(){
|
||||||
|
var me = this
|
||||||
|
,i = 0
|
||||||
|
,key
|
||||||
|
,tab;
|
||||||
|
|
||||||
|
me.items = me.items || [];
|
||||||
|
|
||||||
|
me.colorField = Ext.create('Ext.form.field.Trigger', {
|
||||||
|
flex:1,
|
||||||
|
isFormField:false, //exclude from field query's
|
||||||
|
submitValue:false,
|
||||||
|
readOnly: me.readOnly,
|
||||||
|
onTriggerClick: function() {
|
||||||
|
//needs to be called twice because?
|
||||||
|
me.picker.alignTo(me.colorField.inputEl);
|
||||||
|
me.picker.show();
|
||||||
|
me.picker.alignTo(me.colorField.inputEl);
|
||||||
|
me.picker.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
me.items.push(me.colorField);
|
||||||
|
|
||||||
|
me.picker = Ext.create('Ext.picker.Color', {
|
||||||
|
renderTo: document.body,
|
||||||
|
floating: true,
|
||||||
|
hidden: true,
|
||||||
|
style: {
|
||||||
|
backgroundColor: "#fff"
|
||||||
|
},
|
||||||
|
listeners: {
|
||||||
|
scope:this,
|
||||||
|
select: function(field, value, opts){
|
||||||
|
me.setValue(value);
|
||||||
|
me.picker.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
me.items.push(me.picker);
|
||||||
|
|
||||||
|
for (; i < me.items.length; i++) {
|
||||||
|
me.items[i].on('focus', Ext.bind(me.onItemFocus, me));
|
||||||
|
me.items[i].on('blur', Ext.bind(me.onItemBlur, me));
|
||||||
|
me.items[i].on('specialkey', function(field, event){
|
||||||
|
key = event.getKey();
|
||||||
|
tab = key == event.TAB;
|
||||||
|
|
||||||
|
if (tab && me.focussedItem == me.dateField) {
|
||||||
|
event.stopEvent();
|
||||||
|
me.timeField.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
me.fireEvent('specialkey', field, event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
me.callParent();
|
||||||
|
|
||||||
|
// this dummy is necessary because Ext.Editor will not check whether an inputEl is present or not
|
||||||
|
this.inputEl = {
|
||||||
|
dom: document.createElement('div'),
|
||||||
|
swallowEvent:function(){}
|
||||||
|
};
|
||||||
|
|
||||||
|
me.initField();
|
||||||
|
},
|
||||||
|
focus:function(){
|
||||||
|
this.callParent(arguments);
|
||||||
|
this.colorField.focus();
|
||||||
|
var me = this;
|
||||||
|
},
|
||||||
|
|
||||||
|
onItemFocus:function(item){
|
||||||
|
if (this.blurTask){
|
||||||
|
this.blurTask.cancel();
|
||||||
|
}
|
||||||
|
this.focussedItem = item;
|
||||||
|
},
|
||||||
|
|
||||||
|
onItemBlur:function(item, e){
|
||||||
|
var me = this;
|
||||||
|
if (item != me.focussedItem){ return; }
|
||||||
|
// 100ms to focus a new item that belongs to us, otherwise we will assume the user left the field
|
||||||
|
me.blurTask = new Ext.util.DelayedTask(function(){
|
||||||
|
me.picker.hide();
|
||||||
|
me.fireEvent('blur', me, e);
|
||||||
|
});
|
||||||
|
me.blurTask.delay(100);
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue: function(){
|
||||||
|
var value = null
|
||||||
|
,color = this.colorField.getSubmitValue();
|
||||||
|
|
||||||
|
if (color){
|
||||||
|
value = this.colorField.getValue();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubmitValue: function(){
|
||||||
|
// var value = this.getValue();
|
||||||
|
// return value ? Ext.Date.format(value, this.dateTimeFormat) : null;
|
||||||
|
|
||||||
|
var me = this
|
||||||
|
,value = me.getValue();
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
setValue: function(value){
|
||||||
|
this.colorField.setValue(value);
|
||||||
|
},
|
||||||
|
// Bug? A field-mixin submits the data from getValue, not getSubmitValue
|
||||||
|
getSubmitData: function(){
|
||||||
|
var me = this
|
||||||
|
,data = null;
|
||||||
|
|
||||||
|
if (!me.disabled && me.submitValue && !me.isFileUpload()) {
|
||||||
|
data = {};
|
||||||
|
data[me.getName()] = '' + me.getSubmitValue();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
51
app/assets/javascripts/devise/registrations.js
Normal file
51
app/assets/javascripts/devise/registrations.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
$(document).ready(function(){
|
||||||
|
var MIN_LEN = 3;
|
||||||
|
var MAX_SUBMITS = 3;
|
||||||
|
var submit_count = 0;
|
||||||
|
$("input[name=commit]").click( function(e){
|
||||||
|
console.log("clicked");
|
||||||
|
submit_count += 1;
|
||||||
|
//IDs of contact info
|
||||||
|
var contact_info_ids = [
|
||||||
|
"user_email",
|
||||||
|
"user_user_profiles_attributes_0_addrStreet1",
|
||||||
|
"user_user_profiles_attributes_0_addrCity",
|
||||||
|
"user_user_profiles_attributes_0_addrState",
|
||||||
|
"user_user_profiles_attributes_0_addrZip",
|
||||||
|
"user_user_profiles_attributes_0_phone"
|
||||||
|
];
|
||||||
|
var contact_vals = "";
|
||||||
|
var index = 0;
|
||||||
|
//see if any contact info exists
|
||||||
|
for( var index in contact_info_ids){
|
||||||
|
contact_vals += $("#"+contact_info_ids[index]).val();
|
||||||
|
}
|
||||||
|
if( contact_vals.length >= MIN_LEN || submit_count > MAX_SUBMITS){
|
||||||
|
|
||||||
|
if( submit_count > MAX_SUBMITS ){
|
||||||
|
alert("Fine.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
switch(submit_count){
|
||||||
|
case 1:
|
||||||
|
alert("It appears you have not entered any contact information. " +
|
||||||
|
"Please do.");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
alert("It is highly recommended that you enter at least one form of" +
|
||||||
|
" contact information. It is in your best interest.");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
alert("If something happens to your bicycle, we will not be able to" +
|
||||||
|
" notify you. Please enter at least one form of contact.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
alert("Please enter at least one form of contact.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
0
app/assets/javascripts/devise/sessions.js
Normal file
0
app/assets/javascripts/devise/sessions.js
Normal file
0
app/assets/javascripts/site.js
Normal file
0
app/assets/javascripts/site.js
Normal file
@ -3,7 +3,7 @@ class AppTabPanel < Netzke::Basepack::TabPanel
|
|||||||
|
|
||||||
action :sign_out do |c|
|
action :sign_out do |c|
|
||||||
c.icon = :door_out
|
c.icon = :door_out
|
||||||
c.text = "Sign out #{controller.current_user.email}" if controller.current_user
|
c.text = "Exit"
|
||||||
end
|
end
|
||||||
|
|
||||||
action :check_out do |c|
|
action :check_out do |c|
|
||||||
@ -11,6 +11,11 @@ class AppTabPanel < Netzke::Basepack::TabPanel
|
|||||||
c.text = "CHECK OUT" if controller.current_user
|
c.text = "CHECK OUT" if controller.current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
action :change_account_info do |c|
|
||||||
|
c.icon = :user_edit
|
||||||
|
c.text = "Change Email/Password"
|
||||||
|
end
|
||||||
|
|
||||||
def configure(c)
|
def configure(c)
|
||||||
|
|
||||||
#all users
|
#all users
|
||||||
@ -48,7 +53,9 @@ class AppTabPanel < Netzke::Basepack::TabPanel
|
|||||||
if can? :manage, Role
|
if can? :manage, Role
|
||||||
@@app_tab_panel_items.concat [{ layout: :fit,
|
@@app_tab_panel_items.concat [{ layout: :fit,
|
||||||
wrappedComponent: :user_role_joins,
|
wrappedComponent: :user_role_joins,
|
||||||
title: "User Roles"}]
|
title: "User Roles"},
|
||||||
|
:check_ins
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@app_tab_panel_items.each do |item|
|
@@app_tab_panel_items.each do |item|
|
||||||
@ -59,7 +66,7 @@ class AppTabPanel < Netzke::Basepack::TabPanel
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
c.prevent_header = true
|
c.prevent_header = true
|
||||||
c.tbar = [:sign_out, :check_out]
|
c.tbar = [:sign_out, :check_out, :change_account_info]
|
||||||
c.items = @@app_tab_panel_items
|
c.items = @@app_tab_panel_items
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
@ -17,5 +17,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
onChangeAccountInfo: function(){
|
||||||
|
window.location.href="users/edit";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,8 @@ class Bikes < Netzke::Basepack::Grid
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
:color,
|
#needs to have type :action or else won't work in grid, because... netzke
|
||||||
|
{ :name => "color", :text => "Frame Color", :type => :action, :editor => { :xtype => "xcolorcombo"}, :renderer => :color_block},
|
||||||
{ :name => :bike_style__style, :text => 'Style' },
|
{ :name => :bike_style__style, :text => 'Style' },
|
||||||
{ :name => :seat_tube_height, :text => 'Seat Tube (in)'},
|
{ :name => :seat_tube_height, :text => 'Seat Tube (in)'},
|
||||||
{ :name => :top_tube_length, :text => 'Top Tube (in)'},
|
{ :name => :top_tube_length, :text => 'Top Tube (in)'},
|
||||||
@ -32,6 +33,23 @@ class Bikes < Netzke::Basepack::Grid
|
|||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def default_fields_for_forms
|
||||||
|
[
|
||||||
|
{ :name => :shop_id, :field_label => 'Shop ID'},
|
||||||
|
:serial_number,
|
||||||
|
{ :name => :bike_brand__brand, :field_label => 'Brand' },
|
||||||
|
{ :name => :bike_model__model, :field_label => 'Model'},
|
||||||
|
{ :name => "color", :xtype => "xcolorcombo"},
|
||||||
|
{ :name => :bike_style__style, :field_label => 'Style' },
|
||||||
|
{ :name => :seat_tube_height, :field_label => 'Seat Tube (in)'},
|
||||||
|
{ :name => :top_tube_length, :field_label => 'Top Tube (in)'},
|
||||||
|
{ :name => :wheel_size, :field_label => 'Wheel Size (in)'},
|
||||||
|
:value,
|
||||||
|
{ :name => :bike_condition__condition, :field_label => 'Condition'},
|
||||||
|
{ :name => :bike_status__status, :field_label => 'Status'}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
#override with nil to remove actions
|
#override with nil to remove actions
|
||||||
def default_bbar
|
def default_bbar
|
||||||
[ :apply, :add_in_form, :search ]
|
[ :apply, :add_in_form, :search ]
|
||||||
|
@ -9,5 +9,8 @@
|
|||||||
// The beauty of using Ext.Direct: calling 3 endpoints in a row, which results in a single call to the server!
|
// The beauty of using Ext.Direct: calling 3 endpoints in a row, which results in a single call to the server!
|
||||||
this.selectBikeBrand({bike_brand_id: record.get('bike_brand__brand')});
|
this.selectBikeBrand({bike_brand_id: record.get('bike_brand__brand')});
|
||||||
}, this);
|
}, this);
|
||||||
|
},
|
||||||
|
colorBlock: function(value){
|
||||||
|
return Ext.String.format('<div style="display:inline-block">{1}</div><div style="background-color:#{0};width:50px;height:10px;display:inline-block;margin:0 5px 0 5px;border:solid;border-color:gray;border-width:1px;"></div>', value, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
app/components/check_ins.rb
Normal file
23
app/components/check_ins.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
class CheckIns < Netzke::Basepack::Grid
|
||||||
|
|
||||||
|
def configure(c)
|
||||||
|
super
|
||||||
|
c.header = false
|
||||||
|
c.model = "ActsAsLoggable::Log"
|
||||||
|
c.scope = lambda { |rel| rel.where(:log_action_type => ::ActsAsLoggable::UserAction).
|
||||||
|
where(:loggable_type => "User").
|
||||||
|
where(:log_action_id => ::ActsAsLoggable::UserAction.find_by_action("CHECKIN")).
|
||||||
|
where("start_date >= ?", Time.zone.now.beginning_of_day);
|
||||||
|
}
|
||||||
|
c.columns = [
|
||||||
|
{ :name => :name, :getter => lambda{ |rec|
|
||||||
|
user = User.find_by_id(rec.loggable_id)
|
||||||
|
user.nil? ? "" : "#{user.first_name} #{user.last_name}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ :name => "Status", :getter => lambda{ |rec| rec.start_date == rec.end_date ? "Checked In" : "Checked Out" } },
|
||||||
|
:start_date,
|
||||||
|
:end_date,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
@ -4,6 +4,7 @@ class UserStats < Netzke::Base
|
|||||||
bike = user.bike
|
bike = user.bike
|
||||||
%Q(
|
%Q(
|
||||||
<div id="user_stats_page">
|
<div id="user_stats_page">
|
||||||
|
<p>Username: #{user.username}</p>
|
||||||
<p>Total Hours Worked: #{user.total_hours}</p>
|
<p>Total Hours Worked: #{user.total_hours}</p>
|
||||||
<p>Hours worked in #{Time.now.strftime('%B')}: #{user.current_month_hours}</p>
|
<p>Hours worked in #{Time.now.strftime('%B')}: #{user.current_month_hours}</p>
|
||||||
<p>Current bike Shop ID: #{bike.shop_id if bike}</p>
|
<p>Current bike Shop ID: #{bike.shop_id if bike}</p>
|
||||||
|
@ -1,16 +1,28 @@
|
|||||||
class Users < Netzke::Basepack::Grid
|
class Users < Netzke::Basepack::Grid
|
||||||
|
include Netzke::Basepack::ActionColumn
|
||||||
|
|
||||||
|
column :reset do |c|
|
||||||
|
c.type = :action
|
||||||
|
c.actions = [{name: :reset_password, icon: :lock_break}]
|
||||||
|
c.header = ""
|
||||||
|
c.width = 20
|
||||||
|
end
|
||||||
|
|
||||||
def configure(c)
|
def configure(c)
|
||||||
super
|
super
|
||||||
c.header = false
|
c.header = false
|
||||||
c.model = "User"
|
c.model = "User"
|
||||||
|
|
||||||
c.columns = [
|
c.columns = [
|
||||||
|
:username,
|
||||||
:first_name,
|
:first_name,
|
||||||
:last_name,
|
:last_name,
|
||||||
:nickname,
|
:nickname,
|
||||||
:email,
|
:email,
|
||||||
:bike__shop_id
|
:bike__shop_id
|
||||||
]
|
]
|
||||||
|
|
||||||
|
c.columns << :reset if can? :manage, User
|
||||||
end
|
end
|
||||||
|
|
||||||
#override with nil to remove actions
|
#override with nil to remove actions
|
||||||
|
@ -4,8 +4,32 @@
|
|||||||
this.callParent();
|
this.callParent();
|
||||||
this.getView().on('itemclick', function(view, record){
|
this.getView().on('itemclick', function(view, record){
|
||||||
// The beauty of using Ext.Direct: calling 3 endpoints in a row, which results in a single call to the server!
|
// The beauty of using Ext.Direct: calling 3 endpoints in a row, which results in a single call to the server!
|
||||||
console.log("user: " + record.get('id') );
|
|
||||||
this.selectCustomer({customer_id: record.get('id'), customer_type: 'User'});
|
this.selectCustomer({customer_id: record.get('id'), customer_type: 'User'});
|
||||||
}, this);
|
}, this);
|
||||||
|
},
|
||||||
|
onResetPassword: function(record){
|
||||||
|
user = record.data;
|
||||||
|
Ext.Msg.confirm(
|
||||||
|
"Reset Password",
|
||||||
|
"Are you sure you want to reset "+user.first_name+" "+user.last_name+"'s password?",
|
||||||
|
function(butt_id){
|
||||||
|
if( butt_id === "yes" ){
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/api/v1/reset',
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
processData: false,
|
||||||
|
data: JSON.stringify({"user_id": user.id}),
|
||||||
|
complete: function() { },
|
||||||
|
success: function(data) {
|
||||||
|
Ext.Msg.alert("Success", "New Password: "+data.password);
|
||||||
|
},
|
||||||
|
error: function(data,textStatus) {
|
||||||
|
Ext.Msg.alert( "Error", JSON.parse(data.responseText)["error"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class UsersAndProfilesBorder < Netzke::Base
|
|||||||
super
|
super
|
||||||
c.header = false
|
c.header = false
|
||||||
c.items = [
|
c.items = [
|
||||||
{ netzke_component: :users, header: "Users", region: :center, width: 300, split: true },
|
{ netzke_component: :users, header: "Users", region: :center, width: 350, split: true },
|
||||||
{ netzke_component: :user_profiles, region: :south, height: 150, split: true},
|
{ netzke_component: :user_profiles, region: :south, height: 150, split: true},
|
||||||
{ netzke_component: :user_logs, region: :east, split: true}
|
{ netzke_component: :user_logs, region: :east, split: true}
|
||||||
]
|
]
|
||||||
@ -25,5 +25,5 @@ class UsersAndProfilesBorder < Netzke::Base
|
|||||||
# store selected boss id in the session for this component's instance
|
# store selected boss id in the session for this component's instance
|
||||||
session[:selected_user_id] = params[:user_id]
|
session[:selected_user_id] = params[:user_id]
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
28
app/controllers/api/v1/users_controller.rb
Normal file
28
app/controllers/api/v1/users_controller.rb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
require 'securerandom'
|
||||||
|
class Api::V1::UsersController < Api::V1::BaseController
|
||||||
|
|
||||||
|
def password_reset
|
||||||
|
if can? :manage, User
|
||||||
|
user = User.find_by_id(params[:user_id])
|
||||||
|
render :json => { "error" => "User not found"}, :status => 404 and return if user.nil?
|
||||||
|
render :json => { "error" => "Not allowed to reset your own password in this fashion."}, :status => 403 and return if user.id == current_user.id
|
||||||
|
|
||||||
|
new_pass = SecureRandom.hex[0,8]
|
||||||
|
user.password = new_pass
|
||||||
|
user.save
|
||||||
|
render :json => { "password" => new_pass}, :status => 200 and return
|
||||||
|
else
|
||||||
|
render :json => { "error" => "You do not have the permission"}, :status => 403 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
|
23
app/helpers/devise_helper.rb
Normal file
23
app/helpers/devise_helper.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module DeviseHelper
|
||||||
|
# A simple way to show error messages for the current devise resource. If you need
|
||||||
|
# to customize this method, you can either overwrite it in your application helpers or
|
||||||
|
# copy the views to your application.
|
||||||
|
#
|
||||||
|
# This method is intended to stay simple and it is unlikely that we are going to change
|
||||||
|
# it to add more behavior or options.
|
||||||
|
def devise_error_messages!
|
||||||
|
return "" if resource.errors.empty?
|
||||||
|
|
||||||
|
messages = resource.errors.full_messages.map { |msg| content_tag(:p, msg, :class => "alert") }.join
|
||||||
|
sentence = I18n.t("errors.messages.not_saved",
|
||||||
|
:count => resource.errors.count,
|
||||||
|
:resource => resource.class.model_name.human.downcase)
|
||||||
|
|
||||||
|
html = <<-HTML
|
||||||
|
<p>#{sentence}</p>
|
||||||
|
#{messages}
|
||||||
|
HTML
|
||||||
|
|
||||||
|
html.html_safe
|
||||||
|
end
|
||||||
|
end
|
@ -8,7 +8,7 @@ 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, :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
|
||||||
@ -26,6 +26,10 @@ class User < ActiveRecord::Base
|
|||||||
"#{first_name} #{last_name}"
|
"#{first_name} #{last_name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def email_required?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
def full_name
|
def full_name
|
||||||
to_s
|
to_s
|
||||||
end
|
end
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
class UserProfile < ActiveRecord::Base
|
class UserProfile < ActiveRecord::Base
|
||||||
# Setup accessible (or protected) attributes for your model
|
|
||||||
attr_accessible :user_id, :addrStreet1, :addrStreet2, :addrCity,
|
attr_accessible :user_id, :addrStreet1, :addrStreet2, :addrCity,
|
||||||
:addrState, :addrZip, :phone
|
:addrState, :addrZip, :phone
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :bike
|
belongs_to :bike
|
||||||
|
|
||||||
#validates :addrStreet1 , :presence => true
|
#validates :addrStreet1 , :presence => true
|
||||||
#validates :addrCity , :presence => true
|
#validates :addrCity , :presence => true
|
||||||
#validates :addrState , :presence => true
|
#validates :addrState , :presence => true
|
||||||
#validates :addrZip , :presence => true
|
#validates :addrZip , :presence => true
|
||||||
validates :phone, :presence => true
|
#validates :phone, :presence => true
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
[addrStreet1, addrStreet2, addrCity, addrState, addrZip, phone].join(" - ")
|
[addrStreet1, addrStreet2, addrCity, addrState, addrZip, phone].join(" - ")
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
<%= stylesheet_link_tag "bootstrap_and_overrides", :media => "all" %>
|
||||||
|
|
||||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
||||||
|
|
||||||
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
|
= stylesheet_link_tag "bootstrap_and_overrides", :media => "all"
|
||||||
%h2 Sign up
|
%h2 Sign up
|
||||||
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
|
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
|
||||||
= devise_error_messages!
|
= devise_error_messages!
|
||||||
|
%div
|
||||||
|
= f.label :username
|
||||||
|
%br/
|
||||||
|
= f.text_field :username
|
||||||
%div
|
%div
|
||||||
= f.label :first_name
|
= f.label :first_name
|
||||||
%br/
|
%br/
|
||||||
@ -18,7 +23,8 @@
|
|||||||
%br/
|
%br/
|
||||||
= f.email_field :email
|
= f.email_field :email
|
||||||
%div
|
%div
|
||||||
= f.fields_for :user_profiles, UserProfile.new do |builder|
|
- profile_builder = resource.user_profiles.empty? ? resource.user_profiles.build : resource.user_profiles
|
||||||
|
= f.fields_for :user_profiles, profile_builder do |builder|
|
||||||
= render 'user_profile_fields', f: builder
|
= render 'user_profile_fields', f: builder
|
||||||
%div
|
%div
|
||||||
= f.label :password
|
= f.label :password
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<h2>Velocipede</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 :email %><br />
|
<div><%= f.label :username%><br />
|
||||||
<%= f.email_field :email %></div>
|
<%= f.text_field :username%></div>
|
||||||
|
|
||||||
<div><%= f.label :password %><br />
|
<div><%= f.label :password %><br />
|
||||||
<%= f.password_field :password %></div>
|
<%= f.password_field :password %></div>
|
||||||
@ -28,9 +28,9 @@
|
|||||||
<% if Rails.env.development? %>
|
<% if Rails.env.development? %>
|
||||||
<% User.all.each do |user| %>
|
<% User.all.each do |user| %>
|
||||||
<%= 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| %>
|
||||||
<%= f.hidden_field :email, :value => user.email %></div>
|
<%= f.hidden_field :username, :value => user.username%></div>
|
||||||
<%= f.hidden_field :password, :value => 'password' %></div>
|
<%= f.hidden_field :password, :value => 'password' %></div>
|
||||||
<div><%= f.submit "Sign in as #{user.email}" %></div>
|
<div><%= f.submit "Sign in as #{user.username}" %></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -28,3 +28,4 @@
|
|||||||
%p © Velocipede 2013
|
%p © Velocipede 2013
|
||||||
|
|
||||||
= javascript_include_tag "application"
|
= javascript_include_tag "application"
|
||||||
|
= javascript_include_tag params[:controller]
|
||||||
|
@ -26,7 +26,7 @@ Devise.setup do |config|
|
|||||||
# session. If you need permissions, you should implement that in a before filter.
|
# session. If you need permissions, you should implement that in a before filter.
|
||||||
# You can also supply a hash where the value is a boolean determining whether
|
# You can also supply a hash where the value is a boolean determining whether
|
||||||
# or not authentication should be aborted when the value is not present.
|
# or not authentication should be aborted when the value is not present.
|
||||||
# config.authentication_keys = [ :email ]
|
config.authentication_keys = [ :username ]
|
||||||
|
|
||||||
# Configure parameters from the request object used for authentication. Each entry
|
# Configure parameters from the request object used for authentication. Each entry
|
||||||
# given should be a request method and it will automatically be passed to the
|
# given should be a request method and it will automatically be passed to the
|
||||||
@ -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
|
||||||
|
@ -10,6 +10,7 @@ Velocipede::Application.routes.draw do
|
|||||||
scope 'v1', :module => :v1 do
|
scope 'v1', :module => :v1 do
|
||||||
post 'checkin' => "logs#checkin", :as => "api_checkin"
|
post 'checkin' => "logs#checkin", :as => "api_checkin"
|
||||||
post 'checkout' => "logs#checkout", :as => "api_checkout"
|
post 'checkout' => "logs#checkout", :as => "api_checkout"
|
||||||
|
post 'reset' => "users#password_reset", :as => "api_password_reset"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
6
db/migrate/20130525143240_add_username_to_user.rb
Normal file
6
db/migrate/20130525143240_add_username_to_user.rb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class AddUsernameToUser < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :users, :username, :string
|
||||||
|
add_index :users, :username, :unique => true
|
||||||
|
end
|
||||||
|
end
|
10
db/schema.rb
10
db/schema.rb
@ -11,7 +11,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 => 20130424005701) do
|
ActiveRecord::Schema.define(:version => 20130525143240) do
|
||||||
|
|
||||||
create_table "bike_actions", :force => true do |t|
|
create_table "bike_actions", :force => true do |t|
|
||||||
t.string "action", :limit => 128, :null => false
|
t.string "action", :limit => 128, :null => false
|
||||||
@ -155,9 +155,9 @@ ActiveRecord::Schema.define(:version => 20130424005701) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
create_table "user_role_joins", :force => true do |t|
|
create_table "user_role_joins", :force => true do |t|
|
||||||
t.integer "role_id"
|
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"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
end
|
end
|
||||||
@ -182,10 +182,12 @@ ActiveRecord::Schema.define(:version => 20130424005701) do
|
|||||||
t.string "first_name", :default => "", :null => false
|
t.string "first_name", :default => "", :null => false
|
||||||
t.string "last_name", :default => "", :null => false
|
t.string "last_name", :default => "", :null => false
|
||||||
t.string "nickname"
|
t.string "nickname"
|
||||||
|
t.string "username"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "users", ["bike_id"], :name => "index_users_on_bike_id", :unique => true
|
add_index "users", ["bike_id"], :name => "index_users_on_bike_id", :unique => true
|
||||||
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
|
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
|
||||||
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
|
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
|
||||||
|
add_index "users", ["username"], :name => "index_users_on_username", :unique => true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
factory :user do
|
factory :user do
|
||||||
|
sequence(:username) { |n| "user_#{n}" }
|
||||||
sequence(:email) { |n| "user_#{n}@example.com" }
|
sequence(:email) { |n| "user_#{n}@example.com" }
|
||||||
password 'password'
|
password 'password'
|
||||||
password_confirmation { password }
|
password_confirmation { password }
|
||||||
@ -11,6 +12,7 @@ FactoryGirl.define do
|
|||||||
end
|
end
|
||||||
|
|
||||||
factory :staff do
|
factory :staff do
|
||||||
|
username "staff"
|
||||||
first_name 'Staff'
|
first_name 'Staff'
|
||||||
after_build do |r|
|
after_build do |r|
|
||||||
r.roles << (Role.find_by_role("staff") || FactoryGirl.create(:role_staff))
|
r.roles << (Role.find_by_role("staff") || FactoryGirl.create(:role_staff))
|
||||||
@ -18,6 +20,7 @@ FactoryGirl.define do
|
|||||||
end
|
end
|
||||||
|
|
||||||
factory :admin do
|
factory :admin do
|
||||||
|
username "admin"
|
||||||
first_name 'Admin'
|
first_name 'Admin'
|
||||||
after_build do |r|
|
after_build do |r|
|
||||||
r.roles << (Role.find_by_role("admin") || FactoryGirl.create(:role_admin))
|
r.roles << (Role.find_by_role("admin") || FactoryGirl.create(:role_admin))
|
||||||
@ -25,6 +28,7 @@ FactoryGirl.define do
|
|||||||
end
|
end
|
||||||
|
|
||||||
factory :bike_admin do
|
factory :bike_admin do
|
||||||
|
username "bike_admin"
|
||||||
first_name 'BikeAdmin'
|
first_name 'BikeAdmin'
|
||||||
after_build do |r|
|
after_build do |r|
|
||||||
r.roles << (Role.find_by_role("bike_admin") || FactoryGirl.create(:role_bike_admin))
|
r.roles << (Role.find_by_role("bike_admin") || FactoryGirl.create(:role_bike_admin))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user