Module: TogglCache
- Defined in:
- lib/toggl_cache.rb,
lib/toggl_cache/data.rb,
lib/toggl_cache/version.rb,
lib/toggl_cache/data/report_repository.rb
Overview
Facility to store/cache Toggl reports data in a PostgreSQL database.
Defined Under Namespace
Modules: Data
Constant Summary collapse
- HOUR =
3_600
- DAY =
24 * HOUR
- WEEK =
7 * DAY
- DEFAULT_DATE_SINCE =
Time.now - 1 * WEEK
- DEFAULT_WORKSPACE_ID =
ENV["TOGGL_WORKSPACE_ID"]
- VERSION =
File.read(File.('../../../VERSION', __FILE__)).strip
Class Method Summary collapse
-
.cache_total(year:, month: nil) ⇒ Object
Returns the total duration in TogglCache reports for the specified year or month.
-
.clear_cache(time_since:, time_until:, logger: default_logger) ⇒ Object
Remove TogglCache’s reports between the specified dates.
-
.clear_cache_for_month(year:, month:, logger: default_logger) ⇒ Object
Remove TogglCache’s reports for the specified month.
- .default_client(logger: default_logger) ⇒ Object
- .default_date_since ⇒ Object
- .default_log_level ⇒ Object
- .default_logger ⇒ Object
- .default_workspace_id ⇒ Object
-
.fetch_reports(client: default_client, workspace_id: default_workspace_id, date_since:, date_until: Time.now, &block) ⇒ Object
Fetch from Toggl.
- .process_reports(reports, logger: default_logger) ⇒ Object
-
.sync_check_and_fix(logger: default_logger) ⇒ Object
Performs a full synchronization check, from the time of the first report in the cache to now.
-
.sync_reports(date_since: default_date_since, date_until: Time.now, logger: default_logger, client: default_client) ⇒ Object
Fetches new and updated reports from the specified start date to now.
-
.sync_reports_for_month(year:, month:, logger: default_logger) ⇒ Object
An easy-to-use method to sync reports for a given month.
-
.toggl_total(year:, month: nil) ⇒ Object
Returns the total duration from Toggl (using Reports API) for the specified year or month.
Class Method Details
.cache_total(year:, month: nil) ⇒ Object
Returns the total duration in TogglCache reports for the specified year or month.
141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/toggl_cache.rb', line 141 def self.cache_total(year:, month: nil) reports = TogglCache::Data::ReportRepository.new date_since = month ? Date.civil(year, month, 1).to_s : Date.civil(year, 1, 1) date_until = month ? Date.civil(year, month, -1).to_s : Date.civil(year, 12, -1) time_since = Time.parse("#{date_since} 00:00:00Z") time_until = Time.parse("#{date_until} 23:59:59Z") reports.starting( time_since: time_since, time_until: time_until ).inject(0) { |sum, r| sum + r[:duration] } / 3600 end |
.clear_cache(time_since:, time_until:, logger: default_logger) ⇒ Object
Remove TogglCache’s reports between the specified dates.
105 106 107 108 109 110 111 112 |
# File 'lib/toggl_cache.rb', line 105 def self.clear_cache(time_since:, time_until:, logger: default_logger) logger.info "Clearing cache from #{time_since} to #{time_until}." reports = Data::ReportRepository.new reports.delete_starting( time_since: time_since, time_until: time_until ) end |
.clear_cache_for_month(year:, month:, logger: default_logger) ⇒ Object
Remove TogglCache’s reports for the specified month.
115 116 117 118 119 120 121 122 123 |
# File 'lib/toggl_cache.rb', line 115 def self.clear_cache_for_month(year:, month:, logger: default_logger) date_since = Date.civil(year, month, 1) date_until = Date.civil(year, month, -1) clear_cache( time_since: Time.parse("#{date_since} 00:00:00Z"), time_until: Time.parse("#{date_until} 23:59:59Z"), logger: logger ) end |
.default_client(logger: default_logger) ⇒ Object
201 202 203 204 |
# File 'lib/toggl_cache.rb', line 201 def self.default_client(logger: default_logger) return TogglAPI::ReportsClient.new(logger: logger) if logger TogglAPI::ReportsClient.new end |
.default_date_since ⇒ Object
210 211 212 |
# File 'lib/toggl_cache.rb', line 210 def self.default_date_since DEFAULT_DATE_SINCE end |
.default_log_level ⇒ Object
220 221 222 |
# File 'lib/toggl_cache.rb', line 220 def self.default_log_level Logger.const_get(ENV["TOGGL_CACHE_LOG_LEVEL"]&.upcase || "ERROR") end |
.default_logger ⇒ Object
214 215 216 217 218 |
# File 'lib/toggl_cache.rb', line 214 def self.default_logger logger = ::Logger.new(STDOUT) logger.level = default_log_level logger end |
.default_workspace_id ⇒ Object
206 207 208 |
# File 'lib/toggl_cache.rb', line 206 def self.default_workspace_id DEFAULT_WORKSPACE_ID end |
.fetch_reports(client: default_client, workspace_id: default_workspace_id, date_since:, date_until: Time.now, &block) ⇒ Object
Fetch from Toggl
Handles a fetch over multiple years, which requires splitting the requests over periods extending on a single year (Toggl API requirement). # @param client [TogglCache::Client] configured client
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/toggl_cache.rb', line 163 def self.fetch_reports( client: default_client, workspace_id: default_workspace_id, date_since:, date_until: Time.now, &block ) raise "You must give a block to process fetched records" unless block_given? if date_since && date_until.year > date_since.year [ [date_since, Date.new(date_since.year, 12, 31)], [Date.new(date_since.year + 1, 1, 1), date_until] ].each do |dates| fetch_reports( client: client, workspace_id: workspace_id, date_since: dates.first, date_until: dates.last, &block ) end else = { workspace_id: workspace_id, until: date_until.strftime("%Y-%m-%d") } [:since] = date_since.strftime("%Y-%m-%d") unless date_since.nil? client.fetch_reports(, &block) end end |
.process_reports(reports, logger: default_logger) ⇒ Object
193 194 195 196 197 198 199 |
# File 'lib/toggl_cache.rb', line 193 def self.process_reports(reports, logger: default_logger) logger.debug "Processing #{reports.count} Toggl reports" repository = Data::ReportRepository.new reports.each do |report| repository.create_or_update(report) end end |
.sync_check_and_fix(logger: default_logger) ⇒ Object
Performs a full synchronization check, from the time of the first report in the cache to now. Proceeds by comparing reports total duration from Toggl (using the Reports API) and the total contained in the cache. If a difference is detected, proceeds monthly and clear and reconstructs the cache for the concerned month.
TODO: enable detecting a change in project/task level aggregates.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/toggl_cache.rb', line 55 def self.sync_check_and_fix(logger: default_logger) reports = TogglCache::Data::ReportRepository.new first_report = reports.first year_start = first_report[:start].year year_end = Time.now.year month_start = first_report[:start].month month_end = Time.now.month (year_start..year_end).each do |year| year_toggl = TogglCache.toggl_total(year: year) year_cache = TogglCache.cache_total(year: year) if year_toggl == year_cache logger.info "Checked total for #{year}: ✅ (#{year_toggl})" next end logger.info "Checked total for #{year}: ❌ (Toggl: #{year_toggl}, cache: #{year_cache})" (1..12).each do |month| next if year == year_start && month < month_start next if year == year_end && month > month_end month_toggl = TogglCache.toggl_total(year: year, month: month) month_cache = TogglCache.cache_total(year: year, month: month) if month_toggl == month_cache logger.info "Checked total for #{year}/#{month}: ✅ (#{month_toggl})" else logger.info "Checked total for #{year}/#{month}: ❌ (Toggl: #{month_toggl}, cache: #{month_cache})" TogglCache.clear_cache_for_month(year: year, month: month, logger: logger) TogglCache.sync_reports_for_month(year: year, month: month, logger: logger) end end end end |
.sync_reports(date_since: default_date_since, date_until: Time.now, logger: default_logger, client: default_client) ⇒ Object
Fetches new and updated reports from the specified start date to now. By default, fetches all reports since 1 month ago, allowing updates on old reports to update the cached reports too.
The fetched reports either update the already existing ones, or create new ones.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/toggl_cache.rb', line 27 def self.sync_reports( date_since: default_date_since, date_until: Time.now, logger: default_logger, client: default_client ) logger.info "Syncing reports from #{date_since} to #{date_until}." clear_cache( time_since: Time.parse("#{date_since} 00:00:00Z"), time_until: Time.parse("#{date_until} 23:59:59Z"), logger: logger ) fetch_reports( client: client, date_since: date_since, date_until: date_until ) do |reports| process_reports(reports) end end |
.sync_reports_for_month(year:, month:, logger: default_logger) ⇒ Object
An easy-to-use method to sync reports for a given month. Simply performs a call to ‘sync_reports`.
94 95 96 97 98 99 100 101 102 |
# File 'lib/toggl_cache.rb', line 94 def self.sync_reports_for_month(year:, month:, logger: default_logger) date_since = Date.civil(year, month, 1) date_until = Date.civil(year, month, -1) sync_reports( date_since: date_since, date_until: date_until, logger: logger ) end |
.toggl_total(year:, month: nil) ⇒ Object
Returns the total duration from Toggl (using Reports API) for the specified year or month.
127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/toggl_cache.rb', line 127 def self.toggl_total(year:, month: nil) reports_client = TogglAPI::ReportsClient.new date_since = month ? Date.civil(year, month, 1) : Date.civil(year, 1, 1) date_until = month ? Date.civil(year, month, -1) : Date.civil(year, 12, -1) total_grand = reports_client.fetch_reports_summary_raw( since: date_since.to_s, until: date_until.to_s, workspace_id: ENV["TOGGL_WORKSPACE_ID"] )["total_grand"] total_grand ? total_grand / 3600 / 1000 : 0 end |