53 Commits
members ... csv

Author SHA1 Message Date
25c0d1e1cb Finalized payments and CSVs and inactivity 2013-08-28 08:19:01 -07:00
e8e024c042 Adding CSV show 2013-08-28 05:14:10 -07:00
10a1e4eb84 Switching to RVM, View tweaks 2013-08-28 05:15:50 -07:00
211d79cbcd Adding csv import 2013-08-28 04:25:54 -07:00
69a57bc63b Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-28 03:19:09 -07:00
c662be6dc0 IPN improvements 2013-08-28 03:18:47 -07:00
ca7808a525 Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-27 23:06:43 -07:00
9fb2507aa1 Updating coin 2013-08-27 23:06:16 -07:00
0be2834a5d Minor status tweak 2013-08-27 00:39:43 -07:00
ef46bf6a98 Adjusting ranking method 2013-08-27 00:09:54 -07:00
45bac6cae4 Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-26 23:40:40 -07:00
4dba2b8c3d Adding status symbols 2013-08-26 23:39:54 -07:00
18bc427eb3 Adding quick-add buttons to user profiles 2013-08-26 23:01:43 -07:00
810ff6b034 De-duplicating cert view 2013-08-26 22:32:08 -07:00
ae031838dc Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-26 22:15:54 -07:00
59b6e3c838 Updating nav 2013-08-26 22:12:45 -07:00
98be42e9f9 Fixing nil errors 2013-08-26 22:11:04 -07:00
b5d9514914 Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-26 22:09:37 -07:00
125ad76a1c Hacks to allow 1.8.7 2013-08-26 22:07:41 -07:00
4067477cd4 Updating icons, fixing user cert nil error 2013-08-26 22:05:53 -07:00
9e4b79a353 Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-26 15:39:18 -07:00
f8f11e3d7e Adjust IPN security 2013-08-26 15:34:10 -07:00
805148ee40 Merge branch 'ipn' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into ipn 2013-08-24 03:44:00 -07:00
f111769b20 Remove debug, update schema 2013-08-24 03:43:43 -07:00
eb782f11d5 Adding IPN validation 2013-08-24 03:40:34 -07:00
ec4cf4dea9 Adding IPNs 2013-08-24 02:18:37 -07:00
75e4907a9c Usability tweaks, creating merges, fixing issues 2013-05-23 23:25:09 -07:00
20a007cac5 Instructors can delete their own certs; hidden users are hidden in drop-downs; admins can see last user login; prepping for postgres 2013-05-03 00:16:02 -07:00
719b9447ab Merge branch 'pamela' of github.com:zyphlar/Open-Source-Access-Control-Web-Interface into pamela 2013-02-18 23:29:44 -07:00
8a7fe29f6d Changing lapsed member math to be more accurate & give more info 2013-02-18 23:29:06 -07:00
e630c81298 Resolving nil error for access cards / logs 2013-02-14 23:00:01 -07:00
cefd4b3878 Added nice front page stuff, fixing sqlite issues, adding user payments to profiles 2013-02-14 00:29:22 -07:00
ed75ea0e90 Adding payments 2013-02-12 01:58:17 -07:00
3fb774d057 Adding note to macs json feed 2013-02-09 05:05:06 -07:00
0ced399651 Adjusted profile page to make avatar more clear 2013-02-09 04:21:42 -07:00
02920837e2 Updated new user email to include survey and link to user 2013-02-09 04:11:58 -07:00
63913c0be3 Forgot migration from previous commit. Also added links to home page 2013-02-09 04:01:21 -07:00
ac66cb0cbe Added "how did you hear about us" to user. 2013-02-09 03:47:07 -07:00
1f63709887 Reporting door access logs on each card's page; also card access stats for last 7 days 2013-02-09 03:32:26 -07:00
3f3eb1ed65 Allowed admins to see hidden users, added "no orientation" message to main page and hid new people from non-oriented people 2013-02-09 02:51:35 -07:00
f1b752a4c4 Updating homepage to display cooler door/mac stats 2013-02-09 02:40:38 -07:00
2d0735e914 Replaced "authok" with "ok" on OAC-Ethernet API, changing to match 2013-02-09 02:08:43 -07:00
d156edd683 Updating how macs are stored/viewed 2013-02-09 02:08:29 -07:00
1b64a6b931 Changing email to 2013-02-01 05:03:18 -07:00
1239d6682b Added mailer to notify on new user 2013-02-01 04:44:05 -07:00
50171effad Allowing JSON 2013-02-01 03:58:26 -07:00
43e2cdba78 Finished mac filtering, display, permissions, etc 2013-02-01 03:37:30 -07:00
f3498ddcac Added mac logs, improved mac editing/viewing 2013-02-01 00:06:13 -07:00
04764af983 Got macs working 2013-01-31 22:39:33 -07:00
998558cd30 Figured out mac saving issue 2013-01-31 21:25:54 -07:00
048ce52111 Renaming pamela to macs 2013-01-31 20:48:27 -07:00
a7e999614c Adding pamela but I'm dumb and messed up routing 2013-01-31 20:33:40 -07:00
6673573e36 Updated front page stats to fix dupes 2013-01-31 19:15:35 -07:00
120 changed files with 2467 additions and 117 deletions

35
.rvmrc Normal file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# This is an RVM Project .rvmrc file, used to automatically load the ruby
# development environment upon cd'ing into the directory
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
# Only full ruby name is supported here, for short names use:
# echo "rvm use 1.8.7" > .rvmrc
environment_id="ruby-1.9.3-p385@members-hsl"
# Uncomment the following lines if you want to verify rvm version per project
# rvmrc_rvm_version="1.18.8 (stable)" # 1.10.1 seams as a safe start
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
# return 1
# }
# First we attempt to load the desired environment directly from the environment
# file. This is very fast and efficient compared to running through the entire
# CLI and selector. If you want feedback on which environment was used then
# insert the word 'use' after --create as this triggers verbose mode.
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
then
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
else
# If the environment file has not yet been created, use the RVM CLI to select.
rvm --create "$environment_id" || {
echo "Failed to create RVM environment '${environment_id}'."
return 1
}
fi

View File

@@ -1,5 +1,7 @@
source 'https://rubygems.org' source 'https://rubygems.org'
ruby '1.9.3'
gem 'rails', '3.2.3' gem 'rails', '3.2.3'
# Bundle edge Rails instead: # Bundle edge Rails instead:
@@ -40,7 +42,9 @@ gem 'bcrypt-ruby', '~> 3.0.0'
# gem 'capistrano' # gem 'capistrano'
# To use debugger # To use debugger
# gem 'ruby-debug' #gem 'debugger'
#gem "paperclip", "~> 3.0" #gem "paperclip", "~> 3.0"
gem 'gravtastic' gem 'gravtastic'
gem 'passenger'

View File

@@ -39,6 +39,7 @@ GEM
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.3.3) coffee-script-source (1.3.3)
daemon_controller (1.1.5)
devise (2.1.1) devise (2.1.1)
bcrypt-ruby (~> 3.0) bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
@@ -63,6 +64,10 @@ GEM
mime-types (1.19) mime-types (1.19)
multi_json (1.3.6) multi_json (1.3.6)
orm_adapter (0.1.0) orm_adapter (0.1.0)
passenger (4.0.14)
daemon_controller (>= 1.1.0)
rack
rake (>= 0.8.1)
polyglot (0.3.3) polyglot (0.3.3)
rack (1.4.1) rack (1.4.1)
rack-cache (1.2) rack-cache (1.2)
@@ -124,6 +129,7 @@ DEPENDENCIES
gravtastic gravtastic
jquery-rails jquery-rails
json json
passenger
rails (= 3.2.3) rails (= 3.2.3)
sass-rails (~> 3.2.3) sass-rails (~> 3.2.3)
sqlite3 sqlite3

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View File

