device-tracker 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/Rakefile +6 -0
- data/Readme.md +32 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/device-tracker.gemspec +54 -0
- data/exe/device-tracker +50 -0
- data/lib/device/tracker.rb +19 -0
- data/lib/device/tracker/app.rb +25 -0
- data/lib/device/tracker/config-schema.json +53 -0
- data/lib/device/tracker/config.ru +9 -0
- data/lib/device/tracker/controllers/application_controller.rb +215 -0
- data/lib/device/tracker/controllers/devices_controller.rb +315 -0
- data/lib/device/tracker/controllers/heartbeat_controller.rb +55 -0
- data/lib/device/tracker/controllers/os_controller.rb +43 -0
- data/lib/device/tracker/controllers/transactions_controller.rb +21 -0
- data/lib/device/tracker/controllers/users_controller.rb +193 -0
- data/lib/device/tracker/db/data/devices.xlsx +0 -0
- data/lib/device/tracker/db/migrate/20150521071815_create_users.rb +13 -0
- data/lib/device/tracker/db/migrate/20150521082155_create_devices.rb +23 -0
- data/lib/device/tracker/db/migrate/20150521120335_create_operating_systems.rb +8 -0
- data/lib/device/tracker/db/migrate/20150527162242_create_transactions.rb +13 -0
- data/lib/device/tracker/db/migrate/20151027073050_create_heartbeat.rb +10 -0
- data/lib/device/tracker/db/migrate/20151028132946_add_user_verification.rb +7 -0
- data/lib/device/tracker/db/migrate/20151028141328_remove_is_active_from_users.rb +5 -0
- data/lib/device/tracker/db/migrate/20151029085629_add_password_reset_code_to_users.rb +7 -0
- data/lib/device/tracker/db/migrate/20151030130341_add_missing_column_to_devices.rb +7 -0
- data/lib/device/tracker/db/migrate/20151102141601_add_serial_number_to_devices.rb +7 -0
- data/lib/device/tracker/db/schema.rb +74 -0
- data/lib/device/tracker/db/seeds.rb +18 -0
- data/lib/device/tracker/dependencies.rb +15 -0
- data/lib/device/tracker/helpers/application_helper.rb +84 -0
- data/lib/device/tracker/models/device.rb +39 -0
- data/lib/device/tracker/models/heartbeat.rb +9 -0
- data/lib/device/tracker/models/operating_system.rb +8 -0
- data/lib/device/tracker/models/transaction.rb +56 -0
- data/lib/device/tracker/models/user.rb +22 -0
- data/lib/device/tracker/public/css/bootstrap-sortable.css +100 -0
- data/lib/device/tracker/public/css/bootstrap.min.css +5 -0
- data/lib/device/tracker/public/css/custom.css +88 -0
- data/lib/device/tracker/public/favicon.png +0 -0
- data/lib/device/tracker/public/favicon/android-chrome-144x144.png +0 -0
- data/lib/device/tracker/public/favicon/android-chrome-192x192.png +0 -0
- data/lib/device/tracker/public/favicon/android-chrome-36x36.png +0 -0
- data/lib/device/tracker/public/favicon/android-chrome-48x48.png +0 -0
- data/lib/device/tracker/public/favicon/android-chrome-72x72.png +0 -0
- data/lib/device/tracker/public/favicon/android-chrome-96x96.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-114x114.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-120x120.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-144x144.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-152x152.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-180x180.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-57x57.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-60x60.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-72x72.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-76x76.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon-precomposed.png +0 -0
- data/lib/device/tracker/public/favicon/apple-touch-icon.png +0 -0
- data/lib/device/tracker/public/favicon/browserconfig.xml +12 -0
- data/lib/device/tracker/public/favicon/favicon-16x16.png +0 -0
- data/lib/device/tracker/public/favicon/favicon-32x32.png +0 -0
- data/lib/device/tracker/public/favicon/favicon-96x96.png +0 -0
- data/lib/device/tracker/public/favicon/favicon.ico +0 -0
- data/lib/device/tracker/public/favicon/manifest.json +41 -0
- data/lib/device/tracker/public/favicon/mstile-144x144.png +0 -0
- data/lib/device/tracker/public/favicon/mstile-150x150.png +0 -0
- data/lib/device/tracker/public/favicon/mstile-310x150.png +0 -0
- data/lib/device/tracker/public/favicon/mstile-310x310.png +0 -0
- data/lib/device/tracker/public/favicon/mstile-70x70.png +0 -0
- data/lib/device/tracker/public/favicon/safari-pinned-tab.svg +21 -0
- data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.svg +288 -0
- data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/lib/device/tracker/public/js/bootstrap-sortable.js +211 -0
- data/lib/device/tracker/public/js/bootstrap.min.js +7 -0
- data/lib/device/tracker/public/js/jquery-2.1.4.min.js +4 -0
- data/lib/device/tracker/version.rb +5 -0
- data/lib/device/tracker/views/404.erb +25 -0
- data/lib/device/tracker/views/_alert.erb +5 -0
- data/lib/device/tracker/views/_device_form.erb +52 -0
- data/lib/device/tracker/views/_device_list.erb +47 -0
- data/lib/device/tracker/views/_footer.erb +3 -0
- data/lib/device/tracker/views/_header.erb +97 -0
- data/lib/device/tracker/views/_heartbeat_list.erb +25 -0
- data/lib/device/tracker/views/_user_form.erb +30 -0
- data/lib/device/tracker/views/devices/edit.erb +11 -0
- data/lib/device/tracker/views/devices/index.erb +12 -0
- data/lib/device/tracker/views/devices/new.erb +10 -0
- data/lib/device/tracker/views/devices/show.erb +283 -0
- data/lib/device/tracker/views/devices/users.erb +14 -0
- data/lib/device/tracker/views/emails/new_password.erb +17 -0
- data/lib/device/tracker/views/emails/password_reset.erb +18 -0
- data/lib/device/tracker/views/emails/registration.erb +16 -0
- data/lib/device/tracker/views/emails/reminder.erb +15 -0
- data/lib/device/tracker/views/emails/verification.erb +18 -0
- data/lib/device/tracker/views/forgot_password.erb +6 -0
- data/lib/device/tracker/views/index.erb +38 -0
- data/lib/device/tracker/views/layout.erb +8 -0
- data/lib/device/tracker/views/login.erb +14 -0
- data/lib/device/tracker/views/operating_system/operating_systems.json.jbuilder +9 -0
- data/lib/device/tracker/views/os/manage.erb +38 -0
- data/lib/device/tracker/views/transactions/_transactions_list.erb +18 -0
- data/lib/device/tracker/views/transactions/index.erb +3 -0
- data/lib/device/tracker/views/users/edit.erb +9 -0
- data/lib/device/tracker/views/users/manage.erb +31 -0
- data/lib/device/tracker/views/users/new.erb +7 -0
- metadata +427 -0
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateUsers < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :users do |t|
|
4
|
+
t.string :username, index: true
|
5
|
+
t.string :name
|
6
|
+
t.string :password_digest
|
7
|
+
t.string :email
|
8
|
+
t.boolean :is_active, default: false
|
9
|
+
t.boolean :is_admin, default: false
|
10
|
+
t.timestamps null: false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateDevices < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
|
4
|
+
create_table :devices do |t|
|
5
|
+
|
6
|
+
t.string :unid, index: true
|
7
|
+
t.string :manufacturer
|
8
|
+
t.string :device
|
9
|
+
t.text :description
|
10
|
+
t.datetime :checked_out_since
|
11
|
+
t.boolean :available, default: true
|
12
|
+
t.string :imei, default: nil
|
13
|
+
t.belongs_to :operating_system
|
14
|
+
t.belongs_to :user
|
15
|
+
|
16
|
+
t.boolean :sim_card, default: false
|
17
|
+
t.boolean :debug_device, default: false
|
18
|
+
|
19
|
+
t.timestamps null: false
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateTransactions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :transactions do |t|
|
4
|
+
t.string :transaction_type, index: true
|
5
|
+
|
6
|
+
t.belongs_to :user
|
7
|
+
t.belongs_to :device
|
8
|
+
|
9
|
+
t.text :description
|
10
|
+
t.datetime :created_at
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class CreateHeartbeat < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :heartbeats do |t|
|
4
|
+
t.decimal :longitude, { precision: 10, scale: 6 }
|
5
|
+
t.decimal :latitude, { precision: 10, scale: 6 }
|
6
|
+
t.belongs_to :device
|
7
|
+
t.timestamps null: false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# This file is auto-generated from the current state of the database. Instead
|
3
|
+
# of editing this file, please use the migrations feature of Active Record to
|
4
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
5
|
+
#
|
6
|
+
# Note that this schema.rb definition is the authoritative source for your
|
7
|
+
# database schema. If you need to create the application database on another
|
8
|
+
# system, you should be using db:schema:load, not running all the migrations
|
9
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
10
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
11
|
+
#
|
12
|
+
# It's strongly recommended that you check this file into your version control system.
|
13
|
+
|
14
|
+
ActiveRecord::Schema.define(version: 20151109121036) do
|
15
|
+
|
16
|
+
create_table "devices", force: :cascade do |t|
|
17
|
+
t.string "unid"
|
18
|
+
t.string "manufacturer"
|
19
|
+
t.string "device"
|
20
|
+
t.text "description"
|
21
|
+
t.datetime "checked_out_since"
|
22
|
+
t.boolean "available", default: true
|
23
|
+
t.string "imei"
|
24
|
+
t.integer "operating_system_id"
|
25
|
+
t.integer "user_id"
|
26
|
+
t.boolean "sim_card", default: false
|
27
|
+
t.boolean "debug_device", default: false
|
28
|
+
t.datetime "created_at", null: false
|
29
|
+
t.datetime "updated_at", null: false
|
30
|
+
t.boolean "missing", default: false
|
31
|
+
t.integer "checkout_count", default: 0
|
32
|
+
t.string "serial_number"
|
33
|
+
end
|
34
|
+
|
35
|
+
add_index "devices", ["unid"], name: "index_devices_on_unid"
|
36
|
+
|
37
|
+
create_table "heartbeats", force: :cascade do |t|
|
38
|
+
t.decimal "longitude", precision: 10, scale: 6
|
39
|
+
t.decimal "latitude", precision: 10, scale: 6
|
40
|
+
t.integer "device_id"
|
41
|
+
t.datetime "created_at", null: false
|
42
|
+
t.datetime "updated_at", null: false
|
43
|
+
end
|
44
|
+
|
45
|
+
create_table "operating_systems", force: :cascade do |t|
|
46
|
+
t.string "name"
|
47
|
+
t.integer "api_level"
|
48
|
+
end
|
49
|
+
|
50
|
+
create_table "transactions", force: :cascade do |t|
|
51
|
+
t.string "transaction_type"
|
52
|
+
t.integer "user_id"
|
53
|
+
t.integer "device_id"
|
54
|
+
t.text "description"
|
55
|
+
t.datetime "created_at"
|
56
|
+
end
|
57
|
+
|
58
|
+
add_index "transactions", ["transaction_type"], name: "index_transactions_on_transaction_type"
|
59
|
+
|
60
|
+
create_table "users", force: :cascade do |t|
|
61
|
+
t.string "username"
|
62
|
+
t.string "name"
|
63
|
+
t.string "password_digest"
|
64
|
+
t.string "email"
|
65
|
+
t.boolean "is_admin", default: false
|
66
|
+
t.datetime "created_at", null: false
|
67
|
+
t.datetime "updated_at", null: false
|
68
|
+
t.boolean "is_verified", default: false
|
69
|
+
t.string "reset_code"
|
70
|
+
end
|
71
|
+
|
72
|
+
add_index "users", ["username"], name: "index_users_on_username"
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Device
|
2
|
+
module Tracker
|
3
|
+
class Seed
|
4
|
+
def self.seed(name: name, password: password, email: email)
|
5
|
+
user = User.find_or_create_by({
|
6
|
+
name: name,
|
7
|
+
username: 'admin',
|
8
|
+
email: email,
|
9
|
+
is_admin: true,
|
10
|
+
is_verified: true
|
11
|
+
})
|
12
|
+
user.password = password
|
13
|
+
user.save
|
14
|
+
puts "Added #{user.username} to the database."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
%w(
|
5
|
+
sinatra
|
6
|
+
sinatra/activerecord
|
7
|
+
sinatra/flash
|
8
|
+
sinatra/partial
|
9
|
+
tilt/erb
|
10
|
+
json
|
11
|
+
pony
|
12
|
+
).each { |d| require d }
|
13
|
+
|
14
|
+
puts File.dirname(__FILE__)
|
15
|
+
Dir.glob("#{File.dirname(__FILE__)}/{helpers,controllers,models}/*.rb").each { |file| require file }
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Device
|
2
|
+
module Tracker
|
3
|
+
module ApplicationHelper
|
4
|
+
|
5
|
+
SECRET = 'mYR4nd0mAr$eS3cr3t/fuGg1wugGl3'
|
6
|
+
|
7
|
+
def is_admin?
|
8
|
+
user = get_logged_in_user
|
9
|
+
return if user.nil?
|
10
|
+
user[:is_admin]
|
11
|
+
end
|
12
|
+
|
13
|
+
def value_for(name, object)
|
14
|
+
if flash[name]
|
15
|
+
flash[name]
|
16
|
+
elsif object
|
17
|
+
object.send name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_logged_in_user
|
22
|
+
session[:user] unless session[:user].nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_activation_code(size = 6)
|
26
|
+
charset = %w{0 1 2 3 4 6 7 8 9 A C D E F G H J K M N P Q R T V W X Y Z}
|
27
|
+
(0...size).map{ charset.to_a[rand(charset.size)] }.join
|
28
|
+
end
|
29
|
+
|
30
|
+
def change_password?(params)
|
31
|
+
if params[:user][:password].empty? or params[:user][:password_confirmation].empty?
|
32
|
+
false
|
33
|
+
else
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def protected!
|
39
|
+
if session[:user].nil?
|
40
|
+
create_flash "info", ["You must be logged in to see this page."]
|
41
|
+
redirect "/login"
|
42
|
+
elsif !session[:user][:is_verified]
|
43
|
+
create_flash "info", ["You account is awaiting verification by an admin."]
|
44
|
+
redirect "/login"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def report_transaction(message, type, device = nil)
|
49
|
+
transaction = Transaction.new
|
50
|
+
|
51
|
+
if session[:user]
|
52
|
+
transaction.user_id = get_logged_in_user[:id]
|
53
|
+
end
|
54
|
+
|
55
|
+
transaction.description = message
|
56
|
+
transaction.transaction_type = type
|
57
|
+
transaction.device_id = device.id unless device.nil?
|
58
|
+
|
59
|
+
transaction.save!
|
60
|
+
end
|
61
|
+
|
62
|
+
def perform_admin_check
|
63
|
+
user = get_logged_in_user
|
64
|
+
if user.nil? or user[:is_admin] == false
|
65
|
+
create_flash "warning", ["#{user[:name]} does not have permissions to access this page."]
|
66
|
+
redirect back
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_flash(type, message)
|
71
|
+
flash[:message] = {css_class: type, message: message }
|
72
|
+
end
|
73
|
+
|
74
|
+
def valid_heartbeat?(data)
|
75
|
+
if !data["heartbeat"].nil? and !data["heartbeat"]["longitude"].nil? and
|
76
|
+
!data["heartbeat"]["latitude"].nil? and !data["heartbeat"]["device_id"].nil?
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Device
|
4
|
+
module Tracker
|
5
|
+
class Device < ActiveRecord::Base
|
6
|
+
|
7
|
+
belongs_to :operating_system
|
8
|
+
belongs_to :user
|
9
|
+
|
10
|
+
has_many :transactions
|
11
|
+
has_many :heartbeats
|
12
|
+
|
13
|
+
validates :unid, :manufacturer, :device, :description, :operating_system, presence: true
|
14
|
+
|
15
|
+
validates :unid, uniqueness: true
|
16
|
+
|
17
|
+
def unid=(unid)
|
18
|
+
self[:unid] = unid.upcase
|
19
|
+
end
|
20
|
+
|
21
|
+
def full_name
|
22
|
+
self[:manufacturer] + " " + self[:device]
|
23
|
+
end
|
24
|
+
|
25
|
+
def passed_use_by_date?
|
26
|
+
(! self[:available] and (Time.now - self[:checked_out_since]).to_i / 1.day >= 3)
|
27
|
+
end
|
28
|
+
|
29
|
+
def checked_out_since_formatted
|
30
|
+
self[:checked_out_since].strftime("%A, %d %B %Y at %I:%M%p")
|
31
|
+
end
|
32
|
+
|
33
|
+
def days_checked_out
|
34
|
+
(Time.now.to_date - self[:checked_out_since].to_date).floor
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "date"
|
2
|
+
|
3
|
+
module Device
|
4
|
+
module Tracker
|
5
|
+
class Transaction < ActiveRecord::Base
|
6
|
+
|
7
|
+
belongs_to :user
|
8
|
+
belongs_to :device
|
9
|
+
|
10
|
+
validates :transaction_type, :description, presence: true
|
11
|
+
validates :transaction_type, inclusion: { in: %w(CHECKOUT RETURN REGISTRATION LOGIN ACTIVATE DEACTIVATE DELETION MISSING FOUND),
|
12
|
+
message: "%{value} is not a valid transaction." }
|
13
|
+
|
14
|
+
def created_at
|
15
|
+
self[:created_at].strftime("%a %d %b %Y at %H:%M:%S")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.missing
|
19
|
+
"MISSING"
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.found
|
23
|
+
"FOUND"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.activate
|
27
|
+
"ACTIVATE"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.deactivate
|
31
|
+
"DEACTIVATE"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.checkout
|
35
|
+
"CHECKOUT"
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.return
|
39
|
+
"RETURN"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.registration
|
43
|
+
"REGISTRATION"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.login
|
47
|
+
"LOGIN"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.deletion
|
51
|
+
"DELETION"
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
module Device
|
4
|
+
module Tracker
|
5
|
+
class User < ActiveRecord::Base
|
6
|
+
has_secure_password
|
7
|
+
has_many :devices
|
8
|
+
has_many :transactions
|
9
|
+
validates :username, :name, :email, presence: true
|
10
|
+
validates :password, :presence => { :if => :password_required? }
|
11
|
+
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
|
12
|
+
validates :username, uniqueness: true
|
13
|
+
validates :email, uniqueness: true
|
14
|
+
validates_confirmation_of :password
|
15
|
+
|
16
|
+
protected
|
17
|
+
def password_required?
|
18
|
+
self.new_record?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|