mirror of
				https://github.com/fspc/BikeShed-1.git
				synced 2025-11-04 01:15:36 -05:00 
			
		
		
		
	merging master
This commit is contained in:
		
						commit
						b450baa3dc
					
				@ -12,5 +12,4 @@
 | 
			
		||||
//
 | 
			
		||||
//= require jquery
 | 
			
		||||
//= require jquery_ujs
 | 
			
		||||
//= require twitter/bootstrap
 | 
			
		||||
//= require_tree .
 | 
			
		||||
//= require custom_netzke_helpers
 | 
			
		||||
 | 
			
		||||
@ -3,3 +3,150 @@ Ext.Ajax.on('requestexception', function(conn, response, options) {
 | 
			
		||||
  if (response.status === 401) { window.location = '/users/sign_in'; }
 | 
			
		||||
}, 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|
 | 
			
		||||
    c.icon = :door_out
 | 
			
		||||
    c.text = "Sign out #{controller.current_user.email}" if controller.current_user
 | 
			
		||||
    c.text = "Exit"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  action :check_out do |c|
 | 
			
		||||
@ -11,6 +11,11 @@ class AppTabPanel < Netzke::Basepack::TabPanel
 | 
			
		||||
    c.text = "CHECK OUT" if controller.current_user
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  action :change_account_info do |c|
 | 
			
		||||
    c.icon = :user_edit
 | 
			
		||||
    c.text = "Change Email/Password"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def configure(c)
 | 
			
		||||
 | 
			
		||||
    #all users
 | 
			
		||||
@ -48,7 +53,9 @@ class AppTabPanel < Netzke::Basepack::TabPanel
 | 
			
		||||
    if can? :manage, Role
 | 
			
		||||
      @@app_tab_panel_items.concat [{ layout: :fit,
 | 
			
		||||
                                      wrappedComponent: :user_role_joins,
 | 
			
		||||
                                      title: "User Roles"}]
 | 
			
		||||
                                      title: "User Roles"},
 | 
			
		||||
                                      :check_ins
 | 
			
		||||
                                      ]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    @@app_tab_panel_items.each do |item|
 | 
			
		||||
@ -59,7 +66,7 @@ class AppTabPanel < Netzke::Basepack::TabPanel
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    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
 | 
			
		||||
    super
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -17,5 +17,8 @@
 | 
			
		||||
         });
 | 
			
		||||
       }
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  onChangeAccountInfo: function(){
 | 
			
		||||
    window.location.href="users/edit";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,8 @@ class Bikes < Netzke::Basepack::Grid
 | 
			
		||||
                    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 => :seat_tube_height, :text => 'Seat Tube (in)'},
 | 
			
		||||
      { :name => :top_tube_length, :text => 'Top Tube (in)'},
 | 
			
		||||
@ -32,6 +33,23 @@ class Bikes < Netzke::Basepack::Grid
 | 
			
		||||
    ]
 | 
			
		||||
  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
 | 
			
		||||
  def default_bbar
 | 
			
		||||
    [ :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!
 | 
			
		||||
      this.selectBikeBrand({bike_brand_id: record.get('bike_brand__brand')});
 | 
			
		||||
    }, 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
 | 
			
		||||
    %Q(
 | 
			
		||||
      <div id="user_stats_page">
 | 
			
		||||
        <p>Username: #{user.username}</p>
 | 
			
		||||
        <p>Total Hours Worked: #{user.total_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>
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,28 @@
 | 
			
		||||
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)
 | 
			
		||||
    super
 | 
			
		||||
    c.header = false
 | 
			
		||||
    c.model = "User"
 | 
			
		||||
 | 
			
		||||
    c.columns = [
 | 
			
		||||
      :username,
 | 
			
		||||
      :first_name,
 | 
			
		||||
      :last_name,
 | 
			
		||||
      :nickname,
 | 
			
		||||
      :email,
 | 
			
		||||
      :bike__shop_id
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    c.columns << :reset if can? :manage, User
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  #override with nil to remove actions
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,32 @@
 | 
			
		||||
    this.callParent();
 | 
			
		||||
    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!
 | 
			
		||||
      console.log("user: " + record.get('id') );
 | 
			
		||||
      this.selectCustomer({customer_id: record.get('id'), customer_type: 'User'});
 | 
			
		||||
    }, 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
 | 
			
		||||
    c.header = false
 | 
			
		||||
    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_logs, region: :east, split: true}
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
  attr_accessible :email, :password, :password_confirmation, :remember_me,
 | 
			
		||||
    :first_name, :last_name, :nickname, :bike_id,
 | 
			
		||||
    :user_profiles_attributes
 | 
			
		||||
    :user_profiles_attributes, :username
 | 
			
		||||
 | 
			
		||||
  has_many :transactions
 | 
			
		||||
  has_many :user_profiles
 | 
			
		||||
