checkoff 0.185.0 → 0.186.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/config/definitions.rb +11 -0
- data/lib/checkoff/events.rb +34 -20
- data/lib/checkoff/internal/asana_event_enrichment.rb +215 -0
- data/lib/checkoff/projects.rb +12 -1
- data/lib/checkoff/sections.rb +13 -1
- data/lib/checkoff/tasks.rb +3 -0
- data/lib/checkoff/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab93a442000f1d706e304c5d574a9266c19dcff4be222107dc943f6c1d3ecd3f
|
4
|
+
data.tar.gz: 373ce95b10e181827c2423bfce1a0a37f43a12b32ebebd79ea5b8e98dcc0787f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4f7267e3254bb4d22593bca64557ec58641b69ff95ceb7890c34a5c87512b27a5dda4fecf7db78ee5088692dbcc8c5380f673459a9df3c1edd744746215d364
|
7
|
+
data.tar.gz: '0680cf901961be8001249375c81ceaa77ed903e0acb2f06ecc3b62093a110d7d4bcc225e706d46b31838a50d08d0f8811f4e636166715f5d48b73e33a940f521'
|
data/Gemfile.lock
CHANGED
data/config/definitions.rb
CHANGED
@@ -50,6 +50,8 @@
|
|
50
50
|
# def due_at; end
|
51
51
|
# # @return [String,nil]
|
52
52
|
# def due_on; end
|
53
|
+
# # @return [String,nil]
|
54
|
+
# def name; end
|
53
55
|
# # @return [Hash<String, String>, nil]
|
54
56
|
# def assignee; end
|
55
57
|
# # @return [String, nil]
|
@@ -61,8 +63,14 @@
|
|
61
63
|
# def create(client, assignee:, workspace:, name:); end
|
62
64
|
# end
|
63
65
|
# end
|
66
|
+
# class Section
|
67
|
+
# # @return [String,nil]
|
68
|
+
# def name; end
|
69
|
+
# end
|
64
70
|
# class Project
|
65
71
|
# # @return [String,nil]
|
72
|
+
# def name; end
|
73
|
+
# # @return [String,nil]
|
66
74
|
# def due_date; end
|
67
75
|
# end
|
68
76
|
# class Portfolio
|
@@ -70,6 +78,9 @@
|
|
70
78
|
# def get_items(options = {}); end
|
71
79
|
# end
|
72
80
|
# end
|
81
|
+
# module Errors
|
82
|
+
# class NotFound < StandardError; end
|
83
|
+
# end
|
73
84
|
# module Resources
|
74
85
|
# class Workspace
|
75
86
|
# # @return [String, nil]
|
data/lib/checkoff/events.rb
CHANGED
@@ -7,6 +7,7 @@ require 'cache_method'
|
|
7
7
|
require_relative 'internal/config_loader'
|
8
8
|
require_relative 'internal/logging'
|
9
9
|
require_relative 'internal/asana_event_filter'
|
10
|
+
require_relative 'internal/asana_event_enrichment'
|
10
11
|
require_relative 'workspaces'
|
11
12
|
require_relative 'clients'
|
12
13
|
|
@@ -34,19 +35,28 @@ module Checkoff
|
|
34
35
|
# @param config [Hash]
|
35
36
|
# @param workspaces [Checkoff::Workspaces]
|
36
37
|
# @param tasks [Checkoff::Tasks]
|
38
|
+
# @param sections [Checkoff::Sections]
|
39
|
+
# @param projects [Checkoff::Projects]
|
37
40
|
# @param clients [Checkoff::Clients]
|
38
41
|
# @param client [Asana::Client]
|
39
42
|
# @param asana_event_filter_class [Class<Checkoff::Internal::AsanaEventFilter>]
|
43
|
+
# @param asana_event_enrichment [Checkoff::Internal::AsanaEventEnrichment]
|
40
44
|
def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
|
41
45
|
workspaces: Checkoff::Workspaces.new(config: config),
|
42
46
|
tasks: Checkoff::Tasks.new(config: config),
|
47
|
+
sections: Checkoff::Sections.new(config: config),
|
48
|
+
projects: Checkoff::Projects.new(config: config),
|
43
49
|
clients: Checkoff::Clients.new(config: config),
|
44
50
|
client: clients.client,
|
45
|
-
asana_event_filter_class: Checkoff::Internal::AsanaEventFilter
|
51
|
+
asana_event_filter_class: Checkoff::Internal::AsanaEventFilter,
|
52
|
+
asana_event_enrichment: Checkoff::Internal::AsanaEventEnrichment.new)
|
46
53
|
@workspaces = workspaces
|
47
54
|
@tasks = tasks
|
55
|
+
@sections = sections
|
56
|
+
@projects = projects
|
48
57
|
@client = client
|
49
58
|
@asana_event_filter_class = asana_event_filter_class
|
59
|
+
@asana_event_enrichment = asana_event_enrichment
|
50
60
|
end
|
51
61
|
|
52
62
|
# @param filters [Array<Hash>, nil] The filters to match against
|
@@ -65,34 +75,35 @@ module Checkoff
|
|
65
75
|
#
|
66
76
|
# @return [Hash]
|
67
77
|
def enrich_event(asana_event)
|
68
|
-
|
69
|
-
asana_event = asana_event.dup
|
70
|
-
enrich_event_resource!(asana_event)
|
71
|
-
asana_event
|
78
|
+
asana_event_enrichment.enrich_event(asana_event)
|
72
79
|
end
|
73
80
|
|
74
|
-
|
81
|
+
# @param filter [Hash<String,[String,Array<String>]>]
|
82
|
+
#
|
83
|
+
# @return [Hash<String,[String,Array<String>]>]
|
84
|
+
def enrich_filter(filter)
|
85
|
+
asana_event_enrichment.enrich_filter(filter)
|
86
|
+
end
|
75
87
|
|
76
|
-
# @param
|
88
|
+
# @param webhook_subscription [Hash] Hash of the request made to
|
89
|
+
# webhook POST endpoint - https://app.asana.com/api/1.0/webhooks
|
90
|
+
# https://developers.asana.com/reference/createwebhook
|
77
91
|
#
|
78
92
|
# @return [void]
|
79
|
-
def
|
80
|
-
|
81
|
-
resource = asana_event['resource']
|
82
|
-
# @type [String]
|
83
|
-
resource_type = resource.fetch('resource_type')
|
84
|
-
# @type [String]
|
85
|
-
gid = resource.fetch('gid')
|
86
|
-
|
87
|
-
if resource_type == 'task'
|
88
|
-
task = tasks.task_by_gid(gid, only_uncompleted: false)
|
89
|
-
resource['checkoff:name'] = task.name if task
|
90
|
-
end
|
91
|
-
nil
|
93
|
+
def enrich_webhook_subscription!(webhook_subscription)
|
94
|
+
asana_event_enrichment.enrich_webhook_subscription!(webhook_subscription)
|
92
95
|
end
|
93
96
|
|
97
|
+
private
|
98
|
+
|
94
99
|
include Logging
|
95
100
|
|
101
|
+
# @return [Checkoff::Projects]
|
102
|
+
attr_reader :projects
|
103
|
+
|
104
|
+
# @return [Checkoff::Sections]
|
105
|
+
attr_reader :sections
|
106
|
+
|
96
107
|
# @return [Checkoff::Tasks]
|
97
108
|
attr_reader :tasks
|
98
109
|
|
@@ -102,6 +113,9 @@ module Checkoff
|
|
102
113
|
# @return [Asana::Client]
|
103
114
|
attr_reader :client
|
104
115
|
|
116
|
+
# @return [Checkoff::Internal::AsanaEventEnrichment]
|
117
|
+
attr_reader :asana_event_enrichment
|
118
|
+
|
105
119
|
# bundle exec ./events.rb
|
106
120
|
# :nocov:
|
107
121
|
class << self
|
@@ -0,0 +1,215 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'cache_method'
|
5
|
+
require 'checkoff/internal/config_loader'
|
6
|
+
require 'checkoff/internal/logging'
|
7
|
+
require 'checkoff/internal/asana_event_enrichment'
|
8
|
+
require 'checkoff/workspaces'
|
9
|
+
require 'checkoff/clients'
|
10
|
+
|
11
|
+
module Checkoff
|
12
|
+
module Internal
|
13
|
+
# Add useful info (like resource task names) into an Asana
|
14
|
+
# event/event filters/webhook subscription for human consumption
|
15
|
+
class AsanaEventEnrichment
|
16
|
+
# @param config [Hash]
|
17
|
+
# @param workspaces [Checkoff::Workspaces]
|
18
|
+
# @param tasks [Checkoff::Tasks]
|
19
|
+
# @param sections [Checkoff::Sections]
|
20
|
+
# @param projects [Checkoff::Projects]
|
21
|
+
# @param clients [Checkoff::Clients]
|
22
|
+
# @param client [Asana::Client]
|
23
|
+
# @param asana_event_enrichment [Checkoff::Internal::AsanaEventEnrichment]
|
24
|
+
def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
|
25
|
+
workspaces: Checkoff::Workspaces.new(config: config),
|
26
|
+
tasks: Checkoff::Tasks.new(config: config),
|
27
|
+
sections: Checkoff::Sections.new(config: config),
|
28
|
+
projects: Checkoff::Projects.new(config: config),
|
29
|
+
clients: Checkoff::Clients.new(config: config),
|
30
|
+
client: clients.client)
|
31
|
+
@workspaces = workspaces
|
32
|
+
@tasks = tasks
|
33
|
+
@sections = sections
|
34
|
+
@projects = projects
|
35
|
+
@client = client
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add useful info (like resource task names) into an event for
|
39
|
+
# human consumption
|
40
|
+
#
|
41
|
+
# @param asana_event [Hash]
|
42
|
+
#
|
43
|
+
# @return [Hash]
|
44
|
+
def enrich_event(asana_event)
|
45
|
+
finer { "Enriching event: #{asana_event}" }
|
46
|
+
asana_event = asana_event.dup
|
47
|
+
enrich_event_resource!(asana_event)
|
48
|
+
enrich_event_parent!(asana_event)
|
49
|
+
asana_event
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param filter [Hash<String,[String,Array<String>]>]
|
53
|
+
#
|
54
|
+
# @return [Hash<String,[String,Array<String>]>]
|
55
|
+
def enrich_filter(filter)
|
56
|
+
filter = filter.dup
|
57
|
+
enrich_filter_section!(filter)
|
58
|
+
enrich_filter_resource!(filter)
|
59
|
+
enrich_filter_parent_gid!(filter)
|
60
|
+
filter
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param webhook_subscription [Hash] Hash of the request made to
|
64
|
+
# webhook POST endpoint - https://app.asana.com/api/1.0/webhooks
|
65
|
+
# https://developers.asana.com/reference/createwebhook
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
def enrich_webhook_subscription!(webhook_subscription)
|
69
|
+
webhook_subscription&.fetch('filters', nil)&.map! do |filter|
|
70
|
+
enrich_filter(filter)
|
71
|
+
end
|
72
|
+
resource = webhook_subscription&.fetch('resource', nil)
|
73
|
+
# @sg-ignore
|
74
|
+
name, resource_type = enrich_gid(resource) if resource
|
75
|
+
webhook_subscription['checkoff:enriched:name'] = name if name
|
76
|
+
webhook_subscription['checkoff:enriched:resource_type'] = resource_type if resource_type
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Attempt to look up a GID in situations where we don't have a
|
82
|
+
# resource type provided, and returns the name of the resource.
|
83
|
+
#
|
84
|
+
# @param gid [String]
|
85
|
+
# @param resource_type [String,nil]
|
86
|
+
#
|
87
|
+
# @return [Array<([String, nil], [String,nil])>]
|
88
|
+
def enrich_gid(gid, resource_type: nil)
|
89
|
+
%w[task section project].each do |resource_type_to_try|
|
90
|
+
next unless [resource_type_to_try, nil].include?(resource_type)
|
91
|
+
|
92
|
+
name = method(:"enrich_#{resource_type_to_try}_gid").call(gid)
|
93
|
+
return [name, resource_type_to_try] if name
|
94
|
+
end
|
95
|
+
[nil, nil]
|
96
|
+
end
|
97
|
+
|
98
|
+
# @param filter [Hash{String => String}]
|
99
|
+
#
|
100
|
+
# @return [String, nil]
|
101
|
+
def enrich_filter_parent_gid!(filter)
|
102
|
+
parent_gid = filter['checkoff:parent.gid']
|
103
|
+
return unless parent_gid
|
104
|
+
|
105
|
+
# @sg-ignore
|
106
|
+
name, resource_type = enrich_gid(parent_gid)
|
107
|
+
filter['checkoff:enriched:parent.name'] = name if name
|
108
|
+
filter['checkoff:enriched:parent.resource_type'] = resource_type if resource_type
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param gid [String]
|
112
|
+
#
|
113
|
+
# @return [String, nil]
|
114
|
+
def enrich_task_gid(gid)
|
115
|
+
task = tasks.task_by_gid(gid, only_uncompleted: false)
|
116
|
+
task&.name
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param section_gid [String]
|
120
|
+
#
|
121
|
+
# @return [String, nil]
|
122
|
+
def enrich_section_gid(section_gid)
|
123
|
+
section = sections.section_by_gid(section_gid)
|
124
|
+
section&.name
|
125
|
+
end
|
126
|
+
|
127
|
+
# @param project_gid [String]
|
128
|
+
#
|
129
|
+
# @return [String, nil]
|
130
|
+
def enrich_project_gid(project_gid)
|
131
|
+
project = projects.project_by_gid(project_gid)
|
132
|
+
project&.name
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param filter [Hash{String => String}]
|
136
|
+
#
|
137
|
+
# @return [void]
|
138
|
+
def enrich_filter_resource!(filter)
|
139
|
+
resource_gid = filter['checkoff:resource.gid']
|
140
|
+
|
141
|
+
return unless resource_gid
|
142
|
+
|
143
|
+
task = tasks.task_by_gid(resource_gid)
|
144
|
+
filter['checkoff:enriched:resource.name'] = task.name if task
|
145
|
+
end
|
146
|
+
|
147
|
+
# @param filter [Hash{String => [String,Array<String>]}]
|
148
|
+
#
|
149
|
+
# @return [void]
|
150
|
+
def enrich_filter_section!(filter)
|
151
|
+
section_gid = filter['checkoff:fetched.section.gid']
|
152
|
+
return unless section_gid
|
153
|
+
|
154
|
+
name = enrich_section_gid(section_gid)
|
155
|
+
filter['checkoff:enriched:fetched.section.name'] = name if name
|
156
|
+
end
|
157
|
+
|
158
|
+
# @param asana_event [Hash{'resource' => Hash}]
|
159
|
+
#
|
160
|
+
# @return [void]
|
161
|
+
def enrich_event_parent!(asana_event)
|
162
|
+
# @type [Hash{String => String }]
|
163
|
+
parent = asana_event['parent']
|
164
|
+
|
165
|
+
return unless parent
|
166
|
+
|
167
|
+
# @type [String]
|
168
|
+
resource_type = parent.fetch('resource_type')
|
169
|
+
# @type [String]
|
170
|
+
gid = parent.fetch('gid')
|
171
|
+
# @sg-ignore
|
172
|
+
name, _resource_type = enrich_gid(gid, resource_type: resource_type)
|
173
|
+
parent['checkoff:enriched:name'] = name if name
|
174
|
+
|
175
|
+
nil
|
176
|
+
end
|
177
|
+
|
178
|
+
# @param asana_event [Hash{'resource' => Hash}]
|
179
|
+
#
|
180
|
+
# @return [void]
|
181
|
+
def enrich_event_resource!(asana_event)
|
182
|
+
# @type [Hash{String => String }]
|
183
|
+
resource = asana_event['resource']
|
184
|
+
# @type [String]
|
185
|
+
resource_type = resource.fetch('resource_type')
|
186
|
+
|
187
|
+
# @type [String]
|
188
|
+
gid = resource.fetch('gid')
|
189
|
+
|
190
|
+
# @sg-ignore
|
191
|
+
name, _resource_type = enrich_gid(gid, resource_type: resource_type)
|
192
|
+
resource['checkoff:enriched:name'] = name if name
|
193
|
+
|
194
|
+
nil
|
195
|
+
end
|
196
|
+
|
197
|
+
include Logging
|
198
|
+
|
199
|
+
# @return [Checkoff::Projects]
|
200
|
+
attr_reader :projects
|
201
|
+
|
202
|
+
# @return [Checkoff::Sections]
|
203
|
+
attr_reader :sections
|
204
|
+
|
205
|
+
# @return [Checkoff::Tasks]
|
206
|
+
attr_reader :tasks
|
207
|
+
|
208
|
+
# @return [Checkoff::Workspaces]
|
209
|
+
attr_reader :workspaces
|
210
|
+
|
211
|
+
# @return [Asana::Client]
|
212
|
+
attr_reader :client
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
data/lib/checkoff/projects.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative 'internal/config_loader'
|
4
4
|
require_relative 'internal/project_hashes'
|
5
5
|
require_relative 'internal/project_timing'
|
6
|
+
require_relative 'internal/logging'
|
6
7
|
require_relative 'workspaces'
|
7
8
|
require_relative 'clients'
|
8
9
|
require_relative 'timing'
|
@@ -99,9 +100,12 @@ module Checkoff
|
|
99
100
|
# @param gid [String]
|
100
101
|
# @param [Array<String>] extra_fields
|
101
102
|
#
|
102
|
-
# @return [Asana::Resources::Project]
|
103
|
+
# @return [Asana::Resources::Project,nil]
|
103
104
|
def project_by_gid(gid, extra_fields: [])
|
104
105
|
projects.find_by_id(gid, options: { fields: %w[name] + extra_fields })
|
106
|
+
rescue Asana::Errors::NotFound => e
|
107
|
+
debug e
|
108
|
+
nil
|
105
109
|
end
|
106
110
|
cache_method :project_by_gid, REALLY_LONG_CACHE_TIME
|
107
111
|
|
@@ -192,8 +196,15 @@ module Checkoff
|
|
192
196
|
timing.in_period?(project_date, period)
|
193
197
|
end
|
194
198
|
|
199
|
+
# @return [Hash]
|
200
|
+
def as_cache_key
|
201
|
+
{}
|
202
|
+
end
|
203
|
+
|
195
204
|
private
|
196
205
|
|
206
|
+
include Logging
|
207
|
+
|
197
208
|
# @return [Checkoff::Timing]
|
198
209
|
attr_reader :timing
|
199
210
|
|
data/lib/checkoff/sections.rb
CHANGED
@@ -5,6 +5,7 @@ require_relative 'projects'
|
|
5
5
|
require_relative 'workspaces'
|
6
6
|
require_relative 'clients'
|
7
7
|
require_relative 'my_tasks'
|
8
|
+
require_relative 'internal/logging'
|
8
9
|
|
9
10
|
module Checkoff
|
10
11
|
# Query different sections of Asana projects
|
@@ -197,15 +198,26 @@ module Checkoff
|
|
197
198
|
|
198
199
|
# @param gid [String]
|
199
200
|
#
|
200
|
-
# @return [Asana::Resources::Section]
|
201
|
+
# @return [Asana::Resources::Section, nil]
|
201
202
|
def section_by_gid(gid)
|
202
203
|
options = {}
|
203
204
|
Asana::Resources::Section.new(parse(client.get("/sections/#{gid}", options: options)).first,
|
204
205
|
client: client)
|
206
|
+
rescue Asana::Errors::NotFound => e
|
207
|
+
debug e
|
208
|
+
nil
|
209
|
+
end
|
210
|
+
cache_method :section_by_gid, SHORT_CACHE_TIME
|
211
|
+
|
212
|
+
# @return [Hash]
|
213
|
+
def as_cache_key
|
214
|
+
{}
|
205
215
|
end
|
206
216
|
|
207
217
|
private
|
208
218
|
|
219
|
+
include Logging
|
220
|
+
|
209
221
|
# https://github.com/Asana/ruby-asana/blob/master/lib/asana/resource_includes/response_helper.rb#L7
|
210
222
|
# @param response [Faraday::Response]
|
211
223
|
#
|
data/lib/checkoff/tasks.rb
CHANGED
@@ -161,6 +161,9 @@ module Checkoff
|
|
161
161
|
options[:fields] += extra_fields
|
162
162
|
options[:completed_since] = '9999-12-01' if only_uncompleted
|
163
163
|
client.tasks.find_by_id(task_gid, options: options)
|
164
|
+
rescue Asana::Errors::NotFound => e
|
165
|
+
debug e
|
166
|
+
nil
|
164
167
|
end
|
165
168
|
cache_method :task_by_gid, SHORT_CACHE_TIME
|
166
169
|
|
data/lib/checkoff/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: checkoff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.186.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vince Broz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -149,6 +149,7 @@ files:
|
|
149
149
|
- lib/checkoff/create-entity.sh
|
150
150
|
- lib/checkoff/custom_fields.rb
|
151
151
|
- lib/checkoff/events.rb
|
152
|
+
- lib/checkoff/internal/asana_event_enrichment.rb
|
152
153
|
- lib/checkoff/internal/asana_event_filter.rb
|
153
154
|
- lib/checkoff/internal/config_loader.rb
|
154
155
|
- lib/checkoff/internal/create-class.sh
|