kobot 1.2.1 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfc009d1da0376709ddb63ebec8176601a53cee00bc216c82554c403051d430f
4
- data.tar.gz: d7df58f052b9e2e945efd43c5cb11169c20d00b7d09a5d25ebfd3b688d1e16e8
3
+ metadata.gz: f35251b3ce8549b6b268a9741ecc88398f4fca4e1fbe27c343e2a1c35d456ca0
4
+ data.tar.gz: 1af276cc34607f075650b5be4df65c9666449c761b410fb5cc63629fe0392ff7
5
5
  SHA512:
6
- metadata.gz: 7728891bc95db5eb4dd2d9a4c4d20916930da12b32c82af6ee2458d4cb9e66a7c37cb4156a89f857b93141c22d06493b7f9bce4f5238786d0031bf8b0f64d0a6
7
- data.tar.gz: e4bc4ae0867ecfbe3bdd1018c9ffb9c578f34bf189f820e7344bbca7a7d5f209faee49e73d45f737161993cb2b3ea2f006695ee7f9870ea0dd1f7dea7417ad64
6
+ metadata.gz: a1a76b64eb1aa1019a12b4f1d4a2d34c84d79cf020b0ebc7cee7c1bd4902b180aec70790ee236883100bfd2501bbee9846f61b5b40dd8fb3996159e58b94b0df
7
+ data.tar.gz: a81c35396d3dde1a74ab9aad3c3535e92699268f49a133f9f43514b192bae808a84f1974c9f9c537690ce3561c942251c044591fc363b54c619b44586ede7670
data/CHANGELOG.md CHANGED
@@ -14,3 +14,17 @@
14
14
  - Improved logging for better readability in logs
15
15
  - Switched to builtin Logger#deprecate from Logger#warn for deprecations
16
16
  - Renamed internal method to skip? from holiday? as it was meant for skipping any specified date
17
+
18
+ ### v1.2.2
19
+ - Improved login screen wait and logging
20
+ - Applied fix for offenses about empty lines and long lines reported by Rubocop
21
+
22
+ ### v1.2.3
23
+ - Improved validation logic to skip running due to weekend or intentional skips
24
+ - Refactored engine by reducing methods length based on reports by Rubocop
25
+
26
+ ### v1.2.4
27
+ - Changed to use boolean values for validation instead of raising exceptions
28
+
29
+ ### v1.2.5
30
+ - Added I18n support for both English and Japanese KOT UI
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'kobot'
data/lib/kobot/config.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobot
4
-
5
4
  # Configuration definition includes static ones hardcoded and
6
5
  # dynamic ones that can be specified by command line options.
7
6
  class Config
@@ -4,7 +4,6 @@ module Kobot
4
4
  # Credentials include id and password to login to KOT and
5
5
  # Gmail SMTP id and password to send email notifications.
6
6
  class Credential
7
-
8
7
  class << self
9
8
  attr_accessor :kot_id,
10
9
  :kot_password,
data/lib/kobot/engine.rb CHANGED
@@ -6,7 +6,6 @@ module Kobot
6
6
  # The core class that launches browser, logins to KOT, reads today
7
7
  # record, and conducts clock in or clock out action based on config.
8
8
  class Engine
9
-
10
9
  def initialize
11
10
  @now = Time.now.getlocal(Config.kot_timezone_offset)
12
11
  @today = @now.strftime(Config.kot_date_format)
@@ -15,7 +14,7 @@ module Kobot
15
14
 
16
15
  # The entrance where the whole flow starts.
17
16
  #
18
- # It exits early if today is weekend or treated as holiday by
17
+ # It exits early if today is weekend or marked as to skip by
19
18
  # the #{Config.skip} specified from command line option --skip.
20
19
  #
21
20
  # Unexpected behavior such as record appearing as holiday on
@@ -25,26 +24,12 @@ module Kobot
25
24
  # System errors or any unknown exceptions occurred if any are
26
25
  # to be popped up and should be handled by the outside caller.
27
26
  def start
28
- if weekend?
29
- if Config.force
30
- Kobot.logger.info("[Force] should have exited: today=#{@today} is weekend")
31
- else
32
- Kobot.logger.info("Today=#{@today} is weekend")
33
- return
34
- end
35
- end
36
- if skip?
37
- Kobot.logger.info("Today=#{@today} is skipped as per: --skip=#{Config.skip}")
38
- return
39
- end
40
- unless %i[in out].include? Config.clock
41
- Kobot.logger.warn("Invalid clock operation: #{Config.clock}")
42
- return
43
- end
27
+ return unless should_run_today?
28
+
44
29
  launch_browser
45
30
  login
46
31
  read_today_record
