Adding direct door access commands and interface
This commit is contained in:
parent
d2434be109
commit
41a8431be5
|
@ -7,6 +7,7 @@ class ApplicationController < ActionController::Base
|
||||||
else
|
else
|
||||||
flash[:alert] = "Nothing to see here!"
|
flash[:alert] = "Nothing to see here!"
|
||||||
end
|
end
|
||||||
|
Rails.logger.warn "----------\r\nWARNING: AccessDenied Exception: #{exception.inspect} User: #{current_user.inspect}\r\n----------"
|
||||||
redirect_to root_url
|
redirect_to root_url
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
class SpaceApiController < ApplicationController
|
class SpaceApiController < ApplicationController
|
||||||
authorize_resource :except => :index
|
# Individually remove authorizing stuff since there is no SpaceApi model
|
||||||
before_filter :authenticate_user!, :except => :index
|
authorize_resource :except => [:index, :access, :access_post]
|
||||||
|
# User auth here happens via params, instead of form.
|
||||||
|
before_filter :authenticate_user!, :except => [:index, :access, :access_post]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@json = JSON.parse(Setting.space_api_json_template)
|
@json = JSON.parse(Setting.space_api_json_template)
|
||||||
|
@ -21,11 +23,74 @@ class SpaceApiController < ApplicationController
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
format.json {
|
format.json {
|
||||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
|
||||||
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
||||||
render :json => @json
|
render :json => @json
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def access
|
||||||
|
@status = DoorLog.show_status
|
||||||
|
|
||||||
|
# Nothing, just render form
|
||||||
|
unless user_signed_in?
|
||||||
|
@output = "Invalid email or password. Please login with your Members DB email and password below."
|
||||||
|
else
|
||||||
|
unless can? :access_doors_remotely, :door_access
|
||||||
|
@output = "Sorry, your account isn't able to control doors remotely."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def access_post
|
||||||
|
@output = ""
|
||||||
|
|
||||||
|
#if params['cmd'] == "check-login" then
|
||||||
|
# if users[params['user']] && users[params['user']]['pass'].to_s == (Digest::SHA2.new(bitlen=512) << params['pass']).to_s then
|
||||||
|
# @output += '{ "login": "okay" }'
|
||||||
|
# else
|
||||||
|
# @output += '{ "login": "fail" }'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# exit
|
||||||
|
#end
|
||||||
|
|
||||||
|
# Stop unless signed in already, OR if the supplied user/pass params are good.
|
||||||
|
unless current_user || check_auth(params['user'],params['pass'])
|
||||||
|
@output += "Invalid email or password."
|
||||||
|
else
|
||||||
|
# Stop unless the user can access the door system
|
||||||
|
unless can? :access_doors_remotely, :door_access
|
||||||
|
@output += "Sorry, your account isn't able to control doors remotely. Ask an admin if this is incorrect."
|
||||||
|
Rails.logger.warn "----------\r\nWARNING: DOOR ACCESS ATTEMPT DENIED. USER #{current_user.inspect}\r\n----------"
|
||||||
|
else
|
||||||
|
# Stop unless we've got a command to run
|
||||||
|
unless params['cmd']
|
||||||
|
@output += "No command specified."
|
||||||
|
else
|
||||||
|
# Log the access
|
||||||
|
Rails.logger.info "Door access: user #{current_user.inspect}"
|
||||||
|
DoorLog.create!({:key => "rem_"+DoorLog.parse_command(params['cmd'])[:url_param], :data => current_user.id})
|
||||||
|
|
||||||
|
# Execute the access
|
||||||
|
@output += DoorLog.execute_command(params['cmd'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Render the form again
|
||||||
|
render :access
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_auth(email,password)
|
||||||
|
resource = User.find_by_email(email)
|
||||||
|
if resource && resource.valid_password?(password)
|
||||||
|
resource.remember_me = true
|
||||||
|
sign_in :user, resource
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,10 @@ class Ability
|
||||||
can [:read,:new_member_report], User, :id => user.id #TODO: why can users update themselves? Maybe because Devise doesn't check users/edit?
|
can [:read,:new_member_report], User, :id => user.id #TODO: why can users update themselves? Maybe because Devise doesn't check users/edit?
|
||||||
can :read, UserCertification, :user_id => user.id
|
can :read, UserCertification, :user_id => user.id
|
||||||
|
|
||||||
|
if user.card_access_enabled
|
||||||
|
can :access_doors_remotely, :door_access
|
||||||
|
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
|
||||||
|
@ -39,8 +43,6 @@ class Ability
|
||||||
|
|
||||||
# Admins can manage all
|
# Admins can manage all
|
||||||
if user.admin?
|
if user.admin?
|
||||||
Rails.logger.info user.inspect
|
|
||||||
Rails.logger.info "IS ADMIN"
|
|
||||||
can :manage, :all
|
can :manage, :all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,90 @@ class DoorLog < ActiveRecord::Base
|
||||||
attr_accessible :data, :key
|
attr_accessible :data, :key
|
||||||
require 'open-uri'
|
require 'open-uri'
|
||||||
|
|
||||||
|
def self.execute_command(command)
|
||||||
|
output = ""
|
||||||
|
# load config values
|
||||||
|
door_access_url = APP_CONFIG['door_access_url']
|
||||||
|
door_access_password = APP_CONFIG['door_access_password']
|
||||||
|
|
||||||
|
#login
|
||||||
|
source = open("#{door_access_url}?e=#{door_access_password}").read
|
||||||
|
results = source.scan(/ok/)
|
||||||
|
|
||||||
|
#only continue if we've got an OK login
|
||||||
|
if(results.size > 0) then
|
||||||
|
# Parse the command and result
|
||||||
|
parsing = parse_command(command)
|
||||||
|
output += parsing[:output]
|
||||||
|
url_param = parsing[:url_param]
|
||||||
|
|
||||||
|
# Execute the command
|
||||||
|
open("#{door_access_url}?#{url_param}")
|
||||||
|
|
||||||
|
self.download_status # Update the status cache
|
||||||
|
else
|
||||||
|
output += 'Failed to connect to door system.'
|
||||||
|
end
|
||||||
|
|
||||||
|
#logout
|
||||||
|
open("#{door_access_url}?e=0000")
|
||||||
|
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.parse_command(command)
|
||||||
|
output = ""
|
||||||
|
url_param = ""
|
||||||
|
# @commands = [
|
||||||
|
# ["Unlock all doors","unlock"],
|
||||||
|
# ["Unlock Front door","unlock-front"],
|
||||||
|
# ["Unlock Rear door","unlock-rear"],
|
||||||
|
# ["Lock all doors","lock"],
|
||||||
|
# ["Lock Front door","lock-front"],
|
||||||
|
# ["Lock Rear door","lock-rear"],
|
||||||
|
# ["Open Front door","open-front"],
|
||||||
|
# ["Open Rear door","open-rear"],
|
||||||
|
# ["Arm alarm","arm"],
|
||||||
|
# ["Disarm alarm","disarm"]
|
||||||
|
# ]
|
||||||
|
case command
|
||||||
|
when "open-front"
|
||||||
|
output += "Front door opened."
|
||||||
|
url_param = "o1"
|
||||||
|
when "open-rear"
|
||||||
|
output += "Rear door opened."
|
||||||
|
url_param = "o2"
|
||||||
|
when "u", "unlock"
|
||||||
|
output += "Doors unlocked, remember to re-lock them."
|
||||||
|
url_param = "u"
|
||||||
|
when "u1", "unlock-front"
|
||||||
|
output += "Front Door unlocked, remember to re-lock it."
|
||||||
|
url_param = "u=1"
|
||||||
|
when "u2", "unlock-rear"
|
||||||
|
output += "Rear Door unlocked, remember to re-lock it."
|
||||||
|
url_param = "u=2"
|
||||||
|
when "lock", "l"
|
||||||
|
output += "Doors locked."
|
||||||
|
url_param = "l"
|
||||||
|
when "lock-front", "l1"
|
||||||
|
output += "Front Door locked."
|
||||||
|
url_param = "l=1"
|
||||||
|
when "lock-rear", "l2"
|
||||||
|
output += "Rear Door locked."
|
||||||
|
url_param = "l=2"
|
||||||
|
when "arm"
|
||||||
|
output += "Armed."
|
||||||
|
url_param = "2"
|
||||||
|
when "disarm"
|
||||||
|
output += "Disarmed."
|
||||||
|
url_param = "1"
|
||||||
|
else
|
||||||
|
output += "Fail. Don't be a naughty user!"
|
||||||
|
url_param = "9" # Using 9 because it's just status, no harm done
|
||||||
|
end
|
||||||
|
return {:output => output, :url_param => url_param}
|
||||||
|
end
|
||||||
|
|
||||||
def self.show_status
|
def self.show_status
|
||||||
door_logs = DoorLog.where(key: ["door_1_locked","door_2_locked"]).order('created_at DESC').take(2)
|
door_logs = DoorLog.where(key: ["door_1_locked","door_2_locked"]).order('created_at DESC').take(2)
|
||||||
door_1_locked = parse_locked_status(door_logs, "door_1_locked")
|
door_1_locked = parse_locked_status(door_logs, "door_1_locked")
|
||||||
|
|
|
@ -56,6 +56,11 @@ class User < ActiveRecord::Base
|
||||||
user_to_absorb.destroy
|
user_to_absorb.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def card_access_enabled
|
||||||
|
# If the user has at least one card with permission level 1, they have access
|
||||||
|
self.cards.where(:card_permissions => 1).count > 0
|
||||||
|
end
|
||||||
|
|
||||||
def name_with_email_and_visibility
|
def name_with_email_and_visibility
|
||||||
if hidden then
|
if hidden then
|
||||||
"#{name} (#{email}) HIDDEN"
|
"#{name} (#{email}) HIDDEN"
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<h1>Access Cards</h1>
|
<h1>Access Cards</h1>
|
||||||
|
|
||||||
<%= link_to 'New Card', new_card_path if can? :create, Card %>
|
<%= link_to 'New Card', new_card_path, :class => "btn" 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, :class => "btn" if can? :upload_all, Card %>
|
||||||
<%= link_to 'Door Logs', door_logs_path if can? :read, DoorLog %>
|
<%= link_to 'Door Logs', door_logs_path, :class => "btn" if can? :read, DoorLog %>
|
||||||
|
<%= link_to 'Space API', space_api_path, :class => "btn" %>
|
||||||
|
<%= link_to 'Remote Door Access', space_api_access_path, :class => "btn" if can? :access_doors_remotely, :door_access %>
|
||||||
<p>
|
<p>
|
||||||
<b>Most Active Card Last Month:</b> <%= @most_active_card.name unless @most_active_card.blank? %> (<%= @most_active_card.accesses_this_week unless @most_active_card.blank? %> days)
|
<b>Most Active Card Last Month:</b> <%= @most_active_card.name unless @most_active_card.blank? %> (<%= @most_active_card.accesses_this_week unless @most_active_card.blank? %> days)
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -8,6 +8,17 @@ Guide to Card Number storage:
|
||||||
cardnum = (R+(r*32767)), convert to hex
|
cardnum = (R+(r*32767)), convert to hex
|
||||||
|
|
||||||
Guide to log keys and data:
|
Guide to log keys and data:
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
* rem_ = remote command issues via web UI (#=user id)
|
||||||
|
Statuses:
|
||||||
|
* armed = current status of alarm arming
|
||||||
|
* activated = current status of alarm ringing
|
||||||
|
* alarm_2 = current status of alarm sensor 2
|
||||||
|
* alarm_3 = current status of alarm sensor 3
|
||||||
|
* door_1_locked = status of door 1
|
||||||
|
* door_2_locked = status of door 2
|
||||||
|
Log Entries:
|
||||||
* A=alarm armed (# level)
|
* A=alarm armed (# level)
|
||||||
* a=added user (# usernum)
|
* a=added user (# usernum)
|
||||||
* C=keypad command (# command)
|
* C=keypad command (# command)
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<h2>Member Resources</h2>
|
<h2>Member Resources</h2>
|
||||||
|
<% if can? :access_doors_remotely, :door_access %>
|
||||||
|
<ul><li><%= link_to "Remote Door Access", space_api_access_path %></li></ul>
|
||||||
|
<% end %>
|
||||||
<%= simple_format Setting.member_resources_inset %>
|
<%= simple_format Setting.member_resources_inset %>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<a href="/" title="Home"><img src="/assets/logo.png" id="logo" /></a>
|
<a id="home_nav_link" 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? :create, UserCertification %>
|
<% if can? :create, UserCertification %>
|
||||||
|
|
114
app/views/space_api/access.html.erb
Normal file
114
app/views/space_api/access.html.erb
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<h2 id="title">Door Control System</h2>
|
||||||
|
<% if @output %>
|
||||||
|
<p class="notice">
|
||||||
|
<%= raw @output %>
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
<% end %>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
<style type="text/css">
|
||||||
|
#status, #status span { display: inline-block; text-align: center; font-weight: bold; border-radius: 5px; }
|
||||||
|
#status { width: 400px;}
|
||||||
|
#status span { border: 1px solid black; width: 180px; padding: 5px; }
|
||||||
|
#status span input { width: 100%; margin: 0.2em 0;}
|
||||||
|
@media only screen and (max-width: 480px){
|
||||||
|
#header a:not(#home_nav_link) { display: none; }
|
||||||
|
#title {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 45px;
|
||||||
|
}
|
||||||
|
#status { width: 100%; }
|
||||||
|
#status span { width: 45%; border: none; padding: 1%; margin: 1em 0; }
|
||||||
|
#status span input { font-size: 1.8em; height: 2em;}
|
||||||
|
}
|
||||||
|
.open { background-color: green; }
|
||||||
|
.closed { background-color: red; }
|
||||||
|
.open input.unlock, .closed input.lock { background: #bbb; }
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function updateDoorStatus(){
|
||||||
|
// grab status from space api
|
||||||
|
$.get( "<%= space_api_path(:format => :json) %>", function( data ) {
|
||||||
|
switch(data.status){
|
||||||
|
case "doors_open=both":
|
||||||
|
$( "#status" ).attr("class","open");
|
||||||
|
$( "#door_1_status" ).attr("class","open");
|
||||||
|
$( "#door_2_status" ).attr("class","open");
|
||||||
|
break;
|
||||||
|
case "doors_open=door1":
|
||||||
|
$( "#status" ).attr("class","open");
|
||||||
|
$( "#door_1_status" ).attr("class","open");
|
||||||
|
$( "#door_2_status" ).attr("class","closed");
|
||||||
|
break;
|
||||||
|
case "doors_open=door2":
|
||||||
|
$( "#status" ).attr("class","open");
|
||||||
|
$( "#door_1_status" ).attr("class","closed");
|
||||||
|
$( "#door_2_status" ).attr("class","open");
|
||||||
|
break;
|
||||||
|
case "doors_open=none":
|
||||||
|
$( "#status" ).attr("class","closed");
|
||||||
|
$( "#door_1_status" ).attr("class","closed");
|
||||||
|
$( "#door_2_status" ).attr("class","closed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function updateMacStatus(){
|
||||||
|
$.get( "/macs.json", function( data ) {
|
||||||
|
$("#mac_status").text(data.map(function(item){
|
||||||
|
return item.name;
|
||||||
|
}).join(", "));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// run once
|
||||||
|
updateDoorStatus();
|
||||||
|
updateMacStatus();
|
||||||
|
// and again every few seconds
|
||||||
|
setInterval(updateDoorStatus, 10000);
|
||||||
|
setInterval(updateDoorStatus, 60000);
|
||||||
|
</script>
|
||||||
|
<%= form_tag do %>
|
||||||
|
<% unless user_signed_in? %>
|
||||||
|
<p>
|
||||||
|
<%= label_tag :user, "Email Address" %><br/>
|
||||||
|
<%= text_field_tag :user %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= label_tag :pass, "Password" %><br/>
|
||||||
|
<%= password_field_tag :pass %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<span id="status">
|
||||||
|
<div>
|
||||||
|
<span id="overall_status">
|
||||||
|
Both<br/>
|
||||||
|
<input type="submit" name="cmd" value="unlock" class="btn unlock">
|
||||||
|
<input type="submit" name="cmd" value="lock" class="btn lock">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span id="door_1_status">
|
||||||
|
Door 1<br/>
|
||||||
|
<input type="submit" name="cmd" value="open-front" class="btn unlock">
|
||||||
|
<input type="submit" name="cmd" value="unlock-front" class="btn unlock">
|
||||||
|
<input type="submit" name="cmd" value="lock-front" class="btn lock">
|
||||||
|
</span>
|
||||||
|
<span id="door_2_status">
|
||||||
|
Door 2<br/>
|
||||||
|
<input type="submit" name="cmd" value="open-rear" class="btn unlock">
|
||||||
|
<input type="submit" name="cmd" value="unlock-rear" class="btn unlock">
|
||||||
|
<input type="submit" name="cmd" value="lock-rear" class="btn lock">
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<!--
|
||||||
|
<h3>Alarm</h3>
|
||||||
|
<p>
|
||||||
|
<input type="submit" name="cmd" value="arm" class="btn">
|
||||||
|
<input type="submit" name="cmd" value="disarm" class="btn">
|
||||||
|
</p>
|
||||||
|
-->
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<h3>Who's here?</h3>
|
||||||
|
<p id="mac_status">
|
||||||
|
</p>
|
|
@ -37,7 +37,7 @@ module Dooraccess
|
||||||
config.encoding = "utf-8"
|
config.encoding = "utf-8"
|
||||||
|
|
||||||
# Configure sensitive parameters which will be filtered from the log file.
|
# Configure sensitive parameters which will be filtered from the log file.
|
||||||
config.filter_parameters += [:password]
|
config.filter_parameters += [:password, :pass]
|
||||||
|
|
||||||
# Use SQL instead of Active Record's schema dumper when creating the database.
|
# Use SQL instead of Active Record's schema dumper when creating the database.
|
||||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||||
|
|
|
@ -103,7 +103,7 @@ Devise.setup do |config|
|
||||||
|
|
||||||
# ==> Configuration for :rememberable
|
# ==> Configuration for :rememberable
|
||||||
# The time the user will be remembered without asking for credentials again.
|
# The time the user will be remembered without asking for credentials again.
|
||||||
# config.remember_for = 2.weeks
|
config.remember_for = 1.month
|
||||||
|
|
||||||
# If true, extends the user's remember period when remembered via cookie.
|
# If true, extends the user's remember period when remembered via cookie.
|
||||||
# config.extend_remember_period = false
|
# config.extend_remember_period = false
|
||||||
|
|
|
@ -46,6 +46,8 @@ Dooraccess::Application.routes.draw do
|
||||||
match 'cards/:id/upload' => 'cards#upload', :as => :upload
|
match 'cards/:id/upload' => 'cards#upload', :as => :upload
|
||||||
|
|
||||||
match 'space_api' => 'space_api#index', :as => :space_api
|
match 'space_api' => 'space_api#index', :as => :space_api
|
||||||
|
match 'space_api/access' => 'space_api#access', :via => :get, :as => :space_api_access
|
||||||
|
match 'space_api/access' => 'space_api#access_post', :via => :post
|
||||||
|
|
||||||
match 'door_logs' => 'door_logs#index', :as => :door_logs
|
match 'door_logs' => 'door_logs#index', :as => :door_logs
|
||||||
match 'door_logs/download' => 'door_logs#download', :as => :download
|
match 'door_logs/download' => 'door_logs#download', :as => :download
|
||||||
|
|
Loading…
Reference in New Issue
Block a user