@@ -11,3 +11,38 @@
*= require_self *= require_self
*= require_tree . *= require_tree .
*/ */
.caption { display: inline-block; background-color: #eee; border: 1px solid #333; border-radius: 5px; margin-bottom: 1em; }
.btn {
display: inline-block;
padding: 4px 10px 4px;
margin-bottom: 0;
font-size: 13px;
line-height: 18px;
color: #333;
text-align: center;
text-decoration: none;
text-shadow: 0 1px 1px rgba(255,255,255,.75);
vertical-align: middle;
background-color: #f5f5f5;
background-image: -moz-linear-gradient(top, #fff, #e6e6e6);
background-image: -ms-linear-gradient(top, #fff, #e6e6e6);
background-image: -webkit-gradient(linear,0 0,0 100%,from( #fff),to( #e6e6e6));
background-image: -webkit-linear-gradient(top, #fff, #e6e6e6);
background-image: -o-linear-gradient(top, #fff, #e6e6e6);
background-image: linear-gradient(top, #fff, #e6e6e6);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
border: 1px solid #ccc;
border-bottom-color: #bbb;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);
box-shadow: inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);
cursor: pointer;
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
}

View File

@@ -1,3 +1,4 @@
// Place all the styles related to the home controller here. // Place all the styles related to the home controller here.
// They will automatically be included in application.css. // They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/ // You can use Sass (SCSS) here: http://sass-lang.com/
table, td { vertical-align: top }

View File

@@ -0,0 +1,3 @@
// Place all the styles related to the Ipn controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@@ -0,0 +1,3 @@
// Place all the styles related to the MacLogs controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@@ -0,0 +1,4 @@
// Place all the styles related to the pamela controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
.hidden { color: #ccc; }

View File

@@ -0,0 +1,3 @@
// Place all the styles related to the Payments controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@@ -9,6 +9,23 @@ class CardsController < ApplicationController
#authorize! :read, @cards #authorize! :read, @cards
@cards = @cards.sort_by{|e| e[:id]} @cards = @cards.sort_by{|e| e[:id]}
if can? :read, DoorLog then
Rails.logger.info "CARD STATS:"
most_active_count = 0
@most_active_card = nil
@cards.each do |card|
card_num_R = card.card_number.to_i(16)%32767
Rails.logger.info card_num_R
card[:accesses_this_week] = DoorLog.where('key = "G" AND data =? AND created_at > ?', card_num_R, DateTime.now - 7.days).order("created_at DESC").count
Rails.logger.info card[:accesses_this_week]
if(card[:accesses_this_week] > most_active_count) then
Rails.logger.info "ACTIVE"
most_active_count = card[:accesses_this_week]
@most_active_card = card
end
end
end
respond_to do |format| respond_to do |format|
format.html # index.html.erb format.html # index.html.erb
format.json { render :json => @cards } format.json { render :json => @cards }
@@ -18,8 +35,10 @@ class CardsController < ApplicationController
# GET /cards/1 # GET /cards/1
# GET /cards/1.json # GET /cards/1.json
def show def show
#@card = Card.find(params[:id]) if can? :read, DoorLog then
card_num_R = @card.card_number.to_i(16)%32767
@door_logs = DoorLog.where('key = "R" AND data =?', card_num_R).order("created_at DESC")
end
respond_to do |format| respond_to do |format|
format.html # show.html.erb format.html # show.html.erb
format.json { render :json => @card } format.json { render :json => @card }

View File

@@ -5,10 +5,18 @@ def index
@recent_certs = UserCertification.where("created_at > ?", DateTime.now - 7.days).count @recent_certs = UserCertification.where("created_at > ?", DateTime.now - 7.days).count
@num_users = User.count @num_users = User.count
@recent_users = User.where("created_at > ?", DateTime.now - 7.days).count @recent_users = User.where("created_at > ?", DateTime.now - 7.days).count
@num_paid_users = User.all.select{|u| u.member_status >= 250 }.count
@num_delinquent_users = User.all.select{|u| !u.payment_status }.count
if can? :read, User then
@recent_user_names = User.where("member_level > 10").accessible_by(current_ability).order('created_at desc').limit(5)
end
@num_door_opens = DoorLog.where("key = 'G'").count @num_door_opens = DoorLog.where("key = 'G'").count
@today_door_opens = DoorLog.where("key = 'G' AND created_at > ?", DateTime.now - 1.day).count
@recent_door_opens = DoorLog.where("key = 'G' AND created_at > ?", DateTime.now - 7.days).count @recent_door_opens = DoorLog.where("key = 'G' AND created_at > ?", DateTime.now - 7.days).count
@num_door_denieds = DoorLog.where("key = 'D'").count @num_door_denieds = DoorLog.where("key = 'f'").count
@recent_door_denieds = DoorLog.where("key = 'D' AND created_at > ?", DateTime.now - 7.days).count @recent_door_denieds = DoorLog.where("key = 'f' AND created_at > ?", DateTime.now - 7.days).count
@num_macs = Mac.count
@recent_macs = Mac.where("since > ?", DateTime.now - 1.day).count
respond_to do |format| respond_to do |format|
format.html # index.html.erb format.html # index.html.erb

View File

@@ -0,0 +1,54 @@
class IpnsController < ApplicationController
load_and_authorize_resource :ipn, :except => [:new, :create]
before_filter :authenticate_user!, :except => [:new, :create]
protect_from_forgery :except => [:create]
def index
@ipns = Ipn.all
end
def show
end
def new
end
def create
@ipn = Ipn.new_from_dynamic_params(params)
@ipn.data = params.to_json
@ipn.save
render :nothing => true
#unless @ipn.validate!
# Rails.logger.error "Unable to validate IPN: #{@ipn.inspect}"
#end
end
def import
@ipn = Ipn.new_from_dynamic_params(params)
@ipn.data = params.to_json
@ipn.save
redirect_to ipn_path(@ipn)
#unless @ipn.validate!
# Rails.logger.error "Unable to validate IPN: #{@ipn.inspect}"
#end
end
def validate
if @ipn.validate!
redirect_to ipns_url, :notice => 'Valid!'
else
redirect_to ipns_url, :notice => 'INVALID'
end
end
def link
result = @ipn.link_payment
if result.first
redirect_to ipns_url, :notice => 'Payment was successfully linked.'
else
redirect_to ipns_url, :notice => result.last
end
end
end

View File

@@ -0,0 +1,9 @@
class MacLogsController < ApplicationController
load_and_authorize_resource :mac_log
before_filter :authenticate_user!
def index
@mac_logs = MacLog.desc.limit(1000)
end
end

View File

@@ -0,0 +1,261 @@
class MacsController < ApplicationController
rescue_from CanCan::AccessDenied do |exception|
today = Date.today
event = Date.new(2013,9,1)
if today == event
redirect_to main_app.root_url, :alert => "CryptoParty today; no MAC scanning. Sorry, NSA!"
else
redirect_to main_app.root_url, :alert => "Nothing to see here!"
end
end
load_and_authorize_resource :mac
load_and_authorize_resource :user, :through => :mac, :except => [:index, :show, :scan, :import]
#require "active_record"
require "optparse"
#require "rubygems"
def index
#@active_macs = Mac.where(:active => true, :hidden => false)
#@active_macs += Mac.where(:active => true, :hidden => nil)
# De-dupe users for the public
if can? :update, Mac then
@active_macs = Mac.where("macs.active = ? AND (macs.hidden IS NULL OR macs.hidden = ?)", true, false).includes(:user).order("users.name ASC")
elsif user_signed_in? then
@active_macs = Mac.where("macs.active = ? AND (macs.hidden IS NULL OR macs.hidden = ?)", true, false).includes(:user).order("users.name ASC").group("users.name")
else
@active_macs = Mac.select("mac, note, user_id").where("macs.active = ? AND (macs.hidden IS NULL OR macs.hidden = ?)", true, false).joins(:user).order("users.name ASC").group("users.name")
end
@hidden_macs = Mac.where("macs.active = ? AND macs.hidden = ?", true, true).order("note ASC")
@all_macs = Mac.find(:all, :order => "LOWER(mac)")
respond_to do |format|
format.html
format.json {
@filtered_macs = Mac.select("macs.mac, users.name, macs.note").where("macs.active = ? AND (macs.hidden IS NULL OR macs.hidden = ?)", true, false).joins(:user)
render :json => @filtered_macs
}
end
end
# GET /macs/1
# GET /macs/1.json
def show
@mac = Mac.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => @macs }
end
end
# GET /macs/new
# GET /macs/new.json
def new
@mac = Mac.new
if can? :manage, Mac then
@users = User.accessible_by(current_ability).sort_by(&:name)
else
@users = [current_user]
end
respond_to do |format|
format.html # new.html.erb
format.json { render :json => @mac }
end
end
# GET /macs/1/edit
def edit
@mac = Mac.find(params[:id])
if can? :manage, Mac then
@users = User.accessible_by(current_ability).sort_by(&:name)
else
@users = [current_user]
end
end
# POST /macs
# POST /user
def create
@mac = Mac.new(params[:mac])
authorize! :update, @mac
if can? :manage, Mac then
@users = User.accessible_by(current_ability).sort_by(&:name)
else
@users = [current_user]
end
respond_to do |format|
if @mac.save
format.html { redirect_to macs_path, :notice => 'Mac was successfully created.' }
format.json { render :json => @mac, :status => :created, :location => @mac }
else
format.html { render :action => "new" }
format.json { render :json => @mac.errors, :status => :unprocessable_entity }
end
end
end
# PUT /macs/1
# PUT /macs/1.json
def update
#Log who updated this
@mac = Mac.find(params[:id])
@mac.assign_attributes(params[:mac])
#@mac.user_id = params[:mac][:user_id]
authorize! :update, @mac
if can? :manage, Mac then
@users = User.accessible_by(current_ability).sort_by(&:name)
else
@users = [current_user]
end
respond_to do |format|
if @mac.save
format.html { redirect_to macs_path, :notice => 'Mac was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => @mac.errors, :status => :unprocessable_entity }
end
end
end
def scan
Rails.logger.info "starting scan..."
# Command line arguments
options = {};
OptionParser.new { |opts|
opts.banner = "Usage: pamela-scanner.rb --interface=en0"
options[:verbose] = true
opts.on("v", "--verbose", "Run verbosely") { |verbose|
options[:verbose] = verbose
}
options[:interface] = "eth0"
opts.on("i", "--interface=interface", "Network Interface") { |interface|
options[:interface] = interface
}
options[:max_age] = 20
opts.on("a", "--max-age=minutes", "Minutes to keep expired macs active") { |max_age|
options[:max_age] = max_age.to_i
}
options[:db_host] = "configure_me"
opts.on("r", "--db-host=host", "Database Host") { |host|
options[:db_host] = host
}
options[:db_name] = "configure_me"
opts.on("n", "--db-name=name", "Database Name") { |name|
options[:db_name] = name
}
options[:db_user] = "configure_me"
opts.on("u", "--db-user=user", "Database User") { |user|
options[:db_user] = user
}
options[:db_password] = "configure_me"
opts.on("p", "--db-password=password", "Database Password") { |password|
options[:db_password] = password
}
}.parse!
# Open the database
#ActiveRecord::Base::establish_connection(
# :adapter => "mysql2",
# :host => options[:db_host],
# :database => options[:db_name],
# :username => options[:db_user],
# :password => options[:db_password])
#class Mac < ActiveRecord::Base
#end
#class MacLog < ActiveRecord::Base
#end
# Scan the network for mac addresses
macs = {};
command = sprintf("arp-scan -R --interface=%s --localnet", options[:interface])
if options[:verbose]
Rails.logger.info "Running [#{command}]"
end
IO.popen(command) { |stdin|
Rails.logger.info "Reading stdin: "+stdin.inspect
stdin.each { |line|
next if line !~ /^([\d\.]+)\s+([[:xdigit:]:]+)\s/;
macs[$2] = $1;
}
}
# Scan the existing macs and update each record as necessary
Mac.find(:all).each { |entry|
mac = entry.mac.downcase
ip = entry.ip
if macs.has_key?(mac)
if ! entry.active || ! entry.since
Rails.logger.info "Activating #{mac} at #{ip}" if options[:verbose]
entry.since = Time.now
MacLog.new(:mac => mac, :ip => ip, :action => "activate").save
end
entry.active = 1
entry.ip = ip
entry.refreshed = Time.now
entry.save
macs.delete(mac)
next
end
# Entry is no longer current
if entry.active
ageMinutes = ((Time.now - entry.refreshed)/60).to_i
next if ageMinutes < options[:max_age]
Rails.logger.info "Deactivating #{mac}, #{ageMinutes} minutes old" if options[:verbose]
entry.active = 0
entry.save
MacLog.new(:mac => mac, :ip => ip, :action => "deactivate").save
end
}
# Add entries for any macs not already in the db
macs.each { |mac, ip|
Rails.logger.info "Activating new entry #{mac} at #{ip}" if options[:verbose]
Mac.new(:mac => mac, :ip => ip, :active => 1, :since => Time.now, :refreshed => Time.now).save
Rails.logger.info MacLog.new(:mac => mac, :ip => ip, :action => "activate").save
}
@log = MacLog.all
end #def scan
def import
require 'csv'
csv_text = File.read('mac_log.csv')
csv = CSV.parse(csv_text)
@output = []
csv.each do |row|
@output += [row[1], Mac.create({:mac => row[0], :note => row[1], :hidden => row[2]}) ]
end
end
end

View File

@@ -0,0 +1,88 @@
class PaymentsController < ApplicationController
load_and_authorize_resource :payment
load_and_authorize_resource :user, :through => :payment
before_filter :authenticate_user!
# Load users and certs based on current ability
before_filter do
@users = User.where(:hidden => false).where("member_level > 10").accessible_by(current_ability).sort_by(&:name_with_payee_and_member_level)
end
before_filter :only => [:create, :update] do
@payment.created_by = current_user.id
end
# GET /payments
# GET /payments.json
def index
@payments = @payments.order("date DESC")
respond_to do |format|
format.html # index.html.erb
format.json { render :json => @payments }
end
end
# GET /payments/1
# GET /payments/1.json
def show
respond_to do |format|
format.html # show.html.erb
format.json { render :json => @payment }
end
end
# GET /payments/new
# GET /payments/new.json
def new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => @payment }
end
end
# GET /payments/1/edit
def edit
end
# POST /payments
# POST /payments.json
def create
Rails.logger.warn "payment:"
Rails.logger.warn @payment.inspect
respond_to do |format|
if @payment.save
format.html { redirect_to payments_url, :notice => 'Payment was successfully created.' }
format.json { render :json => @payment, :status => :created, :location => @payment }
else
format.html { render :action => "new" }
format.json { render :json => @payment.errors, :status => :unprocessable_entity }
end
end
end
# PUT /payments/1
# PUT /payments/1.json
def update
respond_to do |format|
if @payment.update_attributes(params[:payment])
format.html { redirect_to payments_url, :notice => 'Payment was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => @payment.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /payments/1
# DELETE /payments/1.json
def destroy
@payment.destroy
respond_to do |format|
format.html { redirect_to payments_url }
format.json { head :no_content }
end
end
end

View File

@@ -0,0 +1,28 @@
class PaypalCsvsController < ApplicationController
load_and_authorize_resource :paypal_csv
before_filter :authenticate_user!
def index
end
def show
end
def new
end
def create
PaypalCsv.batch_import_from_csv(params[:file].path)
redirect_to paypal_csvs_path, :notice => 'Paypal CSV batch was successfully loaded.'
end
def link
result = @paypal_csv.link_payment
if result.first
redirect_to paypal_csvs_url, :notice => 'Payment was successfully linked.'
else
redirect_to paypal_csvs_url, :notice => result.last
end
end
end

View File

@@ -6,7 +6,7 @@ class UserCertificationsController < ApplicationController
# Load users and certs based on current ability # Load users and certs based on current ability
before_filter :only => [:new, :edit, :create, :update] do before_filter :only => [:new, :edit, :create, :update] do
@users = User.accessible_by(current_ability).sort_by(&:name) @users = User.where(:hidden => [false,nil]).accessible_by(current_ability).sort_by(&:name)
@certifications = Certification.accessible_by(current_ability).sort_by(&:name) @certifications = Certification.accessible_by(current_ability).sort_by(&:name)
end end

View File

@@ -15,7 +15,7 @@ class UsersController < ApplicationController
when "waiver" when "waiver"
@users = @users.sort_by{ |u| [-u.waiver.to_i,u.name] } @users = @users.sort_by{ |u| [-u.waiver.to_i,u.name] }
when "member" when "member"
@users = @users.sort_by{ |u| [-u.member.to_i,-u.member_level.to_i,u.name] } @users = @users.sort_by{ |u| [-u.member_status.to_i,u.name] }
when "card" when "card"
@users = @users.sort_by{ |u| [-u.cards.count,u.name] } @users = @users.sort_by{ |u| [-u.cards.count,u.name] }
when "instructor" when "instructor"
@@ -33,15 +33,28 @@ class UsersController < ApplicationController
end end
end end
def inactive
@users = @users.all.select{|u| u if u.payment_status == false }.sort_by{ |u| -u.delinquency }
end
# GET /users/1 # GET /users/1
# GET /users/1.json # GET /users/1.json
def show def show
@payments = Payment.where(:user_id => @user.id).order('date desc').limit(10)
respond_to do |format| respond_to do |format|
format.html # show.html.erb format.html # show.html.erb
format.json { render :json => @user } format.json { render :json => @user }
end end
end end
# GET /user_summary/1
def user_summary
respond_to do |format|
format.html { render :partial => "user_summary" } # show.html.erb
format.json { render :json => @user }
end
end
# GET /users/new # GET /users/new
# GET /users/new.json # GET /users/new.json
def new def new
@@ -60,7 +73,7 @@ class UsersController < ApplicationController
def create def create
respond_to do |format| respond_to do |format|
if @user.save if @user.save
format.html { redirect_to users_url, :notice => 'User was successfully created.' } format.html { redirect_to @user, :notice => 'User was successfully created.' }
format.json { render :json => @user, :status => :created, :location => @user } format.json { render :json => @user, :status => :created, :location => @user }
else else
format.html { render :action => "new" } format.html { render :action => "new" }
@@ -74,7 +87,7 @@ class UsersController < ApplicationController
def update def update
respond_to do |format| respond_to do |format|
if @user.update_attributes(params[:user]) if @user.update_attributes(params[:user])
format.html { redirect_to users_url, :notice => 'User was successfully updated.' } format.html { redirect_to @user, :notice => 'User was successfully updated.' }
format.json { head :no_content } format.json { head :no_content }
else else
format.html { render :action => "edit" } format.html { render :action => "edit" }
@@ -83,6 +96,37 @@ class UsersController < ApplicationController
end end
end end
# GET /users/merge
def merge_view
@users = @users.sort_by(&:name)
respond_to do |format|
format.html # merge_view.html.erb
end
end
# POST /users/merge
def merge_action
@user_to_keep = User.find(params[:user][:to_keep])
Rails.logger.info "USER TO KEEP:"
Rails.logger.info @user_to_keep.inspect
@user_to_merge = User.find(params[:user][:to_merge])
Rails.logger.info "USER TO MERGE:"
Rails.logger.info @user_to_merge.inspect
@user_to_keep.absorb_user(@user_to_merge)
Rails.logger.info "RESULT:"
Rails.logger.info @user_to_keep.inspect
Rails.logger.info @user_to_keep.cards.inspect
Rails.logger.info @user_to_keep.user_certifications.inspect
Rails.logger.info @user_to_keep.payments.inspect
respond_to do |format|
format.html { redirect_to @user_to_keep, :notice => 'Users successfully merged.' }
end
end
# DELETE /users/1 # DELETE /users/1
# DELETE /users/1.json # DELETE /users/1.json
def destroy def destroy

View File

@@ -0,0 +1,2 @@
module IpnHelper
end

View File

@@ -0,0 +1,2 @@
module MacLogsHelper
end

View File

@@ -0,0 +1,2 @@
module PamelaHelper
end

View File

@@ -0,0 +1,2 @@
module PaymentsHelper
end

View File

@@ -0,0 +1,13 @@
class UserMailer < ActionMailer::Base
default :from => "wiki@heatsynclabs.org"
def new_user_email(user)
@user = user
@url = "http://members.heatsynclabs.org"
#@admins = User.where(:name => "Will Bradley")
#@admins.each do |admin|
mail(:to => 'info@heatsynclabs.org', :subject => "New HSL Member: "+user.name)
#end
end
end

View File

@@ -2,23 +2,32 @@ class Ability
include CanCan::Ability include CanCan::Ability
def initialize(user) def initialize(user)
# Anonymous can read mac
today = Date.today
event = Date.new(2013,9,1)
unless today == event
can :read, Mac
can :scan, Mac # Need anonymous so CRON can scan
end
if !user.nil? if !user.nil?
# By default, users can only see their own stuff # By default, users can only see their own stuff
can :read, Card, :user_id => user.id can :read, Card, :user_id => user.id
can :read, Certification can :read, Certification
can :read_details, Mac unless today == event
can [:update], Mac, :user_id => nil
can [:create,:update], Mac, :user_id => user.id
can :read, User, :id => user.id #TODO: why can users update themselves? can :read, User, :id => user.id #TODO: why can users update themselves?
can :read, UserCertification, :user_id => user.id can :read, UserCertification, :user_id => user.id
# Admins can manage all
if user.admin?
can :manage, :all
end
# Instructors can manage certs and see users # Instructors can manage certs and see users
if user.instructor? if user.instructor?
can :manage, Certification can :manage, Certification
can [:create,:read], User, :hidden => [nil,false] can [:create,:read], User, :hidden => [nil,false]
can :manage, UserCertification can [:create,:read], UserCertification
can [:update,:destroy], UserCertification, :created_by => user.id
end end
# Users can see others' stuff if they've been oriented # Users can see others' stuff if they've been oriented
unless user.orientation.blank? unless user.orientation.blank?
@@ -26,12 +35,27 @@ class Ability
can :read, UserCertification can :read, UserCertification
end end
# Accountants can manage payments
if user.accountant?
can :manage, Payment
can :manage, Ipn
can :manage, PaypalCsv
end
# Admins can manage all
if user.admin?
can :manage, :all
end
# Prevent all destruction for now # Prevent all destruction for now
cannot :destroy, User #cannot :destroy, User
cannot :destroy, Card #cannot :destroy, Card
cannot :destroy, Certification cannot :destroy, Certification
cannot :destroy, UserCertification cannot :destroy, Mac
cannot :destroy, MacLog
#cannot :destroy, UserCertification
cannot :destroy, DoorLog cannot :destroy, DoorLog
# no exception for destroying payments
end end
# Define abilities for the passed in user here. For example: # Define abilities for the passed in user here. For example:
# #

View File

@@ -2,6 +2,7 @@ class Card < ActiveRecord::Base
require 'open-uri' require 'open-uri'
attr_accessible :id, :user_id, :name, :card_number, :card_permissions attr_accessible :id, :user_id, :name, :card_number, :card_permissions
validates_presence_of :user_id, :card_number, :card_permissions
validates_uniqueness_of :id, :card_number validates_uniqueness_of :id, :card_number
belongs_to :user belongs_to :user
@@ -12,7 +13,7 @@ class Card < ActiveRecord::Base
# connect to door access system # connect to door access system
source = open("#{door_access_url}?e=#{door_access_password}").read source = open("#{door_access_url}?e=#{door_access_password}").read
results = source.scan(/authok/) results = source.scan(/ok/)
if(results.size > 0) then if(results.size > 0) then
#only continue if we've got an OK login #only continue if we've got an OK login
cardid = self.id.to_s.rjust(3, '0') #TODO: provide ability for cardid = self.id.to_s.rjust(3, '0') #TODO: provide ability for
@@ -47,7 +48,7 @@ class Card < ActiveRecord::Base
door_access_password = APP_CONFIG['door_access_password'] door_access_password = APP_CONFIG['door_access_password']
source = open("#{door_access_url}?e=#{door_access_password}").read source = open("#{door_access_url}?e=#{door_access_password}").read
results = source.scan(/authok/) results = source.scan(/ok/)
if(results.size > 0) then if(results.size > 0) then
@cards.each do |u| @cards.each do |u|
#only continue if we've got an OK login #only continue if we've got an OK login

View File

@@ -9,7 +9,7 @@ class DoorLog < ActiveRecord::Base
# connect to door access system # connect to door access system
source = open("#{door_access_url}?e=#{door_access_password}").read source = open("#{door_access_url}?e=#{door_access_password}").read
results = source.scan(/authok/) results = source.scan(/ok/)
if(results.size > 0) then if(results.size > 0) then
@end_results = Array.new @end_results = Array.new

95
app/models/ipn.rb Normal file
View File

@@ -0,0 +1,95 @@
require 'net/http'
class Ipn < ActiveRecord::Base
attr_accessible :data
belongs_to :payment
after_create :create_payment
def date_parsed
begin
Date.strptime(self.payment_date, "%H:%M:%S %b %e, %Y %Z")
rescue
Date.new
end
end
def self.new_from_dynamic_params(params)
ipn = Ipn.new()
ipn.attributes.each do |c|
unless params[c.first.to_sym].nil?
ipn[c.first.to_sym] = params[c.first.to_sym]
end
end
return ipn
end
# Post back to Paypal to make sure it's valid
def validate!
uri = URI.parse('https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate')
http = Net::HTTP.new(uri.host, uri.port)
http.open_timeout = 60
http.read_timeout = 60
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
http.use_ssl = true
response = http.post(uri.request_uri, self.data,
'Content-Length' => "#{self.data.size}",
'User-Agent' => "Ruby on Rails"
).body
unless ["VERIFIED", "INVALID"].include?(response)
Rails.logger.error "Faulty paypal result: #{response}"
return false
end
unless response == "VERIFIED"
Rails.logger.error "Invalid IPN: #{response}"
Rails.logger.error "Data: #{self.data}"
return false
end
return true
end
def link_payment
create_payment
end
private
def create_payment
# find user by email, then by payee
user = User.where("lower(email) = ?", self._from_email_address.downcase).first
user = User.where("lower(payee) = ?", self._from_email_address.downcase).first if user.nil? && self._from_email_address.present?
# Only create payments if the IPN matches a member
if user.present?
# And is a payment (not a cancellation, etc)
payment_types = ["subscr_payment","send_money"]
if payment_types.include?(self.txn_type)
# And a member level
if User.member_levels[self.payment_gross.to_i].present?
payment = Payment.new
payment.date = Date.strptime(self.payment_date, "%H:%M:%S %b %e, %Y %Z")
payment.user_id = user.id
payment.amount = self.payment_gross
if payment.save
self.payment_id = payment.id
self.save!
else
return [false, "Unable to link payment. Payment error: #{payment.errors.full_messages.first}"]
end
else
return [false, "Unable to link payment. Couldn't find membership level '#{self.payment_gross.to_i}'."]
end
else
return [false, "Unable to link payment. Transaction is a '#{self.txn_type}' instead of '#{payment_types.inspect}'."]
end
else
return [false, "Unable to link payment. Couldn't find user/payee '#{self.payer_email}'."]
end
return [true]
end
end

6
app/models/mac.rb Normal file
View File

@@ -0,0 +1,6 @@
class Mac < ActiveRecord::Base
belongs_to :user
attr_accessible :active, :ip, :mac, :refreshed, :since, :hidden, :note, :user_id
validates_uniqueness_of :mac, :case_sensitive => false
end

5
app/models/mac_log.rb Normal file
View File

@@ -0,0 +1,5 @@
class MacLog < ActiveRecord::Base
attr_accessible :action, :ip, :mac
scope :desc, order("mac_logs.created_at DESC")
end

17
app/models/payment.rb Normal file
View File

@@ -0,0 +1,17 @@
class Payment < ActiveRecord::Base
belongs_to :user
has_one :ipn
has_one :paypal_csv
attr_accessible :date, :user_id, :created_by, :amount
validates_presence_of :user_id, :date, :amount # not created_by
validates_uniqueness_of :date, :scope => :user_id, :message => ' of payment already exists for this user.'
def human_date
if date.year < DateTime.now.year
date.strftime("%b %e, %y")
else
date.strftime("%b %e")
end
end
end

73
app/models/paypal_csv.rb Normal file
View File

@@ -0,0 +1,73 @@
require 'csv'
class PaypalCsv < ActiveRecord::Base
attr_accessible :data, :_address_status, :_counterparty_status, :_currency, :_fee, :_from_email_address, :_gross, :_item_id, :_item_title, :_name, :_net, :_status, :_time, :_time_zone, :_to_email_address, :_transaction_id, :_type, :date, :string
belongs_to :payment
after_create :create_payment
def date_parsed
begin
Date.strptime(self._date, "%m/%d/%Y")
rescue
Date.new
end
end
def self.batch_import_from_csv(filename)
csv = CSV.table(filename)
csv.each do |row|
paypal_csv = PaypalCsv.new()
paypal_csv.attributes.each do |c|
unless row[c.first.to_sym].nil?
paypal_csv[c.first.to_sym] = row[c.first.to_sym]
end
end
paypal_csv.data = row.to_json
paypal_csv.save
end
return true
end
def link_payment
create_payment
end
private
def create_payment
# find user by email, then by payee
user = User.where("lower(email) = ?", self._from_email_address.downcase).first
user = User.where("lower(payee) = ?", self._from_email_address.downcase).first if user.nil? && self._from_email_address.present?
# Only create payments if the CSV matches a member
if user.present?
# And is a payment (not a cancellation, etc)
payment_types = ["Recurring Payment Received","Payment Received"]
if payment_types.include?(self._type)
# And a member level
if User.member_levels[self._gross.to_i].present?
payment = Payment.new
payment.date = Date.strptime(self._date, "%m/%d/%Y") #7/6/2013 for Jul 06
payment.user_id = user.id
payment.amount = self._gross
if payment.save
self.payment_id = payment.id
self.save!
else
return [false, "Unable to link payment. Payment error: #{payment.errors.full_messages.first}"]
end
else
return [false, "Unable to link payment. Couldn't find membership level '#{self._gross.to_i}'."]
end
else
return [false, "Unable to link payment. Transaction is a '#{self._type}' instead of '#{payment_types.inspect}'."]
end
else
return [false, "Unable to link payment. Couldn't find user/payee '#{self._from_email_address}'."]
end
return [true]
end
end

View File

@@ -9,40 +9,186 @@ class User < ActiveRecord::Base
:recoverable, :rememberable, :trackable, :validatable :recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model # Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :admin, :instructor, :member, :emergency_name, :emergency_phone, :current_skills, :desired_skills, :waiver, :emergency_email, :phone, :payment_method, :orientation, :member_level, :certifications, :hidden #TODO: make admin/instructor/member/etc not accessible attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :admin, :instructor, :member, :emergency_name, :emergency_phone, :current_skills, :desired_skills, :waiver, :emergency_email, :phone, :payment_method, :orientation, :member_level, :certifications, :hidden, :marketing_source, :payee, :accountant #TODO: make admin/instructor/member/etc not accessible
has_many :cards has_many :cards
has_many :user_certifications has_many :user_certifications
has_many :certifications, :through => :user_certifications has_many :certifications, :through => :user_certifications
has_many :payments
after_create :send_new_user_email
def absorb_user(user_to_absorb)
# copy all attributes except email, password, name, and anything that isn't blank on the destination
user_to_absorb.attributes.each_pair {|k,v|
unless (v.nil? || k == :id || k == :email || k == :password || k == :name || k == :password_confirmation || k == :hidden || k == 'hidden' || k == :encrypted_password || !self.attributes[k].blank? )
Rails.logger.info "Updating "+k.to_s+" from "+self[k].to_s
self[k] = v
Rails.logger.info "Updated "+k.to_s+" to "+self[k].to_s
end
}
self.save!
user_to_absorb.cards.each {|card|
Rails.logger.info "CARD BEFORE: "+card.inspect
card.user_id = self.id
card.save!
Rails.logger.info "CARD AFTER: "+card.inspect
}
user_to_absorb.user_certifications.each {|user_cert|
Rails.logger.info "CERT BEFORE: "+user_cert.inspect
user_cert.user_id = self.id
user_cert.save!
Rails.logger.info "CERT AFTER: "+user_cert.inspect
}
user_to_absorb.payments.each {|payment|
Rails.logger.info "PAYMENT BEFORE: "+payment.inspect
payment.user_id = self.id
payment.save!
Rails.logger.info "PAYMENT AFTER: "+payment.inspect
}
user_to_absorb.destroy
end
def name_with_email_and_visibility
if hidden then
"#{name} (#{email}) HIDDEN"
else
"#{name} (#{email})"
end
end
def name_with_payee_and_member_level
if payee.blank? then
"#{name} - #{member_level_string}"
else
"#{payee} for #{name} - #{member_level_string}"
end
end
def member_level_string
case self.member_level.to_i
when 0
"None"
when 1
"Unable"
when 10..24
"Volunteer"
when 25..49
"Associate ($25)"
when 50..99
"Basic ($50)"
when 100..999
"Plus ($100)"
end
end
def self.member_levels
{25 => "Associate", 50 => "Basic", 75 => "Basic", 100 => "Plus"}
end
def payment_status
results = payment_status_calculation
return results[:paid]
end
def member_status def member_status
output = "" results = member_status_calculation
return results[:rank]
if self.member_level.to_i >= 1 then
output = "<span class='hoverinfo' title='Inactive'>&#9676;</span>"
end end
unless self.member.nil? then def member_status_symbol
# 1 = inactive, show an X results = member_status_calculation
if self.member >= 10 then return "<img src='/#{results[:icon]}#{results[:flair]}-coin.png' title='#{results[:message]}' />"
output = "<span class='hoverinfo' title='Volunteer'>&#9684;</span>"
# 25 or higher is paying, show a check
end
if self.member >= 25 then
output = "<span class='hoverinfo' title='25'>&#9681;</span>"
end
if self.member >= 50 then
output = "<span class='hoverinfo' title='50'>&#9685;</span>"
end
if self.member >= 100 then
output = "<span class='hoverinfo' title='100'>&#9679;</span>"
end end
if self.member < self.member_level.to_i then def delinquency
output = "<span class='hoverinfo' title='Lapsed'>&#x2717;</span>" if self.payments.count > 0
paydate = self.payments.maximum(:date)
(Date.today - paydate).to_i
else
(Date.today - self.created_at.to_date).to_i
end end
end end
return output private
def member_status_calculation
# Begin output buffer
message = ""
icon = ""
flair = ""
rank = 0
# First status item is level
case self.member_level.to_i
when 0..9
if self.payments.count > 0 then
message = "Former Member (#{(DateTime.now - self.payments.maximum(:date)).to_i/30} months ago)"
icon = :timeout
rank = 1
else
message = "Not a Member"
icon = :no
rank = 0
end
when 10..24
message = "Volunteer"
icon = :heart
rank = 101
when 25..49
message = member_level_string
icon = :copper
rank = 250
when 50..99
message = member_level_string
icon = :silver
rank = 500
when 100..999
message = member_level_string
icon = :gold
rank = 1000
end
payment_results = payment_status_calculation
flair = payment_results[:flair]
rank = rank/10 unless payment_results[:paid]
message = payment_results[:message] unless payment_results[:message].blank?
return {:message => message, :icon => icon, :flair => flair, :rank => rank}
end
def payment_status_calculation
flair = ""
message = ""
paid = true
# Second status item is payment status
case self.member_level.to_i
when 25..999
# There are payments
if self.payments.count > 0 then
# They're on time
if self.payments.maximum(:date) > (DateTime.now - 60.days)
flair = "-paid"
paid = true
else
message = "Last Payment #{(DateTime.now - self.payments.maximum(:date)).to_i/30} months ago"
paid = false
end
else
message = "No Payments Recorded"
paid = false
end end
end end
return {:message => message, :paid => paid, :flair => flair}
end
def send_new_user_email
Rails.logger.info UserMailer.new_user_email(self).deliver
end
end

View File

@@ -1,8 +1,17 @@
class UserCertification < ActiveRecord::Base class UserCertification < ActiveRecord::Base
attr_accessible :certification_id, :user_id attr_accessible :certification_id, :user_id
validates_presence_of :certification_id, :user_id
validates_uniqueness_of :certification_id, :scope => :user_id, :message => 'already exists for this user.' # Makes sure users don't get certified twice validates_uniqueness_of :certification_id, :scope => :user_id, :message => 'already exists for this user.' # Makes sure users don't get certified twice
belongs_to :user belongs_to :user
belongs_to :certification belongs_to :certification
def user_name
if self.user.blank?
""
else
self.user.name
end
end
end end

View File

@@ -11,9 +11,10 @@
</div> </div>
<% end %> <% end %>
<% @card.user_id = params[:user] if params[:user].present? %>
<div class="field"> <div class="field">
<%= f.label :user %><br /> <%= f.label :user %><br />
<%= collection_select(:card, :user_id, User.all.sort_by(&:name), :id, :name) %> <%= collection_select(:card, :user_id, User.all.sort_by(&:name), :id, :name, :include_blank => true) %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :name, "Card Note" %><br /> <%= f.label :name, "Card Note" %><br />

View File

@@ -2,6 +2,11 @@
<%= link_to 'New Card', new_card_path if can? :create, Card %> <%= link_to 'New Card', new_card_path if can? :create, Card %>
<%= link_to 'Upload all cards', upload_all_path if can? :upload_all, Card %> <%= link_to 'Upload all cards', upload_all_path if can? :upload_all, Card %>
<%= link_to 'Door Logs', door_logs_path if can? :read, DoorLog %>
<p>
<b>Most Active Card Last 7 Days:</b> <%= @most_active_card.name unless @most_active_card.blank? %> (<%= @most_active_card.accesses_this_week unless @most_active_card.blank? %> times)
</p>
<table> <table>
<col /> <col />
<col /> <col />
@@ -14,6 +19,7 @@
<th>DB ID</th> <th>DB ID</th>
<th>Card #</th> <th>Card #</th>
<th>Access?</th> <th>Access?</th>
<th>Accesses Last 7 Days</th>
<th></th> <th></th>
<th></th> <th></th>
<th></th> <th></th>
@@ -22,11 +28,18 @@
<% if !@cards.blank? %> <% if !@cards.blank? %>
<% @cards.each do |card| %> <% @cards.each do |card| %>
<tr> <tr>
<td><%= card.user.name %></td> <td>
<% if card.user.nil? %>
n/a
<% else %>
<%= link_to card.user.name , card %>
<% end %>
</td>
<td><%= card.name %></td> <td><%= card.name %></td>
<td><%= card.id %></td> <td><%= card.id %></td>
<td><%= card.card_number %></td> <td><%= card.card_number %></td>
<td><%= if card.card_permissions == 1 then "Access" end %></td> <td><%= if card.card_permissions == 1 then "Access" end %></td>
<td><%= card.accesses_this_week unless card.accesses_this_week < 1 %></td>
<td><%= link_to 'Upload', upload_path(card) if can? :upload, card %></td> <td><%= link_to 'Upload', upload_path(card) if can? :upload, card %></td>
<td><%= link_to 'Edit', edit_card_path(card) if can? :update, card %></td> <td><%= link_to 'Edit', edit_card_path(card) if can? :update, card %></td>
<td><%= link_to 'Destroy', card, :confirm => 'Are you sure? WARNING: THIS DOES NOT REMOVE THE CARD FROM THE DOOR SYSTEM! DISABLE AND UPLOAD IT FIRST.', :method => :delete if can? :destroy, card %></td> <td><%= link_to 'Destroy', card, :confirm => 'Are you sure? WARNING: THIS DOES NOT REMOVE THE CARD FROM THE DOOR SYSTEM! DISABLE AND UPLOAD IT FIRST.', :method => :delete if can? :destroy, card %></td>

View File

@@ -1,6 +1,6 @@
<p> <p>
<b>User:</b> <b>User:</b>
<%= @card.user.name unless @card.user.blank? %> <%= link_to @card.user.name, @card.user unless @card.user.blank? %>
</p> </p>
<p> <p>
@@ -20,9 +20,20 @@
<p> <p>
<b>Card Permissions:</b> <b>Card Permissions:</b>
<%= @card.card_permissions %> <%= if @card.card_permissions == 1 then "Enabled" else "Disabled" end %>
</p> </p>
<% if can? :read, DoorLog %>
<p>
<b>Access attempts:</b>
<ul>
<% @door_logs.each do |log| %>
<li><%= log.created_at %></li>
<% end %>
</ul>
</p>
<% end %>
<%= link_to 'Upload to Door', upload_path(@card) if can? :upload, @card %> <%= link_to 'Upload to Door', upload_path(@card) if can? :upload, @card %>
<% if can? :update, @card then %><%= link_to 'Edit', edit_card_path(@card) %> |<% end %> <% if can? :update, @card then %><%= link_to 'Edit', edit_card_path(@card) %> |<% end %>
<%= link_to 'Back', cards_path %> <%= link_to 'Back', cards_path %>

View File

@@ -8,13 +8,10 @@
<%= simple_format @certification.description %> <%= simple_format @certification.description %>
</p> </p>
<p>
<b>Certified Users:</b> <b>Certified Users:</b>
<ul> <%= link_to "Click Here", user_certifications_path %>
<% @certification_users.each do |user| %> </p>
<li><%= link_to user.name, user %></li>
<% end %>
<% if @certification_users.blank? then %><li>n/a</li><% end %>
</ul>
<% if can? :update, @certification %><%= link_to 'Edit', edit_certification_path(@certification) %> |<% end %> <% if can? :update, @certification %><%= link_to 'Edit', edit_certification_path(@certification) %> |<% end %>
<%= link_to 'Back', certifications_path %> <%= link_to 'Back', certifications_path %>

View File

@@ -1,14 +1,14 @@
<% if params[:flash] == "welcome_msg" then %> <% if params[:flash] == "welcome_msg" then %>
<p class="notice"><strong>Thank for you choosing to become a HeatSync Labs member!</strong> As we foster this community of learning, science, and the arts every member is important. <br/><br/> <p class="notice"><strong>Thank for you choosing to become a HeatSync Labs member!</strong> As we foster this community of learning, science, and the arts every member is important. <br/><br/>
You can get your payments started by following the instructions on this page. <strong>Please note electronic recurring payments are -highly- encouraged</strong>-- we do not have staff. If you must pay via cash/check, please consider prepaying for 3, 6 or 12 months up front.<br/> You can get your payments started by following the instructions on this page. <strong>Please note electronic recurring payments are -highly- encouraged</strong>-- we do not have staff. If you must pay via cash/check, please consider prepaying for 3, 6 or 12 months up front.<br/><br/>
<strong>To claim member benefits</strong> such as storage, grab a volunteer during your next stop into HeatSync or schedule a time to meet up in advance. Someone should also be contacting you shortly via the email address you provided.<br/> <strong>To claim member benefits</strong> such as storage, grab a volunteer during your next stop into HeatSync or schedule a time to meet up in advance. Someone should also be contacting you shortly via the email address you provided.<br/><br/>
Please also note that certain privileges like 24/7 card access require community approval.<br/> Please also note that certain privileges like 24/7 card access require community approval.<br/><br/>
Thanks again, and happy hacking!</p> Thanks again, and happy hacking!</p>
<% end %> <% end %>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => html) do |f| %> <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => html) do |f| %>
<div class="field"> <div class="field">
<%= f.label :name %><br /> <%= f.label :name, "Full Name" %><br />
<%= f.text_field :name %> <%= f.text_field :name %>
</div> </div>
@@ -22,7 +22,7 @@ Thanks again, and happy hacking!</p>
<%= f.text_field :phone %> <%= f.text_field :phone %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :emergency_name, "Emergency contact" %><br /> <%= f.label :emergency_name, "Emergency Contact Name" %><br />
<%= f.text_field :emergency_name %> <%= f.text_field :emergency_name %>
</div> </div>
<div class="field"> <div class="field">
@@ -41,22 +41,26 @@ Thanks again, and happy hacking!</p>
<%= render :partial => "/users/payment_methods", :locals => { :g => f } %> <%= render :partial => "/users/payment_methods", :locals => { :g => f } %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :current_skills %><br /> <%= f.label :current_skills, "What skills, knowledge and experience do you bring to the community?" %><br />
<%= f.text_area :current_skills %> <%= f.text_area :current_skills %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :desired_skills %><br /> <%= f.label :desired_skills, "What skills, knowledge and experiences are you looking for in HeatSync?" %><br />
<%= f.text_area :desired_skills %> <%= f.text_area :desired_skills %>
</div> </div>
<div class="field">
<%= f.label :marketing_source, "How'd you find out about HeatSync?" %><br />
<%= f.text_area :marketing_source %>
</div>
<div><%= f.label :password %><br /> <div><%= f.label :password %><% if params[:action]!='new' %> <em>(Only if you want to change your password)</em><% end %><br />
<%= f.password_field :password %></div> <%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br /> <div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div> <%= f.password_field :password_confirmation %></div>
<% if params[:action]!='new' %> <% if params[:action]!='new' %>
<div><%= f.label :current_password %><br /> <div><%= f.label :current_password, "Type Your Current Password" %> <em>(For your account's security)</em><br />
<%= f.password_field :current_password %></div> <%= f.password_field :current_password %></div>
<% end %> <% end %>

View File

@@ -1,8 +1,19 @@
<h2>Edit Your Profile</h2> <h2>Profile:</h2>
<%= devise_error_messages! %> <%= devise_error_messages! %>
<div class="payment_links"> <div class="payment_links">
<% if can? :read, resource.payments then %>
<h3>Recorded Payments:</h3>
<ul>
<% resource.payments.each do |payment| %>
<li><%= payment.date %></li>
<% end %>
</ul>
<hr/>
<% end %>
<% if resource.payment_method == "Dwolla" %> <% if resource.payment_method == "Dwolla" %>
<h3>Dwolla Payment Link</h3> <h3>Dwolla Payment Link</h3>
<% if resource.member_level == "25" %> <% if resource.member_level == "25" %>
@@ -61,7 +72,10 @@
<% end %> <% end %>
</div> </div>
<%= link_to image_tag(resource.gravatar_url), "https://www.gravatar.com", :title => "Adjust your photo at Gravatar.com" %> <div class="caption">
<%= link_to image_tag(resource.gravatar_url), "https://www.gravatar.com", :title => "Adjust your photo at Gravatar.com" %><br/>
Adjust your photo <br/>at Gravatar.com
</div>
<%= render :partial => "user", :locals => { :resource => resource, :html => { :method => :put }, :button_label => "Update Profile" } %> <%= render :partial => "user", :locals => { :resource => resource, :html => { :method => :put }, :button_label => "Update Profile" } %>

View File

@@ -1,4 +1,4 @@
<h2>Sign up</h2> <h2>Membership Application</h2>
<%= devise_error_messages! %> <%= devise_error_messages! %>

View File

@@ -1,22 +1,68 @@
<h1>Welcome to the HeatSync Labs Members App.</h1> <h1>Welcome to the HeatSync Labs Members App.</h1>
<% if !user_signed_in? then %> <% if !user_signed_in? then %>
<p>You can sign up to become a member here!</p> <p>You can sign up to become a member here!</p>
<% end %> <% end %>
<% if user_signed_in? && current_user.orientation.blank? then %>
<p class="alert">There's a lot more to see here, but our records show you haven't completed the new member orientation yet. If that's incorrect, please contact a volunteer.</p>
<% end %>
<% if user_signed_in? && current_user.member.to_i < current_user.member_level.to_i then %> <% if user_signed_in? && current_user.member.to_i < current_user.member_level.to_i then %>
<p class="alert">Looks like we haven't acknowledged a recent payment for you yet. This could be because we're slow, or this app just got started, but if in doubt please see your profile for payment instructions, or consider updating your membership level to something accurate.<br/>Thanks for supporting HeatSync!</p> <p class="alert">Looks like we haven't acknowledged a recent payment for you yet. This could be because we're slow, or this app just got started, but if in doubt please see your profile for payment instructions, or consider updating your membership level to something accurate.<br/>Thanks for supporting HeatSync!</p>
<% end %> <% end %>
<table>
<tr>
<td>
<% if ((can? :read, @recent_user_names) && (@recent_user_names.count > 1)) then %>
<h2>New People: <em>(say hi!)</em></h2>
<ul>
<% @recent_user_names.each do |user| %>
<li><%= link_to user.name, user %> <%= raw(user.member_status_symbol) %> <em>(Signed up <%= user.created_at.strftime("%b %d") %>)</em></li>
<% end %>
</ul>
<% end %>
<h2>Cool Stats:</h2> <h2>Cool Stats:</h2>
<dl> <dl>
<dt># of People in this DB:</dt> <dt># of People in this DB:</dt>
<dd><%= @num_users %> (<%= @recent_users %> in the last 7 days)</dd> <dd><%= @num_users %> (<%= @recent_users %> new in the last 7 days)</dd>
<dt># of People Certified:</dt> <dt># of People Certified:</dt>
<dd><%= @num_certs %> (<%= @recent_certs %> in the last 7 days)</dd> <dd><%= @num_certs %> (<%= @recent_certs %> new in the last 7 days)</dd>
<dt># of Accesses Granted:</dt> <dt># of Current Paying Members:</dt>
<dd><%= @num_door_opens %> (<%= @recent_door_opens %> in the last 7 days)</dd> <dd><%= @num_paid_users %> (<%= @num_delinquent_users %> not-current)</dd>
<dt># of Accesses Denied:</dt> <dt># of Door Accesses Granted:</dt>
<dd><%= @num_door_denieds %> (<%= @recent_door_denieds %> in the last 7 days)</dd> <dd><%= @num_door_opens %> (<%= @today_door_opens %> today, <%= @recent_door_opens %> in the last 7 days)</dd>
<dt># of Accesses Denied:</dt> <dt># of Door Accesses Denied:</dt>
<dd><%= @num_door_denieds %> (<%= @recent_door_denieds %> in the last 7 days)</dd> <dd><%= @num_door_denieds %> (<%= @recent_door_denieds %> in the last 7 days)</dd>
<dt># of Computers in this DB:</dt>
<dd><%= @num_macs %> (<%= @recent_macs %> seen today)</dd>
</dl> </dl>
</td>
<td>
<h2>Member Resources</h2>
<ul>
<li><%= link_to "Wiki", "http://wiki.heatsynclabs.org" %></li>
<li><%= link_to "Discussion Group", "http://groups.google.com/group/heatsynclabs" %></li>
<li><%= link_to "IRC", "irc://irc.freenode.net#heatsynclabs" %></li>
<li><%= link_to "Live Webcams", "http://live.heatsynclabs.org/" %></li>
<li>Lab Phone: (480) 751-1929</li>
<li>
<style type="text/css">
form input {font-family: 'Lucida Console', Monaco, monospace; }
</style>
<b>Send a Message!</b>
<form method="post" action="http://tweet.zyphon.com/signage.php">
<em>Type here and your message will show up on the LED sign in the front window!</em><br/>
<em>(Please be nice!)</em><br/>
<input type="text" name="msg" id="msg" value=" Hello" size="9" /> (max 9 chars per line)<br/>
<input type="text" name="msg2" id="msg2" value=" World" size="9" /><br/>
<input type="submit" name="submitbutton" id="submitbutton" value="Go!" />
</form>
</li>
</ul>
</td>
</tr>
</table>

View File

@@ -0,0 +1,35 @@
<h2>PayPal IPN Records</h2>
<p>
<em>Automatically loaded from PayPal's servers</em>
</p>
<table>
<tr>
<th>Date</th>
<th>Name</th>
<th>Item</th>
<th>Amount</th>
</tr>
<% @ipns.sort_by(&:date_parsed).reverse!.each do |ipn| %>
<tr>
<td><%= ipn.payment_date %></td>
<td><%= ipn.first_name %> <%= ipn.last_name %></td>
<td><%= ipn.item_name %></td>
<td>
<% if ipn.payment_gross.blank? %>
<%= ipn.txn_type %>
<% else %>
<%= ipn.payment_gross %>
<% end %>
</td>
<td>
<% if ipn.payment.present? %>
<%= link_to "Linked Payment", ipn.payment %>
<% else %>
<%= link_to "Try to link email '#{ipn.payer_email}' at membership level '#{ipn.payment_gross.to_i}'", link_ipn_path(ipn) %>
<% end %>
</td>
<td><%= link_to "Details", ipn %></td>
<td><%= link_to "Validate", validate_ipn_path(ipn) %></td>
</tr>
<% end %>
</table>

123
app/views/ipns/new.html.erb Normal file
View File

@@ -0,0 +1,123 @@
<%= form_tag('/ipns') do |f| %>
<style type="text/css">
label {
width: 10em;
display: inline-block;}
</style>
<div class="actions">
<%= submit_tag %>
</div>
<div class="field">
<%= label_tag :first_name %>
<%= text_field_tag :first_name, "John" %>
</div>
<div class="field">
<%= label_tag :last_name %>
<%= text_field_tag :last_name, "Smith" %>
</div>
<div class="field">
<%= label_tag :payer_email %>
<%= text_field_tag :payer_email, "jsmith@example.com" %>
</div>
<div class="field">
<%= label_tag :item_name %>
<%= text_field_tag :item_name, "Associate Membership" %>
</div>
<div class="field">
<%= label_tag :payment_gross %>
<%= text_field_tag :payment_gross, "25.00" %>
</div>
<div class="field">
<%= label_tag :transaction_subject %>
<%= text_field_tag :transaction_subject, "" %>
</div>
<div class="field">
<%= label_tag :payment_date %>
<%= text_field_tag :payment_date, "20:46:54 Jun 20, 2013 PDT" %>
</div>
<div class="field">
<%= label_tag :txn_type %>
<%= text_field_tag :txn_type, "subscr_payment" %>
</div>
<div class="field">
<%= label_tag :subscr_id %>
<%= text_field_tag :subscr_id, "I-1234567890" %>
</div>
<div class="field">
<%= label_tag :residence_country %>
<%= text_field_tag :residence_country, "US" %>
</div>
<div class="field">
<%= label_tag :mc_currency %>
<%= text_field_tag :mc_currency, "USD" %>
</div>
<div class="field">
<%= label_tag :business %>
<%= text_field_tag :business, "hslfinances@gmail.com" %>
</div>
<div class="field">
<%= label_tag :payment_type %>
<%= text_field_tag :payment_type, "instant" %>
</div>
<div class="field">
<%= label_tag :protection_eligibility %>
<%= text_field_tag :protection_eligibility, "Ineligible" %>
</div>
<div class="field">
<%= label_tag :verify_sign %>
<%= text_field_tag :verify_sign, "12ru9021j9f21j90fj1290fj2910fj0219fj0" %>
</div>
<div class="field">
<%= label_tag :payer_status %>
<%= text_field_tag :payer_status, "verified" %>
</div>
<div class="field">
<%= label_tag :txn_id %>
<%= text_field_tag :txn_id, "1234567890" %>
</div>
<div class="field">
<%= label_tag :receiver_email %>
<%= text_field_tag :receiver_email, "hslfinances@gmail.com" %>
</div>
<div class="field">
<%= label_tag :payer_id %>
<%= text_field_tag :payer_id, "V812314914" %>
</div>
<div class="field">
<%= label_tag :receiver_id %>
<%= text_field_tag :receiver_id, "V90R1280182" %>
</div>
<div class="field">
<%= label_tag :payment_status %>
<%= text_field_tag :payment_status, "Completed" %>
</div>
<div class="field">
<%= label_tag :payment_fee %>
<%= text_field_tag :payment_fee, "0.85" %>
</div>
<div class="field">
<%= label_tag :mc_fee %>
<%= text_field_tag :mc_fee, "0.85" %>
</div>
<div class="field">
<%= label_tag :mc_gross %>
<%= text_field_tag :mc_gross, "25.00" %>
</div>
<div class="field">
<%= label_tag :charset %>
<%= text_field_tag :charset, "windows-1252" %>
</div>
<div class="field">
<%= label_tag :notify_version %>
<%= text_field_tag :notify_version, "3.7" %>
</div>
<div class="field">
<%= label_tag :ipn_track_id %>
<%= text_field_tag :ipn_track_id, "9d3d032d9070" %>
</div>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>

View File

@@ -0,0 +1,18 @@
<h2>IPN Details</h2>
<% @ipn.attributes.except("data","payment_id").each do |attr| %>
<p>
<b><%= attr.first.to_s %>:</b>
<%= @ipn.attributes[attr.first] %>
</p>
<% end %>
<p>
<% if @ipn.payment.present? %>
<%= link_to "Linked Payment", @ipn.payment %>
<% else %>
<span class="alert">Couldn't link automatically. Please create payment manually or adjust the user account and try again to <%= link_to "link email '#{@ipn.payer_email}' at membership level '#{@ipn.payment_gross.to_i}'", link_ipn_path(@ipn) %>.</span>
<% end %>
</p>
<%= link_to "Back", ipns_path %>

View File

@@ -11,17 +11,18 @@
<a href="/" title="Home"><img src="/assets/logo.png" id="logo" /></a> <a href="/" title="Home"><img src="/assets/logo.png" id="logo" /></a>
<%= link_to 'People', users_path if can? :read, User %> <%= link_to 'People', users_path if can? :read, User %>
<%= link_to 'Access Cards', cards_path if can? :manage, Card %> <%= link_to 'Access Cards', cards_path if can? :manage, Card %>
<% if can? :manage, UserCertification %> <% if can? :create, UserCertification %>
<%= link_to 'Cert Classes', certifications_path if can? :read, Certification %> <%= link_to 'Cert Classes', certifications_path if can? :read, Certification %>
<%= link_to 'User Certs', user_certifications_path if can? :create, UserCertification %> <%= link_to 'User Certs', user_certifications_path if can? :create, UserCertification %>
<% else %> <% else %>
<%= link_to 'Certifications', certifications_path if can? :read, Certification %> <%= link_to 'Certifications', certifications_path if can? :read, Certification %>
<% end %> <% end %>
<%= link_to 'Door Logs', door_logs_path if can? :read, DoorLog %> <%= link_to 'Payments', payments_path if can? :read, Payment %>
<%= link_to 'Computers', macs_path if user_signed_in? && (can? :read, Mac) %>
<% if user_signed_in? then %><%= link_to 'Profile', edit_user_registration_path %><% end %> <% if user_signed_in? then %><%= link_to 'Profile', edit_user_registration_path %><% end %>
<%= link_to 'Logout', destroy_user_session_path, :method => :delete if user_signed_in? %> <%= link_to 'Logout', destroy_user_session_path, :method => :delete if user_signed_in? %>
<%= link_to 'Login', new_user_session_path unless user_signed_in? %> <%= link_to 'Login', new_user_session_path unless user_signed_in? %>
<%= link_to 'Become a Member', new_user_registration_path unless user_signed_in? %> <%= link_to 'Membership Application', new_user_registration_path unless user_signed_in? %>
</div> </div>
<div id="content"> <div id="content">
<p class="notice"><%= raw(notice) %></p> <p class="notice"><%= raw(notice) %></p>

View File

@@ -0,0 +1,10 @@
<table>
<% @mac_logs.each do |mac_log| %>
<tr>
<td><%= mac_log.mac %></td>
<td><%= mac_log.ip %></td>
<td><%= mac_log.action %></td>
<td><%= mac_log.created_at %></td>
</tr>
<% end %>
</table>

View File

@@ -0,0 +1,33 @@
<%= form_for(@mac) do |f| %>
<% if @mac.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@mac.errors.count, "error") %> prohibited this Mac from being saved:</h2>
<ul>
<% @mac.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :user_id, "User" %><br />
<%= collection_select(:mac, :user_id, @users, :id, :name, :include_blank => true) %>
</div>
<div class="field">
<%= f.label :mac %><br />
<%= f.text_field :mac %>
</div>
<div class="field">
<%= f.label :note %><br />
<%= f.text_field :note %>
</div>
<div class="field">
<%= f.label :hidden %><br />
<%= f.check_box :hidden %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

View File

@@ -0,0 +1,6 @@
<h1>Editing Mac</h1>
<%= render 'form' %>
<%= link_to 'Show', @mac %> |
<%= link_to 'Back', macs_path %>

View File

@@ -0,0 +1 @@
<%= @output %>

View File

@@ -0,0 +1,47 @@
<h2>What machines are on our network?</h2>
<%= link_to "New MAC registration", new_mac_path if can? :create, Mac %>
<ul class="mac_list">
<%
@active_macs.each do |mac|
Rails.logger.info mac.inspect %>
<li>
<span title="<%= mac.mac if user_signed_in? %><%= " - "+mac.ip.to_s if can? :read_details, mac %><%= " - "+((Time.now - mac.since) / 1.hour).round(1).to_s+" hours" if can? :manage, mac %>">
<%= mac.user.name unless mac.user.blank? %>
<%= mac.mac if mac.user.blank? %>
<%= "("+mac.note+")" unless mac.note.blank? %></span>
<%= link_to ' Edit', edit_mac_path(mac) if can? :update, mac %> <br/>
</li>
<% end %>
</ul>
<% if can? :read_details, Mac %>
<ul class="mac_list hidden">
<% @hidden_macs.each do |mac| %>
<li>
<span title="<%= mac.mac %><%= " - "+mac.ip.to_s if can? :read_details, mac %><%= " - "+((Time.now - mac.since) / 1.hour).round(1).to_s+" hours" if can? :manage, mac %>">
<%= mac.user.name unless mac.user.blank? %>
<%= "("+mac.note+")" unless mac.note.blank? %></span>
<%= link_to ' Edit', edit_mac_path(mac) if can? :update, mac %> <br/>
</li>
<% end %>
</ul>
<% end %>
<% if can? :manage, Mac %>
<h3>All Macs</h3>
<table>
<% @all_macs.each do |mac| %>
<tr <%= raw('class="hidden"') if mac.hidden? %>>
<td><%= mac.mac.downcase %> </td>
<td><%= mac.user.name unless mac.user.blank? %></td>
<td><%= "("+mac.note+")" unless mac.note.blank? %></td>
<td><%= if mac.active? then raw("<strong>Here</strong>") else "Gone" end %></td>
<td><%= ((Time.now - mac.since) / 1.hour).round(1).to_s+" hours" unless mac.since.blank? %></td>
<td><%= link_to 'Edit', edit_mac_path(mac) %></td>
</tr>
<% end %>
</table>
<% end %>

View File

@@ -0,0 +1,5 @@
<h1>New Mac</h1>
<%= render 'form' %>
<%= link_to 'Back', macs_path %>

View File

@@ -0,0 +1,7 @@
Scanning...
<% if can? :read_details, Mac
@log.each do |log| %>
<%= log.mac %> =
<%= log.ip %><br/>
<% end
end %>

View File

@@ -0,0 +1,27 @@
<p>
<b>User:</b>
<%= @mac.user.name unless @mac.user.blank? %>
</p>
<p>
<b>Mac:</b>
<%= @mac.mac %>
</p>
<p>
<b>Note:</b>
<%= @mac.note %>
</p>
<p>
<b>Hidden:</b>
<%= @mac.hidden %>
</p>
<p>
<b>IP:</b>
<%= @mac.ip %>
</p>
<%= link_to 'Edit', edit_mac_path(@mac) %> |
<%= link_to 'Back', macs_path %>

View File

@@ -0,0 +1,29 @@
<%= form_for(@payment) do |f| %>
<% if @payment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@payment.errors.count, "error") %> prohibited this payment from being saved:</h2>
<ul>
<% @payment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :user_id, "User" %><br />
<%= collection_select(:payment, :user_id, @users, :id, :name_with_payee_and_member_level) %> (inactive members are not shown.)
</div>
<div class="field">
<%= f.label :date, "Paid for month beginning" %><br />
<%= f.date_select :date, :default => (DateTime.now - 1.month) %>
</div>
<div class="field">
<%= f.label :amount %><br />
<%= f.number_field :amount %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

View File

@@ -0,0 +1,6 @@
<h1>Editing payment</h1>
<%= render 'form' %>
<%= link_to 'Show', @payment %> |
<%= link_to 'Back', payments_path %>

View File

@@ -0,0 +1,31 @@
<h1>Listing payments</h1>
<p>
<b>Create Payments:</b>
<%= link_to 'Manually', new_payment_path %> |
<%= link_to 'Batched CSV', paypal_csvs_path %> |
<%= link_to 'IPN', ipns_path %>
</p>
<table>
<tr>
<th>User</th>
<th>Paid for month <br/>beginning</th>
<th>Amount</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @payments.each do |payment| %>
<tr>
<td><%= link_to payment.user.name_with_payee_and_member_level, payment.user unless payment.user.blank? %></td>
<td><%= payment.human_date %></td>
<td><%= payment.amount %></td>
<td><%= link_to 'Details', payment %></td>
<td><%= link_to 'Edit', edit_payment_path(payment) %></td>
</tr>
<% end %>
</table>

View File

@@ -0,0 +1,5 @@
<h1>New payment</h1>
<%= render 'form' %>
<%= link_to 'Back', payments_path %>

View File

@@ -0,0 +1,51 @@
<p>
<b>User:</b>
<%= link_to @payment.user.name_with_payee_and_member_level, @payment.user unless @payment.user.blank? %>
</p>
<p>
<b>Paid for month beginning:</b>
<%= @payment.date %>
</p>
<p>
<b>Amount:</b>
<%= @payment.amount %>
</p>
<p>
<b>Last Modified by:</b>
<% user = @users.find{|u| u.id == @payment.created_by} %>
<% if user.blank? %>
n/a
<% else %>
<%= link_to user.name, user %>
<% end %>
</p>
<p>
<b>Created date:</b>
<%= @payment.created_at %>
</p>
<p>
<b>Updated date:</b>
<%= @payment.updated_at %>
</p>
<% if @payment.ipn.present? %>
<p>
<%= link_to "Paid via PayPal (IPN)", @payment.ipn %>
</p>
<% end %>
<% if @payment.paypal_csv.present? %>
<p>
<%= link_to "Paid via PayPal (CSV)", @payment.paypal_csv %>
</p>
<% end %>
<%= link_to 'Edit', edit_payment_path(@payment) %> |
<%= link_to 'Destroy', @payment, :confirm => 'Are you sure you want to destroy this payment?', :method => :delete if can? :destroy, @payment %> |
<%= link_to 'Back', payments_path %>

View File

@@ -0,0 +1,35 @@
<h2>PayPal CSV Records</h2>
<p>
<%= link_to "Upload CSV", new_paypal_csv_path %>
</p>
<table>
<tr>
<th>Date</th>
<th>Name</th>
<th>Item</th>
<th>Amount</th>
</tr>
<% @paypal_csvs.sort_by(&:date_parsed).reverse!.each do |paypal_csv| %>
<tr>
<td><%= paypal_csv.date %></td>
<td><%= paypal_csv._name %></td>
<td><%= paypal_csv._item_title %></td>
<td>
<% if paypal_csv._gross.blank? %>
<%= paypal_csv._type %>
<% else %>
<%= paypal_csv._gross %>
<% end %>
</td>
<td>
<% if paypal_csv.payment.present? %>
<%= link_to "Linked Payment", paypal_csv.payment %>
<% else %>
<%= link_to "Try to link email '#{paypal_csv._from_email_address}' at membership level '#{paypal_csv._gross.to_i}'", link_paypal_csv_path(paypal_csv) %>
<% end %>
</td>
<td><%= link_to "Details", paypal_csv %></td>
</tr>
<% end %>
</table>

View File

@@ -0,0 +1,15 @@
<style type="text/css">
label {
width: 10em;
display: inline-block;}
</style>
<%= form_tag('/paypal_csvs', :multipart => true) do |f| %>
<div class="field">
<%= label_tag :file %>
<%= file_field_tag :file %>
</div>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>

View File

@@ -0,0 +1,17 @@
<h2>PayPal CSV Item Details</h2>
<% @paypal_csv.attributes.except("data","payment_id").each do |attr| %>
<p>
<b><%= attr.first.to_s %>:</b>
<%= @paypal_csv.attributes[attr.first] %>
</p>
<% end %>
<p>
<% if @paypal_csv.payment.present? %>
<%= link_to "Linked Payment", @paypal_csv.payment %>
<% else %>
<span class="alert">Couldn't link automatically. Please create payment manually or adjust the user account and try again to <%= link_to "link email '#{@paypal_csv._from_email_address}' at membership level '#{@paypal_csv._gross.to_i}'", link_paypal_csv_path(@paypal_csv) %>.</span>
<% end %>
</p>
<%= link_to "Back", paypal_csvs_path %>

View File

@@ -11,13 +11,14 @@
</div> </div>
<% end %> <% end %>
<% @user_certification.user_id = params[:user] if params[:user].present? %>
<div class="field"> <div class="field">
<%= f.label :user_id, "User" %><br /> <%= f.label :user_id, "User" %><br />
<%= collection_select(:user_certification, :user_id, @users, :id, :name) %> <%= collection_select(:user_certification, :user_id, @users, :id, :name, :include_blank => true) %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :certification_id, "Certification" %><br /> <%= f.label :certification_id, "Certification" %><br />
<%= collection_select(:user_certification, :certification_id, @certifications, :id, :name) %> <%= collection_select(:user_certification, :certification_id, @certifications, :id, :name, :include_blank => true) %>
</div> </div>
<div class="actions"> <div class="actions">
<%= f.submit %> <%= f.submit %>

View File

@@ -5,9 +5,9 @@
<% @grouped_user_certs.sort.each do |cert, user_certifications| %> <% @grouped_user_certs.sort.each do |cert, user_certifications| %>
<dl class="collapsible"> <dl class="collapsible">
<dt><%= cert.name %></dt> <dt><%= cert.name %></dt>
<% user_certifications.sort{|a,b| a.user.name <=> b.user.name}.each do |user_certification| %> <% user_certifications.sort{|a,b| a.user_name <=> b.user_name}.each do |user_certification| %>
<dd> <dd>
<%= link_to user_certification.user.name, user_certification %> <%= link_to user_certification.user_name, user_certification %>
</dd> </dd>
<% end %> <% end %>
</dl> </dl>

View File

@@ -1,6 +1,6 @@
<p> <p>
<b>User:</b> <b>User:</b>
<%= @user_certification.user.name %> <%= link_to @user_certification.user.name, @user_certification.user %>
</p> </p>
<p> <p>
@@ -18,8 +18,14 @@
at <%= @user_certification.updated_at %> at <%= @user_certification.updated_at %>
</p> </p>
<%= link_to 'Edit', edit_user_certification_path(@user_certification) %> |
<%= link_to 'Back', user_certifications_path %>
<p> <p>
<%= link_to 'Destroy', @user_certification, :confirm => "Are you sure you want to destroy this user's certification?", :method => :delete if can? :destroy, @user_certification %> <% if can? :update, @user_certification %>
<%= link_to 'Edit', edit_user_certification_path(@user_certification) %> |
<% end %>
<% if can? :destroy, @user_certification %>
<%= link_to 'Delete', @user_certification, :confirm => "Are you sure you want to destroy this user's certification?", :method => :delete %> |
<% end %>
<%= link_to 'Back', user_certifications_path %>
</p> </p>

View File

@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
</head>
<body>
<h2><%= @user.name %> just signed up.</h2>
<p>
Please contact them at <%= @user.email %><%= " or "+@user.phone.to_s unless @user.phone.blank? %> to set up a
new user orientation, waiver, welcome, payment help, etc.
</p>
<p>
User Details: <%= link_to @url+user_path(@user), @url+user_path(@user) %>
</p>
<p>
<b>Member Level:</b>
<%= simple_format @user.member_level_string %>
</p>
<p>
<b>What skills, knowledge and experience do you bring to the community?</b>
<%= simple_format @user.current_skills %>
</p>
<p>
<b>What skills, knowledge and experiences are you looking for in HeatSync?</b>
<%= simple_format @user.desired_skills %>
</p>
<p>
<b>How'd you find out about HeatSync?</b>
<%= simple_format @user.marketing_source %>
</p>
</body>
</html>

View File

@@ -0,0 +1,17 @@
<%= @user.name %> just signed up.
---
Please contact them at <%= @user.email %><%= " or "+@user.phone.to_s unless @user.phone.blank? %> to set up a
new user orientation, waiver, welcome, payment help, etc.
User Details: <%= link_to @url+user_path(@user), @url+user_path(@user) %>
Member Level: <%= simple_format @user.member_level %>
What skills, knowledge and experience do you bring to the community?
<%= simple_format @user.current_skills %>
What skills, knowledge and experiences are you looking for in HeatSync?
<%= simple_format @user.desired_skills %>
How'd you find out about HeatSync?
<%= simple_format @user.marketing_source %>

View File

@@ -17,7 +17,7 @@
<% end %> <% end %>
<div class="field"> <div class="field">
<%= f.label :name %><br /> <%= f.label :name, "Full Name" %><br />
<%= f.text_field :name %> <%= f.text_field :name %>
</div> </div>
<div class="field"> <div class="field">
@@ -60,26 +60,30 @@
</div> </div>
<div class="field"> <div class="field">
<%= f.label :member_level, "Desired Member Level" %><br /> <%= f.label :member_level, "Desired Member Level" %><br />
<%= f.select :member_level, [[nil],["None",0],["Unable",1],["Volunteer",10],["Associate",25],["Basic",50],["Plus",100]] %> <%= f.select :member_level, [[nil],["None",0],["Unable",1],["Volunteer",10],["Associate ($25)",25],["Basic ($50)",50],["Plus ($100)",100]] %>
</div> </div>
<div class="field"> <div class="field">
<%= render :partial => "/users/payment_methods", :locals => { :g => f } %> <%= render :partial => "/users/payment_methods", :locals => { :g => f } %>
</div> </div>
<div class="field">
<%= f.label :payee %><br />
<%= f.text_field :payee%>
</div>
<div class="field"> <div class="field">
<%= f.label :phone %><br /> <%= f.label :phone %><br />
<%= f.text_field :phone %> <%= f.text_field :phone %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :current_skills %><br /> <%= f.label :current_skills, "What skills, knowledge and experience do you bring to the community?" %><br />
<%= f.text_area :current_skills %> <%= f.text_area :current_skills %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :desired_skills %><br /> <%= f.label :desired_skills, "What skills, knowledge and experiences are you looking for in HeatSync?" %><br />
<%= f.text_area :desired_skills %> <%= f.text_area :desired_skills %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :member, "Member?" %><br /> <%= f.label :marketing_source, "How'd you find out about HeatSync?" %><br />
<%= f.select :member, [[nil],["No",0],["Inactive",1],["Volunteer",10],["Associate",25],["Basic",50],["Plus",100]] %> <%= f.text_area :marketing_source %>
</div> </div>
<div class="field"> <div class="field">
<%= f.label :instructor, "Instructor?" %><br /> <%= f.label :instructor, "Instructor?" %><br />
@@ -89,6 +93,10 @@
<%= f.label :admin, "Admin?" %><br /> <%= f.label :admin, "Admin?" %><br />
<%= f.check_box :admin %> <%= f.check_box :admin %>
</div> </div>
<div class="field">
<%= f.label :accountant, "Accountant?" %><br />
<%= f.check_box :accountant %>
</div>
<div class="field"> <div class="field">
<%= f.label :hidden, "Hidden?" %><br /> <%= f.label :hidden, "Hidden?" %><br />
<%= f.check_box :hidden %> <%= f.check_box :hidden %>

View File

@@ -1,13 +1,13 @@
<% @payment_methods = [[nil],["PayPal"],["Dwolla"],["Bill Pay","BillPay"],["Check"],["Cash"],["Other"]] <% @payment_methods = [[nil],["PayPal"],["Dwolla"],["Bill Pay","BillPay"],["Check"],["Cash"],["Other"]]
@payment_instructions = {nil => nil, @payment_instructions = {nil => nil,
:PayPal => "Set up a monthly recurring payment to hslfinances@gmail.com", :PayPal => "Set up a monthly recurring payment to hslfinances@gmail.com or via the button on the next page.",
:Dwolla => "Set up a monthly recurring payment to hslfinances@gmail.com", :Dwolla => "Set up a monthly recurring payment to hslfinances@gmail.com or via the button on the next page.",
:BillPay => "Have your bank send a monthly check to HeatSync Labs Treasurer, 140 W Main St, Mesa AZ 85201", :BillPay => "Have your bank send a monthly check to HeatSync Labs Treasurer, 140 W Main St, Mesa AZ 85201",
:Check => "Mail to HeatSync Labs Treasurer, 140 W Main St, Mesa AZ 85201 OR put in the drop safe at the Lab with a deposit slip firmly attached each month.", :Check => "Mail to HeatSync Labs Treasurer, 140 W Main St, Mesa AZ 85201 OR put in the drop safe at the Lab with a deposit slip firmly attached each month.",
:Cash => "Put in the drop safe at the Lab with a deposit slip firmly attached each month.", :Cash => "Put in the drop safe at the Lab with a deposit slip firmly attached each month.",
:Other => "Hmm... talk to a Treasurer!"} %> :Other => "Hmm... talk to a Treasurer!"} %>
<%= g.label :payment_method %> <i>(after changing this, please make sure you update your payment service, it's not automatic.)</i><br /> <%= g.label :payment_method %><% if params[:action] != 'new' %> <i>(after changing this, please make sure you update your payment service, it's not automatic.)</i><% end %><br />
<%= g.select :payment_method, @payment_methods %> <%= g.select :payment_method, @payment_methods %>
<% @payment_instructions.each_pair do |key, value| %> <% @payment_instructions.each_pair do |key, value| %>
<span class="payment_instructions" id="pmt_<%= key %>"><%= value %></span> <span class="payment_instructions" id="pmt_<%= key %>"><%= value %></span>

View File

@@ -0,0 +1,95 @@
<% user ||= @user #unless @user.blank? %>
<p>
<b>Name:</b>
<%= user.name %>
</p>
<% if current_user.admin? then %>
<p>
<b>Email:</b>
<%= user.email %>
</p>
<p>
<b>Orientation?</b>
<%= user.orientation.strftime("%B %d %Y") unless user.orientation.blank? %>
</p>
<% end %>
<p>
<b>Waiver?</b>
<%= user.waiver.strftime("%B %d %Y") unless user.waiver.blank? %>
</p>
<p>
<b>Current Member?</b>
<%= raw(user.member_status_symbol) %>
</p>
<% if current_user.admin? then %>
<p>
<b>Desired Member Level:</b>
<%= user.member_level %>
</p>
<p>
<b>Payment Method:</b>
<%= user.payment_method %>
</p>
<p>
<b>Payee:</b>
<%= user.payee %>
</p>
<p>
<b>Phone:</b>
<%= user.phone %>
</p>
<% end %>
<p>
<b>Current Skills:</b>
<%= simple_format user.current_skills %>
</p>
<p>
<b>Desired Skills:</b>
<%= simple_format user.desired_skills %>
</p>
<p>
<b>Card:</b>
<% if current_user.admin? then %>
<% user.cards.each do |c| %>
<%= link_to c.card_number, c %><%= "," unless c == user.cards.last %>
<% end %>
<% else %>
<%= unless user.cards.blank? then raw("&#x2713;") end %>
<% end %>
</p>
<b>Certifications:</b>
<ul>
<% user.certifications.each do |certification| %>
<li><%= link_to certification.name, certification %></li>
<% end %>
<% if user.certifications.blank? %><li>n/a</li><% end %>
</ul>
<% if current_user.admin? then %>
<p>
<b>Payments:</b>
<ul>
<% user.payments.each do |payment| %>
<li><%= payment.date %></li>
<% end %>
</ul>
</p>
<% end %>
<% if current_user.admin? then %>
<p>
<b>Created:</b>
<%= user.created_at %>
</p>
<p>
<b>Last signed in:</b>
<%= user.current_sign_in_at %>
</p>
<% end %>

View File

@@ -0,0 +1,65 @@
<h1>Inactive Users</h1>
<table>
<col />
<col />
<% if current_user.admin? then %><col /><% end %>
<col />
<% if current_user.admin? %><col />
<col class="col_highlight" /><% end %>
<col />
<col class="col_highlight" />
<col />
<col class="col_highlight" />
<tr>
<th></th>
<th>Name</th>
<% if current_user.admin? then %><th>Email</th><% end %>
<th>Certifications</th>
<% if current_user.admin? then %>
<th>Orientation?</th>
<% end %>
<th>Card?</th>
<th>Pmt Method</th>
<th>Desired Level</th>
<th>Last Payment</th>
<th>Joined</th>
<th></th>
<th></th>
</tr>
<% if !@users.blank? %>
<% @users.each do |user| %>
<tr<%= " class='hidden'" if user.hidden? %>>
<td><%= image_tag user.gravatar_url(:default => "http://members.heatsynclabs.org/assets/nil.png"), :class => :avatar %></td>
<td><%= link_to user.name, user %></td>
<% if current_user.admin? then %><td><%= user.email %></td><% end %>
<td><% user.certifications.each do |c| %>
<%= link_to c.name, c %><%= "," unless c.id == user.certifications.last.id %>
<% end %></td>
<% if current_user.admin? then %><td>
<%= unless user.orientation.blank? then raw("<span class='hoverinfo' title='"+user.orientation.strftime("%B %d %Y")+"'>&#x2713;</span>") end %>
</td><% end %>
<td><%= unless user.cards.blank? then raw("<span class='iconinfo'>&#x2713;</span>") end %></td>
<td><%= user.payment_method %></td>
<td><%= user.member_level %></td>
<td><% delinquency = user.delinquency %>
<% if delinquency == 9999 %>
No Payments
<% else %>
<%= (delinquency/30).to_s+" mo. ago" %>
<% end %>
</td>
<td><%= user.created_at.to_date %></td>
<td><%= link_to 'Edit', edit_user_path(user) if can? :update, user %></td>
<td><%= link_to 'Destroy', user, :confirm => 'Are you sure? WARNING: THIS DOES NOT REMOVE THE USER FROM THE DOOR SYSTEM! DISABLE THEM FIRST.', :method => :delete if can? :destroy, user %></td>
</tr>
<% end %>
<% end %>
</table>
<% if current_user.orientation.blank? then %>
<p class="alert">There's a lot more to see here, but our records show you haven't completed the new member orientation yet. If that's incorrect, please contact a volunteer.</p>
<% end %>
<br />

View File

@@ -3,13 +3,19 @@
<% if can? :create, User %> <% if can? :create, User %>
<%= link_to 'New User', new_user_path %> <%= link_to 'New User', new_user_path %>
<% end %> <% end %>
<% if can? :manage, User %>
| <%= link_to 'Merge Users', users_merge_path %>
<% end %>
<% if current_user.admin? %>
| <%= link_to 'Inactive Users', users_inactive_path %>
<% end %>
<table> <table>
<col /> <col />
<col /> <col />
<% if current_user.admin? then %><col /><% end %> <% if current_user.admin? then %><col /><% end %>
<col /> <col />
<% if current_user.admin? %><col /><% end %> <% if current_user.admin? %><col />
<col class="col_highlight" /> <col class="col_highlight" /><% end %>
<col /> <col />
<col class="col_highlight" /> <col class="col_highlight" />
<col /> <col />
@@ -26,7 +32,7 @@
<th><a href="?sort=member">Member?</a></th> <th><a href="?sort=member">Member?</a></th>
<th><a href="?sort=card">Card?</a></th> <th><a href="?sort=card">Card?</a></th>
<th><a href="?sort=instructor">Instructor?</a></th> <th><a href="?sort=instructor">Instructor?</a></th>
<th><a href="?sort=admin">Admin?</a></th> <% if current_user.admin? then %><th><a href="?sort=admin">Admin?</a></th><% end %>
<th></th> <th></th>
<th></th> <th></th>
</tr> </tr>
@@ -44,10 +50,10 @@
<%= unless user.orientation.blank? then raw("<span class='hoverinfo' title='"+user.orientation.strftime("%B %d %Y")+"'>&#x2713;</span>") end %> <%= unless user.orientation.blank? then raw("<span class='hoverinfo' title='"+user.orientation.strftime("%B %d %Y")+"'>&#x2713;</span>") end %>
</td><% end %> </td><% end %>
<td><%= unless user.waiver.blank? then raw("<span class='hoverinfo' title='"+user.waiver.strftime("%B %d %Y")+"'>&#x2713;</span>") end %></td> <td><%= unless user.waiver.blank? then raw("<span class='hoverinfo' title='"+user.waiver.strftime("%B %d %Y")+"'>&#x2713;</span>") end %></td>
<td><%= raw(user.member_status) %></td> <td><%= raw(user.member_status_symbol) %></td>
<td><%= unless user.cards.blank? then raw("<span class='iconinfo'>&#x2713;</span>") end %></td> <td><%= unless user.cards.blank? then raw("<span class='iconinfo'>&#x2713;</span>") end %></td>
<td><%= if user.instructor? then raw("<span class='iconinfo'>&#x2713;</a>") end %></td> <td><%= if user.instructor? then raw("<span class='iconinfo'>&#x2713;</a>") end %></td>
<td><%= if user.admin? then raw("<span class='iconinfo'>&#x2713;</a>") end %></td> <% if current_user.admin? then %><td><%= if user.admin? then raw("<span class='iconinfo'>&#x2713;</a>") end %></td><% end %>
<td><%= link_to 'Edit', edit_user_path(user) if can? :update, user %></td> <td><%= link_to 'Edit', edit_user_path(user) if can? :update, user %></td>
<td><%= link_to 'Destroy', user, :confirm => 'Are you sure? WARNING: THIS DOES NOT REMOVE THE USER FROM THE DOOR SYSTEM! DISABLE THEM FIRST.', :method => :delete if can? :destroy, user %></td> <td><%= link_to 'Destroy', user, :confirm => 'Are you sure? WARNING: THIS DOES NOT REMOVE THE USER FROM THE DOOR SYSTEM! DISABLE THEM FIRST.', :method => :delete if can? :destroy, user %></td>
</tr> </tr>

View File

@@ -0,0 +1,48 @@
<style type="text/css">
#user_to_merge_details, #user_to_keep_details,
#user_to_merge_details p, #user_to_keep_details p {
font-size: 12px;
margin: 0;
}
</style>
<h1>Merging users</h1>
<%= form_tag('/users/merge', :method => :post) do %>
<b>Everything except the email, password, name, id, hidden, and blank values will be moved to the "user to keep" UNLESS there is a value already there. The "user to merge" will be deleted.</b>
<table>
<tr>
<td>
<div class="field">
<%= label_tag :user_to_keep, "User to Keep" %><br />
<%= collection_select(:user, :to_keep, @users, :id, :name_with_email_and_visibility, :include_blank => true) %>
</div>
<div id="user_to_keep_details"></div>
</td>
<td style="font-size: 16px">&#x25C0;&#x25C0;</td>
<td>
<div class="field">
<%= label_tag :user_to_merge, "User to Merge" %><br />
<%= collection_select(:user, :to_merge, @users, :id, :name_with_email_and_visibility, :include_blank => true) %>
</div>
<div id="user_to_merge_details"></div>
</td>
</tr>
</table>
<hr/>
<div class="actions">
<%= submit_tag "Merge" %>
</div>
<% end %>
<%= link_to 'Back', users_path %>
<script>
$("#user_to_keep").change(function(event,handler){
$("#user_to_keep_details").load("/user_summary/"+event.target.value);
});
$("#user_to_merge").change(function(event,handler){
$("#user_to_merge_details").load("/user_summary/"+event.target.value);
});
</script>

View File

@@ -12,7 +12,7 @@
<p> <p>
<b>Current Member?</b> <b>Current Member?</b>
<%= raw(@user.member_status) %> <%= raw(@user.member_status_symbol) %>
</p> </p>
<p> <p>
@@ -20,12 +20,6 @@
<%= @user.instructor? %> <%= @user.instructor? %>
</p> </p>
<p>
<b>Admin?</b>
<%= @user.admin? %>
</p>
<% if current_user.admin? then %> <% if current_user.admin? then %>
<p> <p>
<b>Email:</b> <b>Email:</b>
@@ -56,6 +50,10 @@
<b>Payment Method:</b> <b>Payment Method:</b>
<%= @user.payment_method %> <%= @user.payment_method %>
</p> </p>
<p>
<b>Payee:</b>
<%= @user.payee %>
</p>
<p> <p>
<b>Phone:</b> <b>Phone:</b>
<%= @user.phone %> <%= @user.phone %>
@@ -69,18 +67,26 @@
<b>Desired Skills:</b> <b>Desired Skills:</b>
<%= simple_format @user.desired_skills %> <%= simple_format @user.desired_skills %>
</p> </p>
<p>
<b>Card:</b>
<% if current_user.admin? then %> <% if current_user.admin? then %>
<% @user.cards.each do |c| %> <p>
<%= link_to c.card_number, c %><%= "," unless c == @user.cards.last %> <b>Found HeatSync via:</b>
<%= simple_format @user.marketing_source %>
</p>
<% end %> <% end %>
<p>
<b>Card: </b><%= link_to "+ Add", (new_card_path+"?user="+@user.id.to_s), :class => 'btn' if can? :create, Card %>
<% if current_user.admin? then %>
<ul>
<% @user.cards.each do |c| %>
<li><%= link_to c.card_number, c %><%= "," unless c == @user.cards.last %></li>
<% end %>
</ul>
<% else %> <% else %>
<%= unless @user.cards.blank? then raw("&#x2713;") end %> <%= unless @user.cards.blank? then raw("&#x2713;") end %>
<% end %> <% end %>
</p> </p>
<b>Certifications:</b> <b>Certifications: </b><%= link_to "+ Add", (new_user_certification_path+"?user="+@user.id.to_s), :class => 'btn' if can? :create, UserCertification %>
<ul> <ul>
<% @user.certifications.each do |certification| %> <% @user.certifications.each do |certification| %>
<li><%= link_to certification.name, certification %></li> <li><%= link_to certification.name, certification %></li>
@@ -88,5 +94,27 @@
<% if @user.certifications.blank? %><li>n/a</li><% end %> <% if @user.certifications.blank? %><li>n/a</li><% end %>
</ul> </ul>
<% if current_user.admin? then %>
<p>
<b>Payments:</b>
<ul>
<% @payments.each do |payment| %>
<li><%= payment.date %></li>
<% end %>
</ul>
</p>
<% end %>
<% if current_user.admin? then %>
<p>
<b>Created:</b>
<%= @user.created_at %>
</p>
<p>
<b>Last signed in:</b>
<%= @user.current_sign_in_at %>
</p>
<% end %>
<% if can? :update, @user then %><%= link_to 'Edit', edit_user_path(@user) %> |<% end %> <% if can? :update, @user then %><%= link_to 'Edit', edit_user_path(@user) %> |<% end %>
<%= link_to 'Back', users_path %> <%= link_to 'Back', users_path %>

View File

@@ -23,3 +23,9 @@ production:
database: db/production.sqlite3 database: db/production.sqlite3
pool: 5 pool: 5
timeout: 5000 timeout: 5000
# adapter: postgresql
# encoding: unicode
# database: members
# pool: 5
# username: postgres
# password:

View File

@@ -1,4 +1,13 @@
Dooraccess::Application.routes.draw do Dooraccess::Application.routes.draw do
match 'ipns/import' => 'ipns#import', :as => :import_ipn
resources :ipns
match 'ipns/:id/link' => 'ipns#link', :as => :link_ipn
match 'ipns/:id/validate' => 'ipns#validate', :as => :validate_ipn
resources :paypal_csvs
match 'paypal_csvs/:id/link' => 'paypal_csvs#link', :as => :link_paypal_csv
resources :payments
resources :user_certifications resources :user_certifications
@@ -16,6 +25,10 @@ Dooraccess::Application.routes.draw do
end end
end end
match 'user_summary/:id' => 'users#user_summary' # User summary view
match 'users/merge' => 'users#merge_view', :via => :get # Merge view
match 'users/merge' => 'users#merge_action', :via => :post # Merge action
match 'users/inactive' => 'users#inactive' # Inactive users report
resources :users resources :users
match 'users/create' => 'users#create', :via => :post # Use POST users/create instead of POST users to avoid devise conflict match 'users/create' => 'users#create', :via => :post # Use POST users/create instead of POST users to avoid devise conflict
@@ -27,6 +40,12 @@ Dooraccess::Application.routes.draw do
match 'door_logs/download' => 'door_logs#download', :as => :download match 'door_logs/download' => 'door_logs#download', :as => :download
match 'door_logs/auto_download' => 'door_logs#auto_download', :as => :auto_download match 'door_logs/auto_download' => 'door_logs#auto_download', :as => :auto_download
match 'macs/scan' => 'macs#scan'
match 'macs/import' => 'macs#import'
resources :macs
resources :mac_logs
root :to => "home#index" root :to => "home#index"
# The priority is based upon order of creation: # The priority is based upon order of creation:

View File

@@ -0,0 +1,15 @@
class CreateMacs < ActiveRecord::Migration
def change
create_table :macs do |t|
t.references :user
t.string :mac
t.string :ip
t.datetime :since
t.datetime :refreshed
t.boolean :active
t.timestamps
end
add_index :macs, :user_id
end
end

View File

@@ -0,0 +1,11 @@
class CreateMacLogs < ActiveRecord::Migration
def change
create_table :mac_logs do |t|
t.string :mac
t.string :ip
t.string :action
t.timestamps
end
end
end

View File

@@ -0,0 +1,6 @@
class AddPropertiesToMacs < ActiveRecord::Migration
def change
add_column :macs, :hidden, :boolean
add_column :macs, :note, :string
end
end

View File

@@ -0,0 +1,5 @@
class AddMarketingSourceToUsers < ActiveRecord::Migration
def change
add_column :users, :marketing_source, :string
end
end

View File

@@ -0,0 +1,11 @@
class CreatePayments < ActiveRecord::Migration
def change
create_table :payments do |t|
t.references :user
t.date :date
t.timestamps
end
add_index :payments, :user_id
end
end

View File

@@ -0,0 +1,5 @@
class AddCreatedByToPayments < ActiveRecord::Migration
def change
add_column :payments, :created_by, :integer
end
end

View File

@@ -0,0 +1,5 @@
class AddPayeeToUsers < ActiveRecord::Migration
def change
add_column :users, :payee, :string
end
end

View File

@@ -0,0 +1,5 @@
class AddAccountantToUsers < ActiveRecord::Migration
def change
add_column :users, :accountant, :boolean
end
end

View File

@@ -0,0 +1,24 @@
class CreateIpns < ActiveRecord::Migration
def change
create_table :ipns do |t|
t.integer :payment_id
t.text :data
t.string :txn_id
t.string :txn_type
t.string :first_name
t.string :last_name
t.string :payer_business_name
t.string :payer_email
t.string :payer_id
t.string :auth_amount
t.string :payment_date
t.string :payment_fee
t.string :payment_gross
t.string :payment_status
t.string :item_name
t.string :payment_type
t.timestamps
end
end
end

View File

@@ -0,0 +1,5 @@
class AddAmountToPayments < ActiveRecord::Migration
def change
add_column :payments, :amount, :decimal
end
end

View File

@@ -0,0 +1,28 @@
class CreatePaypalCsvs < ActiveRecord::Migration
def change
create_table :paypal_csvs do |t|
t.integer :payment_id
t.text :data
t.string :date
t.string :_time
t.string :_time_zone
t.string :_name
t.string :_type
t.string :_status
t.string :_currency
t.string :_gross
t.string :_fee
t.string :_net
t.string :_from_email_address
t.string :_to_email_address
t.string :_transaction_id
t.string :_counterparty_status
t.string :_address_status
t.string :_item_title
t.string :_item_id
t.string :string
t.timestamps
end
end
end

View File

@@ -10,7 +10,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 => 20130125185724) do ActiveRecord::Schema.define(:version => 20130828104240) do
create_table "cards", :force => true do |t| create_table "cards", :force => true do |t|
t.string "card_number" t.string "card_number"
@@ -35,6 +35,86 @@ ActiveRecord::Schema.define(:version => 20130125185724) do
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
end end
create_table "ipns", :force => true do |t|
t.integer "payment_id"
t.text "data"
t.string "txn_id"
t.string "txn_type"
t.string "first_name"
t.string "last_name"
t.string "payer_business_name"
t.string "payer_email"
t.string "payer_id"
t.string "auth_amount"
t.string "payment_date"
t.string "payment_fee"
t.string "payment_gross"
t.string "payment_status"
t.string "item_name"
t.string "payment_type"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "mac_logs", :force => true do |t|
t.string "mac"
t.string "ip"
t.string "action"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "macs", :force => true do |t|
t.integer "user_id"
t.string "mac"
t.string "ip"
t.datetime "since"
t.datetime "refreshed"
t.boolean "active"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "hidden"
t.string "note"
end
add_index "macs", ["user_id"], :name => "index_macs_on_user_id"
create_table "payments", :force => true do |t|
t.integer "user_id"
t.date "date"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "created_by"
t.decimal "amount"
end
add_index "payments", ["user_id"], :name => "index_payments_on_user_id"
create_table "paypal_csvs", :force => true do |t|
t.integer "payment_id"
t.text "data"
t.string "date"
t.string "_time"
t.string "_time_zone"
t.string "_name"
t.string "_type"
t.string "_status"
t.string "_currency"
t.string "_gross"
t.string "_fee"
t.string "_net"
t.string "_from_email_address"
t.string "_to_email_address"
t.string "_transaction_id"
t.string "_counterparty_status"
t.string "_address_status"
t.string "_item_title"
t.string "_item_id"
t.string "string"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "user_certifications", :force => true do |t| create_table "user_certifications", :force => true do |t|
t.integer "user_id" t.integer "user_id"
t.integer "certification_id" t.integer "certification_id"
@@ -72,6 +152,9 @@ ActiveRecord::Schema.define(:version => 20130125185724) do
t.string "desired_skills" t.string "desired_skills"
t.boolean "instructor" t.boolean "instructor"
t.boolean "hidden" t.boolean "hidden"
t.string "marketing_source"
t.string "payee"
t.boolean "accountant"
end end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["email"], :name => "index_users_on_email", :unique => true

BIN
public/copper-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
public/copper-paid-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 661 B

BIN
public/gold-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/gold-paid-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
public/heart-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/no-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/silver-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/silver-paid-coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show More