Managing loaner chromebooks for students and teachers in the HUUSD school district.
at main 178 lines 4.7 kB view raw
1# == Schema Information 2# 3# Table name: loaners 4# 5# id :integer not null, primary key 6# active :boolean 7# asset_tag :string 8# serial_number :string 9# status :string 10# created_at :datetime not null 11# updated_at :datetime not null 12# current_loan_id :integer 13# freindly_id :integer 14# loaner_id :integer 15# 16# Indexes 17# 18# index_loaners_on_asset_tag (asset_tag) 19# index_loaners_on_current_loan_id (current_loan_id) 20# index_loaners_on_loaner_id (loaner_id) 21# index_loaners_on_status (status) 22# 23# Foreign Keys 24# 25# current_loan_id (current_loan_id => loans.id) 26# 27class AssetTagValidator < ActiveModel::Validator 28 def validate(record) 29 # Increment a counter for validation attempts 30 StatsD.increment("asset_tag_validation_attempts") 31 32 if record.asset_tag.blank? 33 # Log and increment counter for blank asset tag errors 34 StatsD.increment("asset_tag_validation_blank_errors") 35 record.errors.add(:asset_tag, "can't be blank") 36 elsif record.asset_tag =~ /^[0-9]{6}$/ 37 # Log successful validation 38 StatsD.increment("asset_tag_validation_success") 39 else 40 # Log and increment counter for format errors 41 StatsD.increment("asset_tag_validation_format_errors") 42 record.errors.add(:asset_tag, 'must be a 6-digit number') 43 end 44 end 45end 46 47class Loaner < ApplicationRecord 48 include AASM 49 50 before_create :set_loaner_id 51 52 def chrome_device 53 # TODO: Get Google Auth working 54 GoogleService.instance.get_chrome_device(self.serial_number) 55 end 56 57 def chrome_status 58 chrome_device.status 59 end 60 61 def chrome_status_update(status) 62 chrome_device.status = status 63 # TODO: Get Google Auth working 64 GoogleService.instance.update_chrome_device(self.serial_number, chrome_device) 65 end 66 67 def chrome_disable 68 chrome_status_update("DISABLED") 69 end 70 71 def chrome_enable 72 chrome_status_update("ACTIVE") 73 end 74 75 aasm column: 'status' do 76 state :available, initial: true, display: "Available" 77 state :loaned, display: "Loaned" 78 state :disabled, display: "Disabled" 79 state :maintenance, display: "Maintenance" 80 state :decommissioned, display: "Decommissioned" 81 82 after_all_transitions :log_status_change 83 84 event :loan do 85 transitions from: :available, to: :loaned 86 87 after do 88 StatsD.increment("loaner.loaned") 89 assign_current_loan 90 end 91 end 92 93 event :return do 94 transitions from: :loaned, to: :available 95 96 after do 97 StatsD.increment("loaner.returned") 98 99 if self.current_loan 100 self.current_loan.return! 101 else 102 Rails.logger.warn "Attempted to return a loaner without a current loan" 103 end 104 end 105 end 106 107 108 event :disable do 109 transitions from: [:available, :loaned], to: :disabled 110 111 after do 112 chrome_disable() 113 StatsD.increment("loaner.disabled") 114 end 115 end 116 117 event :enable do 118 transitions from: :disabled, to: :available 119 120 after do 121 chrome_enable() 122 StatsD.increment("loaner.enabled") 123 end 124 end 125 126 event :broken do 127 transitions from: [:available, :loaned], to: :maintenance 128 129 after do 130 StatsD.increment("loaner.broken") 131 end 132 end 133 134 event :repair do 135 transitions from: :maintenance, to: :available 136 137 after do 138 StatsD.increment("loaner.repaired") 139 end 140 end 141 end 142 143 def log_status_change 144 StatsD.increment("loaner.status_change", tags: ["from:#{aasm.from_state}", "to:#{aasm.to_state}", "event:#{aasm.current_event}"]) 145 Rails.logger.info "Changing from #{aasm.from_state} to #{aasm.to_state} (event: #{aasm.current_event})" 146 end 147 148 validates :asset_tag, presence: true, uniqueness: true 149 validates_with AssetTagValidator 150 validates :serial_number, uniqueness: true 151 validates :loaner_id, presence: true, uniqueness: true 152 153 has_many :loans, foreign_key: 'loaner_id' 154 has_one :current_loan, -> { where(status: 'out').order(loaned_at: :desc) }, class_name: 'Loan' 155 has_many :borrowers, through: :loans 156 157 private 158 159 def set_loaner_id 160 StatsD.measure("loaner.set_loaner_id_time") do 161 max_id = Loaner.maximum(:loaner_id) || 0 162 self.loaner_id = max_id + 1 163 StatsD.increment("loaner.id_set") 164 end 165 end 166 167 def assign_current_loan 168 StatsD.measure("loaner.assign_current_loan_time") do 169 current_loan = loans.pending.first 170 if current_loan 171 self.current_loan_id = current_loan.id 172 save! 173 StatsD.increment("loaner.current_loan_assigned") 174 current_loan.loan! 175 end 176 end 177 end 178end