47
- verify_today_record!
32
+ validate_today_record!
48
33
  if Config.clock == :in
49
34
  clock_in!
50
35
  else
@@ -69,12 +54,23 @@ module Kobot
69
54
  Mailer.send(clock_notify_message(status: e.message))
70
55
  logout
71
56
  ensure
72
- Kobot.logger.info('Close browser')
73
- @browser&.quit
57
+ close_browser
74
58
  end
75
59
 
76
60
  private
77
61
 
62
+ def should_run_today?
63
+ if skip?
64
+ Kobot.logger.warn("Today=#{@today} is skipped as per: --skip=#{Config.skip}")
65
+ return false
66
+ end
67
+ return true unless weekend?
68
+
69
+ Kobot.logger.info("[Force] should have exited: today=#{@today} is weekend") if Config.force
70
+ Kobot.logger.warn("Today=#{@today} is weekend") unless Config.force
71
+ Config.force
72
+ end
73
+
78
74
  def launch_browser
79
75
  prefs = {
80
76
  profile: {
@@ -90,9 +86,24 @@ module Kobot
90
86
  Kobot.logger.info('Launch browser successful')
91
87
  end
92
88
 
89
+ def close_browser
90
+ return unless @browser
91
+
92
+ Kobot.logger.info('Close browser')
93
+ @browser.quit
94
+ end
95
+
93
96
  def login
94
97
  Kobot.logger.info("Navigate to: #{@top_url}")
95
98
  @browser.get @top_url
99
+ @wait.until { @browser.find_element(id: 'modal_window') }
100
+ modal_title_element = @wait.until { @browser.find_element(css: '.modal-title') }
101
+ @selector = if modal_title_element.text.downcase.include? 'password'
102
+ Selector.en
103
+ else
104
+ Selector.ja
105
+ end
106
+ Kobot.logger.info "Page title: #{@browser.title}"
96
107
  Kobot.logger.debug do
97
108
  "Login with id=#{Credential.kot_id} and password=#{Credential.kot_password}"
98
109
  end
@@ -101,10 +112,14 @@ module Kobot
101
112
  @browser.find_element(css: 'div.btn-control-message').click
102
113
 
103
114
  Kobot.logger.info 'Login successful'
104
- @wait.until { @browser.find_element(id: 'notification_content').text.include?('データを取得しました') }
115
+ @wait.until do
116
+ @browser.find_element(id: 'notification_content').text.include?(@selector.login_success_notification_text)
117
+ end
105
118
  if Config.browser_geolocation
106
119
  begin
107
- @wait.until { @browser.find_element(id: 'location_area').text.include?('位置情報取得済み') }
120
+ @wait.until do
121
+ @browser.find_element(id: 'location_area').text.include?(@selector.location_area_notification_text)
122
+ end
108
123
  rescue StandardError => e
109
124
  Kobot.logger.warn "Get geolocation failed: #{e.message}"
110
125
  end
@@ -114,21 +129,21 @@ module Kobot
114
129
 
115
130
  def logout
116
131
  if @browser.current_url.include? 'admin'
117
- Kobot.logger.info('Logout from タイムカード page')
132
+ Kobot.logger.info('Logout from Time Card (タイムカード) page')
118
133
  @browser.find_element(css: 'div.htBlock-header_logoutButton').click
119
134
  else
120
- Kobot.logger.info('Logout from Myレコーダー page')
135
+ Kobot.logger.info('Logout from My Recorder (Myレコーダー) page')
121
136
  @wait.until { @browser.find_element(id: 'menu_icon') }.click
122
- @wait.until { @browser.find_element(link: 'ログアウト') }.click
137
+ @wait.until { @browser.find_element(link: @selector.logout_menu_link_text) }.click
123
138
  @browser.switch_to.alert.accept
124
139
  end
125
140
  Kobot.logger.info 'Logout successful'
126
141
  end
127
142
 
128
143
  def read_today_record
129
- Kobot.logger.info('Navigate to タイムカード page')
144
+ Kobot.logger.info('Navigate to Time Card (タイムカード) page')
130
145
  @wait.until { @browser.find_element(id: 'menu_icon') }.click
131
- @wait.until { @browser.find_element(link: 'タイムカード') }.click
146
+ @wait.until { @browser.find_element(link: @selector.time_card_menu_link_text) }.click
132
147
 
133
148
  time_table = @wait.until { @browser.find_element(css: 'div.htBlock-adjastableTableF_inner > table') }
134
149
  time_table.find_elements(css: 'tbody > tr').each do |tr|
@@ -139,8 +154,12 @@ module Kobot
139
154
  @kot_today = date_cell.text
140
155
  @kot_today_css_class = date_cell.attribute('class')
141
156
  @kot_today_type = tr.find_element(css: 'td.work_day_type').text
142
- @kot_today_clock_in = tr.find_element(css: 'td.start_end_timerecord[data-ht-sort-index="START_TIMERECORD"]').text
143
- @kot_today_clock_out = tr.find_element(css: 'td.start_end_timerecord[data-ht-sort-index="END_TIMERECORD"]').text
157
+ @kot_today_clock_in = tr.find_element(
158
+ css: 'td.start_end_timerecord[data-ht-sort-index="START_TIMERECORD"]'
159
+ ).text
160
+ @kot_today_clock_out = tr.find_element(
161
+ css: 'td.start_end_timerecord[data-ht-sort-index="END_TIMERECORD"]'
162
+ ).text
144
163
  Kobot.logger.debug do
145
164
  {
146
165
  kot_toay: @kot_today,
@@ -154,30 +173,23 @@ module Kobot
154
173
  end
155
174
  end
156
175
 
157
- def verify_today_record!
176
+ def validate_today_record!
158
177
  raise KotRecordError, "Today=#{@today} is not found on kot" if @kot_today.strip.empty?
159
178
 
160
179
  if kot_weekend?
161
- unless Config.force
162
- raise KotRecordError,
163
- "Today=#{@today} is marked as weekend on kot: #{@kot_today}"
164
- end
180
+ raise KotRecordError, "Today=#{@today} is marked as weekend on kot: #{@kot_today}" unless Config.force
165
181
 
166
182
  Kobot.logger.info(
167
183
  "[Force] should have exited: today=#{@today} is marked as weekend on kot: #{@kot_today}"
168
184
  )
169
185
  end
170
186
 
171
- if kot_public_holiday?
172
- unless Config.force
173
- raise KotRecordError,
174
- "Today=#{@today} is marked as public holiday on kot: #{@kot_today}"
175
- end
187
+ return unless kot_public_holiday?
188
+ raise KotRecordError, "Today=#{@today} is marked as public holiday on kot: #{@kot_today}" unless Config.force
176
189
 
177
- Kobot.logger.info(
178
- "[Force] should have exited: today=#{@today} is marked as public holiday on kot: #{@kot_today}"
179
- )
180
- end
190
+ Kobot.logger.info(
191
+ "[Force] should have exited: today=#{@today} is marked as public holiday on kot: #{@kot_today}"
192
+ )
181
193
  end
182
194
 
183
195
  def clock_in!
@@ -224,9 +236,9 @@ module Kobot
224
236
  @browser.get @top_url
225
237
  clock_in_button = @wait.until { @browser.find_element(css: 'div.record-clock-in') }
226
238
  if Config.dryrun
227
- Kobot.logger.info('[Dryrun] clock in button (出勤) would have been clicked')
239
+ Kobot.logger.info('[Dryrun] Clock-in button (出勤) would have been clicked')
228
240
  else
229
- Kobot.logger.info('Clicking the clock in button (出勤)')
241
+ Kobot.logger.info('Clicking the Clock-in button (出勤)')
230
242
  clock_in_button.click
231
243
  end
232
244
  end
@@ -236,9 +248,9 @@ module Kobot
236
248
  @browser.get @top_url
237
249
  clock_out_button = @wait.until { @browser.find_element(css: 'div.record-clock-out') }
238
250
  if Config.dryrun
239
- Kobot.logger.info('[Dryrun] clock out button (退勤) would have been clicked')
251
+ Kobot.logger.info('[Dryrun] Clock-out button (退勤) would have been clicked')
240
252
  else
241
- Kobot.logger.info('Clicking the clock in button (退勤)')
253
+ Kobot.logger.info('Clicking the Clock-out button (退勤)')
242
254
  clock_out_button.click
243
255
  end
244
256
  end
@@ -255,18 +267,21 @@ module Kobot
255
267
  end
256
268
 
257
269
  def kot_weekend?
258
- %w[土 日].any? { |kanji| @kot_today&.include? kanji }
270
+ [
271
+ @selector.kot_date_saturday,
272
+ @selector.kot_date_sunday
273
+ ].any? { |weekend| @kot_today&.include? weekend }
259
274
  end
260
275
 
261
276
  def kot_public_holiday?
262
- return true if @kot_today_type&.include? '休日'
277
+ return true if @kot_today_type&.include? @selector.kot_workday_time_off_text
263
278
 
264
279
  kot_today_highlighted = %w[sunday saturday].any? do |css|
265
280
  @kot_today_css_class&.include? css
266
281
  end
267
282
  if kot_today_highlighted
268
283
  Kobot.logger.warn(
269
- "Today=#{@kot_today} is highlighted (holiday) but not marked as 休日"
284
+ "Today=#{@kot_today} is highlighted (holiday) but not marked as #{@selector.kot_workday_time_off_text}"
270
285
  )
271
286
  end
272
287
  kot_today_highlighted
@@ -1,14 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobot
4
-
5
- class KotRecordError < StandardError
6
- end
7
-
8
- class KotClockInError < StandardError
9
- end
10
-
11
- class KotClockOutError < StandardError
12
- end
13
-
4
+ class KotRecordError < StandardError; end
5
+ class KotClockInError < StandardError; end
6
+ class KotClockOutError < StandardError; end
14
7
  end
data/lib/kobot/mailer.rb CHANGED
@@ -3,11 +3,9 @@
3
3
  require 'net/smtp'
4
4
 
5
5
  module Kobot
6
-
7
6
  # Responsible for sending email notifications in SMTP with Gmail
8
7
  class Mailer
9
8
  class << self
10
-
11
9
  # Sends email in preconfigured Gmail SMTP credential and to the recipient
12
10
  # configured by #{Config.gmail_notify_to} or self if not configured, with
13
11
  # email subject set by #{Config.gmail_notify_subject}.
data/lib/kobot/option.rb CHANGED
@@ -3,11 +3,9 @@
3
3
  require 'optparse'
4
4
 
5
5
  module Kobot
6
-
7
6
  # Responsible for parsing the command line options for custom execution.
8
7
  class Option
9
8
  class << self
10
-
11
9
  # Parses command line options and returns a hash containing the options.
12
10
  def parse!
13
11
  options = {}
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kobot
4
+ # The texts used in selectors to identify the elements on KOT UI.
5
+ class Selector
6
+ attr_accessor :login_success_notification_text,
7
+ :location_area_notification_text,
8
+ :time_card_menu_link_text,
9
+ :kot_date_saturday,
10
+ :kot_date_sunday,
11
+ :kot_workday_time_off_text,
12
+ :logout_menu_link_text
13
+
14
+ class << self
15
+ def en
16
+ selector = Selector.new
17
+ selector.login_success_notification_text = 'Data has been obtained'
18
+ selector.location_area_notification_text = 'Obtained location'
19
+ selector.time_card_menu_link_text = 'Time Card'
20
+ selector.kot_date_saturday = 'Sat'
21
+ selector.kot_date_sunday = 'Sun'
22
+ selector.kot_workday_time_off_text = 'time-off'
23
+ selector.logout_menu_link_text = 'Sign out'
24
+ selector
25
+ end
26
+
27
+ def ja
28
+ selector = Selector.new
29
+ selector.login_success_notification_text = 'データを取得しました'
30
+ selector.location_area_notification_text = '位置情報取得済み'
31
+ selector.time_card_menu_link_text = 'タイムカード'
32
+ selector.kot_date_saturday = '土'
33
+ selector.kot_date_sunday = '日'
34
+ selector.kot_workday_time_off_text = '休日'
35
+ selector.logout_menu_link_text = 'ログアウト'
36
+ selector
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/kobot/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kobot
4
- VERSION = '1.2.1'
4
+ VERSION = '1.2.5'
5
5
  end
data/lib/kobot.rb CHANGED
@@ -4,6 +4,7 @@ require 'kobot/version'
4
4
  require 'kobot/exception'
5
5
  require 'kobot/option'
6
6
  require 'kobot/config'
7
+ require 'kobot/selector'
7
8
  require 'kobot/credential'
8
9
  require 'kobot/logger'
9
10
  require 'kobot/mailer'
@@ -14,8 +15,6 @@ require 'kobot/engine'
14
15
  # and with Google Gmail service email notification can also be sent to notify the results.
15
16
  module Kobot
16
17
  class << self
17
-
18
- # The entrance to run Kobot.
19
18
  def run
20
19
  configure
21
20
  Engine.new.start
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kobot
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jiang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2021-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: webdrivers
@@ -83,6 +83,7 @@ files:
83
83
  - lib/kobot/logger.rb
84
84
  - lib/kobot/mailer.rb
85
85
  - lib/kobot/option.rb
86
+ - lib/kobot/selector.rb
86
87
  - lib/kobot/version.rb
87
88
  homepage: https://github.com/yuan-jiang/kobot
88
89
  licenses:
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
108
  - !ruby/object:Gem::Version
108
109
  version: '0'
109
110
  requirements: []
110
- rubygems_version: 3.0.3
111
+ rubygems_version: 3.1.2
111
112
  signing_key:
112
113
  specification_version: 4
113
114
  summary: Kobot automates the clock in/out of KING OF TIME.