class Kobot::Engine
The core class that launches browser, logins to KOT, reads today record, and conducts clock in or clock out action based on config.
Public Class Methods
new()
click to toggle source
# File lib/kobot/engine.rb, line 9 def initialize @now = Time.now.getlocal(Config.kot_timezone_offset) @today = @now.strftime(Config.kot_date_format) @top_url = Config.kot_url end
Public Instance Methods
start()
click to toggle source
The entrance where the whole flow starts.
It exits early if today is weekend or marked as to skip by the #{Config.skip} specified from command line option –skip.
Unexpected behavior such as record appearing as holiday on the web or failure of clock in/out action is handled within the method by logging and/or email notifications if enabled.
System errors or any unknown exceptions occurred if any are to be popped up and should be handled by the outside caller.
# File lib/kobot/engine.rb, line 26 def start return unless should_run_today? launch_browser login read_today_record validate_today_record! if Config.clock == :in clock_in! else clock_out! end logout rescue KotRecordError => e Kobot.logger.warn(e.message) Mailer.send(clock_notify_message(status: e.message)) logout rescue KotClockInError => e Kobot.logger.warn e.message Mailer.send(clock_notify_message(clock: :in, status: e.message)) logout rescue KotClockOutError => e Kobot.logger.warn e.message Mailer.send(clock_notify_message(clock: :out, status: e.message)) logout rescue StandardError => e Kobot.logger.error(e.message) Kobot.logger.error(e.backtrace) Mailer.send(clock_notify_message(status: e.message)) logout ensure close_browser end
Private Instance Methods
clock_in!()
click to toggle source
# File lib/kobot/engine.rb, line 185 def clock_in! Kobot.logger.warn("Clock in during the afternoon: #{@now}") if @now.hour > 12 if @kot_today_clock_in.strip.empty? click_clock_in_button return if Config.dryrun read_today_record raise KotClockInError, 'Clock in operation seems to have failed' if @kot_today_clock_in.strip.empty? Kobot.logger.info("Clock in successful: #{@kot_today_clock_in}") Mailer.send(clock_notify_message(clock: :in)) else Kobot.logger.warn("Clock in done already: #{@kot_today_clock_in}") end end
clock_notify_message(clock: nil, status: :success)
click to toggle source
# File lib/kobot/engine.rb, line 277 def clock_notify_message(clock: nil, status: :success) color = status == :success ? 'green' : 'red' message = [ "<b>Date:</b> #{@today}", "<b>Status:</b> <span style='color:#{color}'>#{status}</span>" ] message << "<b>Clock_in:</b> #{@kot_today_clock_in}" if clock message << "<b>Clock_out:</b> #{@kot_today_clock_out}" if clock == :out message.join('<br>') end
clock_out!()
click to toggle source
# File lib/kobot/engine.rb, line 201 def clock_out! Kobot.logger.warn("Clock out during the morning: #{@now}") if @now.hour <= 12 unless Config.dryrun if @kot_today_clock_in.strip.empty? raise KotClockOutError, "!!!No clock in record for today=#{@kot_today}!!!" end end if @kot_today_clock_out.strip.empty? click_clock_out_button return if Config.dryrun read_today_record raise KotClockOutError, 'Clock out operation seems to have failed' if @kot_today_clock_out.strip.empty? Kobot.logger.info("Clock out successful: #{@kot_today_clock_out}") Mailer.send(clock_notify_message(clock: :out)) else Kobot.logger.warn("Clock out done already: #{@kot_today_clock_out}") end end
close_browser()
click to toggle source
# File lib/kobot/engine.rb, line 89 def close_browser return unless @browser Kobot.logger.info('Close browser') @browser.quit end
kot_public_holiday?()
click to toggle source
# File lib/kobot/engine.rb, line 263 def kot_public_holiday? return true if @kot_today_type&.include? '休日' kot_today_highlighted = %w[sunday saturday].any? do |css| @kot_today_css_class&.include? css end if kot_today_highlighted Kobot.logger.warn( "Today=#{@kot_today} is highlighted (holiday) but not marked as 休日" ) end kot_today_highlighted end
kot_weekend?()
click to toggle source
# File lib/kobot/engine.rb, line 259 def kot_weekend? %w[土 日].any? { |kanji| @kot_today&.include? kanji } end
launch_browser()
click to toggle source
# File lib/kobot/engine.rb, line 74 def launch_browser prefs = { profile: { default_content_settings: { geolocation: Config.browser_geolocation ? 1 : 2 } } } options = Selenium::WebDriver::Chrome::Options.new(prefs: prefs) options.headless! if Config.browser_headless @browser = Selenium::WebDriver.for(:chrome, options: options) @wait = Selenium::WebDriver::Wait.new(timeout: Config.browser_wait_timeout) Kobot.logger.info('Launch browser successful') end
login()
click to toggle source
# File lib/kobot/engine.rb, line 96 def login Kobot.logger.info("Navigate to: #{@top_url}") @browser.get @top_url @wait.until { @browser.find_element(id: 'modal_window') } Kobot.logger.info "Page title: #{@browser.title}" Kobot.logger.debug do "Login with id=#{Credential.kot_id} and password=#{Credential.kot_password}" end @browser.find_element(id: 'id').send_keys Credential.kot_id @browser.find_element(id: 'password').send_keys Credential.kot_password @browser.find_element(css: 'div.btn-control-message').click Kobot.logger.info 'Login successful' @wait.until { @browser.find_element(id: 'notification_content').text.include?('データを取得しました') } if Config.browser_geolocation begin @wait.until { @browser.find_element(id: 'location_area').text.include?('位置情報取得済み') } rescue StandardError => e Kobot.logger.warn "Get geolocation failed: #{e.message}" end end Kobot.logger.info "Page title: #{@browser.title}" end
logout()
click to toggle source
# File lib/kobot/engine.rb, line 120 def logout if @browser.current_url.include? 'admin' Kobot.logger.info('Logout from タイムカード page') @browser.find_element(css: 'div.htBlock-header_logoutButton').click else Kobot.logger.info('Logout from Myレコーダー page') @wait.until { @browser.find_element(id: 'menu_icon') }.click @wait.until { @browser.find_element(link: 'ログアウト') }.click @browser.switch_to.alert.accept end Kobot.logger.info 'Logout successful' end
read_today_record()
click to toggle source
# File lib/kobot/engine.rb, line 133 def read_today_record Kobot.logger.info('Navigate to タイムカード page') @wait.until { @browser.find_element(id: 'menu_icon') }.click @wait.until { @browser.find_element(link: 'タイムカード') }.click time_table = @wait.until { @browser.find_element(css: 'div.htBlock-adjastableTableF_inner > table') } time_table.find_elements(css: 'tbody > tr').each do |tr| date_cell = tr.find_element(css: 'td.htBlock-scrollTable_day') next unless date_cell.text.include? @today Kobot.logger.info('Reading today record') @kot_today = date_cell.text @kot_today_css_class = date_cell.attribute('class') @kot_today_type = tr.find_element(css: 'td.work_day_type').text @kot_today_clock_in = tr.find_element( css: 'td.start_end_timerecord[data-ht-sort-index="START_TIMERECORD"]' ).text @kot_today_clock_out = tr.find_element( css: 'td.start_end_timerecord[data-ht-sort-index="END_TIMERECORD"]' ).text Kobot.logger.debug do { kot_toay: @kot_today, kot_today_css_class: @kot_today_css_class, kot_today_type: @kot_today_type, kot_today_clock_in: @kot_today_clock_in, kot_today_clock_out: @kot_today_clock_out } end break end end
should_run_today?()
click to toggle source
# File lib/kobot/engine.rb, line 62 def should_run_today? if skip? Kobot.logger.warn("Today=#{@today} is skipped as per: --skip=#{Config.skip}") return false end return true unless weekend? Kobot.logger.info("[Force] should have exited: today=#{@today} is weekend") if Config.force Kobot.logger.warn("Today=#{@today} is weekend") unless Config.force Config.force end
skip?()
click to toggle source
# File lib/kobot/engine.rb, line 252 def skip? return false unless Config.skip return false unless Config.skip.respond_to? :include? Config.skip.include? @now.strftime('%F') end
validate_today_record!()
click to toggle source
# File lib/kobot/engine.rb, line 166 def validate_today_record! raise KotRecordError, "Today=#{@today} is not found on kot" if @kot_today.strip.empty? if kot_weekend? raise KotRecordError, "Today=#{@today} is marked as weekend on kot: #{@kot_today}" unless Config.force Kobot.logger.info( "[Force] should have exited: today=#{@today} is marked as weekend on kot: #{@kot_today}" ) end return unless kot_public_holiday? raise KotRecordError, "Today=#{@today} is marked as public holiday on kot: #{@kot_today}" unless Config.force Kobot.logger.info( "[Force] should have exited: today=#{@today} is marked as public holiday on kot: #{@kot_today}" ) end
weekend?()
click to toggle source
# File lib/kobot/engine.rb, line 248 def weekend? @now.saturday? || @now.sunday? end