@ -26,6 +26,10 @@ class User < ActiveRecord::Base
 | 
			
		||||
    "#{first_name} #{last_name}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def email_required?
 | 
			
		||||
    false
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def full_name
 | 
			
		||||
    to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,15 @@
 | 
			
		||||
class UserProfile < ActiveRecord::Base
 | 
			
		||||
  # Setup accessible (or protected) attributes for your model
 | 
			
		||||
  attr_accessible :user_id, :addrStreet1, :addrStreet2, :addrCity,
 | 
			
		||||
    :addrState, :addrZip, :phone
 | 
			
		||||
 | 
			
		||||
  belongs_to :user
 | 
			
		||||
  belongs_to :bike
 | 
			
		||||
 | 
			
		||||
 #validates :addrStreet1 , :presence => true
 | 
			
		||||
 #validates :addrCity , :presence => true
 | 
			
		||||
 #validates :addrState , :presence => true
 | 
			
		||||
 #validates :addrZip , :presence => true
 | 
			
		||||
  validates :phone, :presence => true
 | 
			
		||||
  #validates :addrStreet1 , :presence => true
 | 
			
		||||
  #validates :addrCity , :presence => true
 | 
			
		||||
  #validates :addrState , :presence => true
 | 
			
		||||
  #validates :addrZip , :presence => true
 | 
			
		||||
  #validates :phone, :presence => true
 | 
			
		||||
 | 
			
		||||
  def to_s
 | 
			
		||||
    [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>
 | 
			
		||||
 | 
			
		||||
<%= 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
 | 
			
		||||
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
 | 
			
		||||
  = devise_error_messages!
 | 
			
		||||
  %div
 | 
			
		||||
    = f.label :username
 | 
			
		||||
    %br/
 | 
			
		||||
    = f.text_field :username
 | 
			
		||||
  %div
 | 
			
		||||
    = f.label :first_name
 | 
			
		||||
    %br/
 | 
			
		||||
@ -18,7 +23,8 @@
 | 
			
		||||
    %br/
 | 
			
		||||
    = f.email_field :email
 | 
			
		||||
  %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
 | 
			
		||||
  %div
 | 
			
		||||
    = f.label :password
 | 
			
		||||
 | 
			
		||||
@ -3,8 +3,8 @@
 | 
			
		||||
<h2>Velocipede</h2>
 | 
			
		||||
 | 
			
		||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
 | 
			
		||||
  <div><%= f.label :email %><br />
 | 
			
		||||
    <%= f.email_field :email %></div>
 | 
			
		||||
  <div><%= f.label :username%><br />
 | 
			
		||||
    <%= f.text_field :username%></div>
 | 
			
		||||
 | 
			
		||||
  <div><%= f.label :password %><br />
 | 
			
		||||
    <%= f.password_field :password %></div>
 | 
			
		||||
@ -28,9 +28,9 @@
 | 
			
		||||
<% if Rails.env.development? %>
 | 
			
		||||
  <% User.all.each do |user| %>
 | 
			
		||||
    <%= 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>
 | 
			
		||||
      <div><%= f.submit "Sign in as #{user.email}" %></div>
 | 
			
		||||
      <div><%= f.submit "Sign in as #{user.username}" %></div>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
@ -28,3 +28,4 @@
 | 
			
		||||
        %p © Velocipede 2013
 | 
			
		||||
 | 
			
		||||
    = 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.
 | 
			
		||||
  # 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.
 | 
			
		||||
  # config.authentication_keys = [ :email ]
 | 
			
		||||
  config.authentication_keys = [ :username ]
 | 
			
		||||
 | 
			
		||||
  # 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
 | 
			
		||||
@ -38,12 +38,12 @@ Devise.setup do |config|
 | 
			
		||||
  # Configure which authentication keys should be case-insensitive.
 | 
			
		||||
  # These keys will be downcased upon creating or modifying a user and when used
 | 
			
		||||
  # 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.
 | 
			
		||||
  # 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.
 | 
			
		||||
  config.strip_whitespace_keys = [ :email ]
 | 
			
		||||
  config.strip_whitespace_keys = [ :username ]
 | 
			
		||||
 | 
			
		||||
  # 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
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,7 @@ Velocipede::Application.routes.draw do
 | 
			
		||||
    scope 'v1', :module => :v1 do
 | 
			
		||||
      post 'checkin' => "logs#checkin", :as => "api_checkin"
 | 
			
		||||
      post 'checkout' => "logs#checkout", :as => "api_checkout"
 | 
			
		||||
      post 'reset' => "users#password_reset", :as => "api_password_reset"
 | 
			
		||||
    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.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(:version => 20130424005701) do
 | 
			
		||||
ActiveRecord::Schema.define(:version => 20130525143240) do
 | 
			
		||||
 | 
			
		||||
  create_table "bike_actions", :force => true do |t|
 | 
			
		||||
    t.string   "action",     :limit => 128, :null => false
 | 
			
		||||
@ -155,9 +155,9 @@ ActiveRecord::Schema.define(:version => 20130424005701) do
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "user_role_joins", :force => true do |t|
 | 
			
		||||
    t.integer  "role_id"
 | 
			
		||||
    t.datetime "created_at", :null => false
 | 
			
		||||
    t.datetime "updated_at", :null => false
 | 
			
		||||
    t.integer  "role_id",    :limit => 255
 | 
			
		||||
    t.datetime "created_at",                :null => false
 | 
			
		||||
    t.datetime "updated_at",                :null => false
 | 
			
		||||
    t.datetime "ends"
 | 
			
		||||
    t.integer  "user_id"
 | 
			
		||||
  end
 | 
			
		||||
@ -182,10 +182,12 @@ ActiveRecord::Schema.define(:version => 20130424005701) do
 | 
			
		||||
    t.string   "first_name",             :default => "", :null => false
 | 
			
		||||
    t.string   "last_name",              :default => "", :null => false
 | 
			
		||||
    t.string   "nickname"
 | 
			
		||||
    t.string   "username"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  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", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
 | 
			
		||||
  add_index "users", ["username"], :name => "index_users_on_username", :unique => true
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
FactoryGirl.define do
 | 
			
		||||
  factory :user do
 | 
			
		||||
    sequence(:username) { |n| "user_#{n}" }
 | 
			
		||||
    sequence(:email) { |n| "user_#{n}@example.com" }
 | 
			
		||||
    password 'password'
 | 
			
		||||
    password_confirmation { password }
 | 
			
		||||
@ -11,6 +12,7 @@ FactoryGirl.define do
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    factory :staff do
 | 
			
		||||
      username "staff"
 | 
			
		||||
      first_name 'Staff'
 | 
			
		||||
      after_build do |r|
 | 
			
		||||
        r.roles << (Role.find_by_role("staff") || FactoryGirl.create(:role_staff))
 | 
			
		||||
@ -18,6 +20,7 @@ FactoryGirl.define do
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    factory :admin do
 | 
			
		||||
      username "admin"
 | 
			
		||||
      first_name 'Admin'
 | 
			
		||||
      after_build do |r|
 | 
			
		||||
        r.roles << (Role.find_by_role("admin") || FactoryGirl.create(:role_admin))
 | 
			
		||||
@ -25,6 +28,7 @@ FactoryGirl.define do
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    factory :bike_admin do
 | 
			
		||||
      username "bike_admin"
 | 
			
		||||
      first_name 'BikeAdmin'
 | 
			
		||||
      after_build do |r|
 | 
			
		||||
        r.roles << (Role.find_by_role("bike_admin") || FactoryGirl.create(:role_bike_admin))
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user