device-tracker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +6 -0
  5. data/Readme.md +32 -0
  6. data/bin/console +14 -0
  7. data/bin/setup +7 -0
  8. data/device-tracker.gemspec +54 -0
  9. data/exe/device-tracker +50 -0
  10. data/lib/device/tracker.rb +19 -0
  11. data/lib/device/tracker/app.rb +25 -0
  12. data/lib/device/tracker/config-schema.json +53 -0
  13. data/lib/device/tracker/config.ru +9 -0
  14. data/lib/device/tracker/controllers/application_controller.rb +215 -0
  15. data/lib/device/tracker/controllers/devices_controller.rb +315 -0
  16. data/lib/device/tracker/controllers/heartbeat_controller.rb +55 -0
  17. data/lib/device/tracker/controllers/os_controller.rb +43 -0
  18. data/lib/device/tracker/controllers/transactions_controller.rb +21 -0
  19. data/lib/device/tracker/controllers/users_controller.rb +193 -0
  20. data/lib/device/tracker/db/data/devices.xlsx +0 -0
  21. data/lib/device/tracker/db/migrate/20150521071815_create_users.rb +13 -0
  22. data/lib/device/tracker/db/migrate/20150521082155_create_devices.rb +23 -0
  23. data/lib/device/tracker/db/migrate/20150521120335_create_operating_systems.rb +8 -0
  24. data/lib/device/tracker/db/migrate/20150527162242_create_transactions.rb +13 -0
  25. data/lib/device/tracker/db/migrate/20151027073050_create_heartbeat.rb +10 -0
  26. data/lib/device/tracker/db/migrate/20151028132946_add_user_verification.rb +7 -0
  27. data/lib/device/tracker/db/migrate/20151028141328_remove_is_active_from_users.rb +5 -0
  28. data/lib/device/tracker/db/migrate/20151029085629_add_password_reset_code_to_users.rb +7 -0
  29. data/lib/device/tracker/db/migrate/20151030130341_add_missing_column_to_devices.rb +7 -0
  30. data/lib/device/tracker/db/migrate/20151102141601_add_serial_number_to_devices.rb +7 -0
  31. data/lib/device/tracker/db/schema.rb +74 -0
  32. data/lib/device/tracker/db/seeds.rb +18 -0
  33. data/lib/device/tracker/dependencies.rb +15 -0
  34. data/lib/device/tracker/helpers/application_helper.rb +84 -0
  35. data/lib/device/tracker/models/device.rb +39 -0
  36. data/lib/device/tracker/models/heartbeat.rb +9 -0
  37. data/lib/device/tracker/models/operating_system.rb +8 -0
  38. data/lib/device/tracker/models/transaction.rb +56 -0
  39. data/lib/device/tracker/models/user.rb +22 -0
  40. data/lib/device/tracker/public/css/bootstrap-sortable.css +100 -0
  41. data/lib/device/tracker/public/css/bootstrap.min.css +5 -0
  42. data/lib/device/tracker/public/css/custom.css +88 -0
  43. data/lib/device/tracker/public/favicon.png +0 -0
  44. data/lib/device/tracker/public/favicon/android-chrome-144x144.png +0 -0
  45. data/lib/device/tracker/public/favicon/android-chrome-192x192.png +0 -0
  46. data/lib/device/tracker/public/favicon/android-chrome-36x36.png +0 -0
  47. data/lib/device/tracker/public/favicon/android-chrome-48x48.png +0 -0
  48. data/lib/device/tracker/public/favicon/android-chrome-72x72.png +0 -0
  49. data/lib/device/tracker/public/favicon/android-chrome-96x96.png +0 -0
  50. data/lib/device/tracker/public/favicon/apple-touch-icon-114x114.png +0 -0
  51. data/lib/device/tracker/public/favicon/apple-touch-icon-120x120.png +0 -0
  52. data/lib/device/tracker/public/favicon/apple-touch-icon-144x144.png +0 -0
  53. data/lib/device/tracker/public/favicon/apple-touch-icon-152x152.png +0 -0
  54. data/lib/device/tracker/public/favicon/apple-touch-icon-180x180.png +0 -0
  55. data/lib/device/tracker/public/favicon/apple-touch-icon-57x57.png +0 -0
  56. data/lib/device/tracker/public/favicon/apple-touch-icon-60x60.png +0 -0
  57. data/lib/device/tracker/public/favicon/apple-touch-icon-72x72.png +0 -0
  58. data/lib/device/tracker/public/favicon/apple-touch-icon-76x76.png +0 -0
  59. data/lib/device/tracker/public/favicon/apple-touch-icon-precomposed.png +0 -0
  60. data/lib/device/tracker/public/favicon/apple-touch-icon.png +0 -0
  61. data/lib/device/tracker/public/favicon/browserconfig.xml +12 -0
  62. data/lib/device/tracker/public/favicon/favicon-16x16.png +0 -0
  63. data/lib/device/tracker/public/favicon/favicon-32x32.png +0 -0
  64. data/lib/device/tracker/public/favicon/favicon-96x96.png +0 -0
  65. data/lib/device/tracker/public/favicon/favicon.ico +0 -0
  66. data/lib/device/tracker/public/favicon/manifest.json +41 -0
  67. data/lib/device/tracker/public/favicon/mstile-144x144.png +0 -0
  68. data/lib/device/tracker/public/favicon/mstile-150x150.png +0 -0
  69. data/lib/device/tracker/public/favicon/mstile-310x150.png +0 -0
  70. data/lib/device/tracker/public/favicon/mstile-310x310.png +0 -0
  71. data/lib/device/tracker/public/favicon/mstile-70x70.png +0 -0
  72. data/lib/device/tracker/public/favicon/safari-pinned-tab.svg +21 -0
  73. data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.eot +0 -0
  74. data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.svg +288 -0
  75. data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  76. data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.woff +0 -0
  77. data/lib/device/tracker/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  78. data/lib/device/tracker/public/js/bootstrap-sortable.js +211 -0
  79. data/lib/device/tracker/public/js/bootstrap.min.js +7 -0
  80. data/lib/device/tracker/public/js/jquery-2.1.4.min.js +4 -0
  81. data/lib/device/tracker/version.rb +5 -0
  82. data/lib/device/tracker/views/404.erb +25 -0
  83. data/lib/device/tracker/views/_alert.erb +5 -0
  84. data/lib/device/tracker/views/_device_form.erb +52 -0
  85. data/lib/device/tracker/views/_device_list.erb +47 -0
  86. data/lib/device/tracker/views/_footer.erb +3 -0
  87. data/lib/device/tracker/views/_header.erb +97 -0
  88. data/lib/device/tracker/views/_heartbeat_list.erb +25 -0
  89. data/lib/device/tracker/views/_user_form.erb +30 -0
  90. data/lib/device/tracker/views/devices/edit.erb +11 -0
  91. data/lib/device/tracker/views/devices/index.erb +12 -0
  92. data/lib/device/tracker/views/devices/new.erb +10 -0
  93. data/lib/device/tracker/views/devices/show.erb +283 -0
  94. data/lib/device/tracker/views/devices/users.erb +14 -0
  95. data/lib/device/tracker/views/emails/new_password.erb +17 -0
  96. data/lib/device/tracker/views/emails/password_reset.erb +18 -0
  97. data/lib/device/tracker/views/emails/registration.erb +16 -0
  98. data/lib/device/tracker/views/emails/reminder.erb +15 -0
  99. data/lib/device/tracker/views/emails/verification.erb +18 -0
  100. data/lib/device/tracker/views/forgot_password.erb +6 -0
  101. data/lib/device/tracker/views/index.erb +38 -0
  102. data/lib/device/tracker/views/layout.erb +8 -0
  103. data/lib/device/tracker/views/login.erb +14 -0
  104. data/lib/device/tracker/views/operating_system/operating_systems.json.jbuilder +9 -0
  105. data/lib/device/tracker/views/os/manage.erb +38 -0
  106. data/lib/device/tracker/views/transactions/_transactions_list.erb +18 -0
  107. data/lib/device/tracker/views/transactions/index.erb +3 -0
  108. data/lib/device/tracker/views/users/edit.erb +9 -0
  109. data/lib/device/tracker/views/users/manage.erb +31 -0
  110. data/lib/device/tracker/views/users/new.erb +7 -0
  111. metadata +427 -0
@@ -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,8 @@
1
+ class CreateOperatingSystems < ActiveRecord::Migration
2
+ def change
3
+ create_table :operating_systems do |t|
4
+ t.string :name
5
+ t.integer :api_level
6
+ end
7
+ end
8
+ 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,7 @@
1
+ class AddUserVerification < ActiveRecord::Migration
2
+ def change
3
+ change_table :users do |t|
4
+ t.boolean :is_verified, default: false
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class RemoveIsActiveFromUsers < ActiveRecord::Migration
2
+ def change
3
+ remove_column :users, :is_active, :boolean, default: false
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ class AddPasswordResetCodeToUsers < ActiveRecord::Migration
2
+ def change
3
+ change_table :users do |t|
4
+ t.string :reset_code, default: nil
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class AddMissingColumnToDevices < ActiveRecord::Migration
2
+ def change
3
+ change_table :devices do |t|
4
+ t.boolean :missing, default: false
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class AddSerialNumberToDevices < ActiveRecord::Migration
2
+ def change
3
+ change_table :devices do |t|
4
+ t.string :serial_number
5
+ end
6
+ end
7
+ 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,9 @@
1
+ module Device
2
+ module Tracker
3
+ class Heartbeat < ActiveRecord::Base
4
+ validates :longitude, :latitude, :device_id, presence: true
5
+
6
+ belongs_to :device
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Device
2
+ module Tracker
3
+ class OperatingSystem < ActiveRecord::Base
4
+ validates :name, presence: true, uniqueness: true
5
+ has_many :devices
6
+ end
7
+ end
8
+ 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