checkoff 0.192.0 → 0.194.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/config/definitions.rb +12 -0
- data/lib/checkoff/projects.rb +39 -11
- data/lib/checkoff/sections.rb +4 -6
- data/lib/checkoff/subtasks.rb +53 -7
- data/lib/checkoff/tags.rb +2 -7
- data/lib/checkoff/task_searches.rb +2 -4
- data/lib/checkoff/tasks.rb +5 -3
- data/lib/checkoff/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebec494187b376d4803fa45da76cfdb6ca3b958290ec0308caacb4ac895fa092
|
4
|
+
data.tar.gz: 7d2fd1701ecbae61048495a6eb91587a3cc384f3aa067f01b7b580e9807d02a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ce29418e9649e852ce60b1a3ac8c166e7da1d06bb52d496356bb01022be067b26846b82b631842ae80a8703824ba84731fd585c621df4b982effebdb3b50452
|
7
|
+
data.tar.gz: 29997815ab3aa694eb4d67758fb6cdd8f2e06a2467006b54b13f82c00ad3e385773e8ad69da448e7ef563d2b4c938b6e8719e923ddc95abe06d6f79403151444
|
data/Gemfile.lock
CHANGED
@@ -12,7 +12,7 @@ GIT
|
|
12
12
|
PATH
|
13
13
|
remote: .
|
14
14
|
specs:
|
15
|
-
checkoff (0.
|
15
|
+
checkoff (0.194.0)
|
16
16
|
activesupport
|
17
17
|
asana (> 0.10.0)
|
18
18
|
cache_method
|
@@ -130,11 +130,11 @@ GEM
|
|
130
130
|
multi_xml (0.6.0)
|
131
131
|
multipart-post (2.3.0)
|
132
132
|
mutex_m (0.2.0)
|
133
|
-
nokogiri (1.
|
133
|
+
nokogiri (1.16.2-arm64-darwin)
|
134
134
|
racc (~> 1.4)
|
135
|
-
nokogiri (1.
|
135
|
+
nokogiri (1.16.2-x86_64-darwin)
|
136
136
|
racc (~> 1.4)
|
137
|
-
nokogiri (1.
|
137
|
+
nokogiri (1.16.2-x86_64-linux)
|
138
138
|
racc (~> 1.4)
|
139
139
|
oauth2 (1.4.11)
|
140
140
|
faraday (>= 0.17.3, < 3.0)
|
data/config/definitions.rb
CHANGED
@@ -54,6 +54,8 @@
|
|
54
54
|
# class Task
|
55
55
|
# # @return [String]
|
56
56
|
# def resource_subtype; end
|
57
|
+
# # @return [Boolean,nil]
|
58
|
+
# def is_rendered_as_separator; end
|
57
59
|
# # @return [String,nil]
|
58
60
|
# def due_at; end
|
59
61
|
# # @return [String,nil]
|
@@ -110,6 +112,16 @@
|
|
110
112
|
# def get_custom_fields_for_workspace(workspace_gid: required("workspace_gid"), options: {}); end
|
111
113
|
# end
|
112
114
|
# class Task
|
115
|
+
# # Get subtasks from a task
|
116
|
+
# #
|
117
|
+
# # @param task_gid [String] (required) The task to operate on.
|
118
|
+
# # @param options [Hash] the request I/O options
|
119
|
+
# # > offset - [str] Offset token. An offset to the next page returned by the API. A pagination request will return an offset token, which can be used as an input parameter to the next request. If an offset is not passed in, the API will return the first page of results. 'Note: You can only pass in an offset that was returned to you via a previously paginated request.'
|
120
|
+
# # > limit - [int] Results per page. The number of objects to return per page. The value must be between 1 and 100.
|
121
|
+
# # > opt_fields - [list[str]] Defines fields to return. Some requests return *compact* representations of objects in order to conserve resources and complete the request more efficiently. Other times requests return more information than you may need. This option allows you to list the exact set of fields that the API should be sure to return for the objects. The field names should be provided as paths, described below. The id of included objects will always be returned, regardless of the field options.
|
122
|
+
# # > opt_pretty - [bool] Provides “pretty” output. Provides the response in a “pretty” format. In the case of JSON this means doing proper line breaking and indentation to make it readable. This will take extra time and increase the response size so it is advisable only to use this during debugging.
|
123
|
+
# # @return [Enumerable<Asana::Resources::Task>]
|
124
|
+
# def get_subtasks_for_task(task_gid: required("task_gid"), options: {}); end
|
113
125
|
# # Returns the complete task record for a single task.
|
114
126
|
# #
|
115
127
|
# # @param id [String] The task to get.
|
data/lib/checkoff/projects.rb
CHANGED
@@ -52,17 +52,46 @@ module Checkoff
|
|
52
52
|
@timing = timing
|
53
53
|
end
|
54
54
|
|
55
|
+
# @param extra_fields [Array<String>]
|
56
|
+
#
|
57
|
+
# @return [Array<String>]
|
58
|
+
def task_fields(extra_fields: [])
|
59
|
+
(%w[name completed_at start_at start_on due_at due_on tags
|
60
|
+
memberships.project.gid memberships.project.name
|
61
|
+
memberships.section.name dependencies] + extra_fields).sort.uniq
|
62
|
+
end
|
63
|
+
|
55
64
|
# Default options used in Asana API to pull tasks
|
65
|
+
#
|
66
|
+
# @param extra_fields [Array<String>]
|
67
|
+
# @param [Boolean] only_uncompleted
|
68
|
+
#
|
56
69
|
# @return [Hash<Symbol, Object>]
|
57
|
-
def task_options
|
58
|
-
{
|
70
|
+
def task_options(extra_fields: [], only_uncompleted: false)
|
71
|
+
options = {
|
59
72
|
per_page: 100,
|
60
73
|
options: {
|
61
|
-
fields:
|
62
|
-
memberships.project.gid memberships.project.name
|
63
|
-
memberships.section.name dependencies],
|
74
|
+
fields: task_fields(extra_fields: extra_fields),
|
64
75
|
},
|
65
76
|
}
|
77
|
+
options[:completed_since] = '9999-12-01' if only_uncompleted
|
78
|
+
options
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param extra_project_fields [Array<String>]
|
82
|
+
#
|
83
|
+
# @return [Array<String>]
|
84
|
+
def project_fields(extra_project_fields: [])
|
85
|
+
(%w[name custom_fields] + extra_project_fields).sort.uniq
|
86
|
+
end
|
87
|
+
|
88
|
+
# Default options used in Asana API to pull projects
|
89
|
+
#
|
90
|
+
# @param extra_project_fields [Array<String>]
|
91
|
+
#
|
92
|
+
# @return [Hash<Symbol, Object>]
|
93
|
+
def project_options(extra_project_fields: [])
|
94
|
+
{ fields: project_fields(extra_project_fields: extra_project_fields) }
|
66
95
|
end
|
67
96
|
|
68
97
|
# pulls an Asana API project class given a name
|
@@ -103,7 +132,7 @@ module Checkoff
|
|
103
132
|
#
|
104
133
|
# @return [Asana::Resources::Project,nil]
|
105
134
|
def project_by_gid(gid, extra_fields: [])
|
106
|
-
projects.find_by_id(gid, options:
|
135
|
+
projects.find_by_id(gid, options: project_options(extra_project_fields: extra_fields))
|
107
136
|
rescue Asana::Errors::NotFound => e
|
108
137
|
debug e
|
109
138
|
nil
|
@@ -142,10 +171,8 @@ module Checkoff
|
|
142
171
|
def tasks_from_project_gid(project_gid,
|
143
172
|
only_uncompleted: true,
|
144
173
|
extra_fields: [])
|
145
|
-
options = task_options
|
146
|
-
options[:completed_since] = '9999-12-01' if only_uncompleted
|
174
|
+
options = task_options(extra_fields: extra_fields, only_uncompleted: only_uncompleted)
|
147
175
|
options[:project] = project_gid
|
148
|
-
options[:options][:fields] += extra_fields
|
149
176
|
# Note: 30 minute cache time on a raw Enumerable from SDK gives
|
150
177
|
# 'Your pagination token has expired' errors. So we go ahead
|
151
178
|
# and eagerly evaluate here so we can enjoy the cache.
|
@@ -158,11 +185,12 @@ module Checkoff
|
|
158
185
|
# @return [Enumerable<Asana::Resources::Project>]
|
159
186
|
def projects_by_workspace_name(workspace_name, extra_fields: [])
|
160
187
|
workspace = @workspaces.workspace_or_raise(workspace_name)
|
161
|
-
options = { fields: %w[name] + extra_fields }
|
162
188
|
# 15 minute cache resulted in 'Your pagination token has
|
163
189
|
# expired', so let's cache this a super long time and force
|
164
190
|
# evaluation
|
165
|
-
projects.find_by_workspace(workspace: workspace.gid,
|
191
|
+
projects.find_by_workspace(workspace: workspace.gid,
|
192
|
+
per_page: 100,
|
193
|
+
options: project_options(extra_project_fields: extra_fields)).to_a
|
166
194
|
end
|
167
195
|
cache_method :projects_by_workspace_name, REALLY_LONG_CACHE_TIME
|
168
196
|
|
data/lib/checkoff/sections.rb
CHANGED
@@ -106,9 +106,8 @@ module Checkoff
|
|
106
106
|
def tasks_by_section_gid(section_gid,
|
107
107
|
only_uncompleted: true,
|
108
108
|
extra_fields: [])
|
109
|
-
options = projects.task_options
|
110
|
-
|
111
|
-
options[:completed_since] = '9999-12-01' if only_uncompleted
|
109
|
+
options = projects.task_options(extra_fields: extra_fields,
|
110
|
+
only_uncompleted: only_uncompleted)
|
112
111
|
client.tasks.get_tasks(section: section_gid, **options)
|
113
112
|
end
|
114
113
|
|
@@ -127,9 +126,8 @@ module Checkoff
|
|
127
126
|
only_uncompleted: true,
|
128
127
|
extra_fields: [])
|
129
128
|
section = section_or_raise(workspace_name, project_name, section_name)
|
130
|
-
options = projects.task_options
|
131
|
-
|
132
|
-
options[:completed_since] = '9999-12-01' if only_uncompleted
|
129
|
+
options = projects.task_options(extra_fields: extra_fields,
|
130
|
+
only_uncompleted: only_uncompleted)
|
133
131
|
# Note: 30 minute cache time on a raw Enumerable from SDK gives
|
134
132
|
# 'Your pagination token has expired' errors. So we go ahead
|
135
133
|
# and eagerly evaluate here so we can enjoy the cache.
|
data/lib/checkoff/subtasks.rb
CHANGED
@@ -7,32 +7,45 @@ require_relative 'projects'
|
|
7
7
|
module Checkoff
|
8
8
|
# Query different subtasks of Asana tasks
|
9
9
|
class Subtasks
|
10
|
+
# @!parse
|
11
|
+
# extend CacheMethod::ClassMethods
|
12
|
+
|
10
13
|
MINUTE = 60
|
11
14
|
LONG_CACHE_TIME = MINUTE * 15
|
12
15
|
SHORT_CACHE_TIME = MINUTE * 5
|
13
16
|
|
14
17
|
extend Forwardable
|
15
18
|
|
19
|
+
# @param config [Hash]
|
20
|
+
# @param projects [Checkoff::Projects]
|
21
|
+
# @param clients [Checkoff::Clients]
|
16
22
|
def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
|
17
|
-
projects: Checkoff::Projects.new(config: config)
|
23
|
+
projects: Checkoff::Projects.new(config: config),
|
24
|
+
clients: Checkoff::Clients.new(config: config))
|
18
25
|
@projects = projects
|
26
|
+
@client = clients.client
|
19
27
|
end
|
20
28
|
|
21
29
|
# True if all subtasks of the task are completed
|
30
|
+
#
|
31
|
+
# @param task [Asana::Resources::Task]
|
22
32
|
def all_subtasks_completed?(task)
|
23
|
-
|
24
|
-
active_subtasks = @projects.active_tasks(
|
33
|
+
rs = raw_subtasks(task)
|
34
|
+
active_subtasks = @projects.active_tasks(rs)
|
25
35
|
# anything left should be a section
|
26
36
|
active_subtasks.all? { |subtask| subtask_section?(subtask) }
|
27
37
|
end
|
28
38
|
|
29
39
|
# pulls a Hash of subtasks broken out by section
|
40
|
+
#
|
30
41
|
# @param tasks [Enumerable<Asana::Resources::Task>]
|
42
|
+
#
|
31
43
|
# @return [Hash<[nil,String], Enumerable<Asana::Resources::Task>>]
|
32
44
|
def by_section(tasks)
|
33
45
|
current_section = nil
|
34
46
|
by_section = { nil => [] }
|
35
47
|
tasks.each do |task|
|
48
|
+
# @sg-ignore
|
36
49
|
current_section, by_section = file_task_by_section(current_section,
|
37
50
|
by_section, task)
|
38
51
|
end
|
@@ -40,26 +53,59 @@ module Checkoff
|
|
40
53
|
end
|
41
54
|
|
42
55
|
# Returns all subtasks, including section headers
|
56
|
+
#
|
57
|
+
# @param task [Asana::Resources::Task]
|
58
|
+
#
|
59
|
+
# @return [Enumerable<Asana::Resources::Task>]
|
43
60
|
def raw_subtasks(task)
|
44
|
-
|
45
|
-
task_options[:options][:fields] << 'is_rendered_as_separator'
|
46
|
-
task.subtasks(**task_options)
|
61
|
+
subtasks_by_gid(task.gid)
|
47
62
|
end
|
48
|
-
cache_method :raw_subtasks,
|
63
|
+
cache_method :raw_subtasks, LONG_CACHE_TIME
|
64
|
+
|
65
|
+
# Pull a specific task by GID
|
66
|
+
#
|
67
|
+
# @param task_gid [String]
|
68
|
+
# @param extra_fields [Array<String>]
|
69
|
+
# @param only_uncompleted [Boolean]
|
70
|
+
#
|
71
|
+
# @return [Enumerable<Asana::Resources::Task>]
|
72
|
+
def subtasks_by_gid(task_gid,
|
73
|
+
extra_fields: [],
|
74
|
+
only_uncompleted: true)
|
75
|
+
# @type [Hash]
|
76
|
+
all_options = projects.task_options(extra_fields: extra_fields + %w[is_rendered_as_separator],
|
77
|
+
only_uncompleted: only_uncompleted)
|
78
|
+
options = all_options.fetch(:options, {})
|
79
|
+
client.tasks.get_subtasks_for_task(task_gid: task_gid,
|
80
|
+
# per_page: 100, # stub doesn't have this arg available
|
81
|
+
options: options)
|
82
|
+
end
|
83
|
+
cache_method :subtasks_by_gid, LONG_CACHE_TIME
|
49
84
|
|
50
85
|
# True if the subtask passed in represents a section in the subtasks
|
51
86
|
#
|
52
87
|
# Note: expect this to be removed in a future version, as Asana is
|
53
88
|
# expected to move to the new-style way of representing sections
|
54
89
|
# as memberships with a separate API within a task.
|
90
|
+
#
|
91
|
+
# @param subtask [Asana::Resources::Task]
|
55
92
|
def subtask_section?(subtask)
|
56
93
|
subtask.is_rendered_as_separator
|
57
94
|
end
|
58
95
|
|
59
96
|
private
|
60
97
|
|
98
|
+
# @return [Checkoff::Projects]
|
61
99
|
attr_reader :projects
|
62
100
|
|
101
|
+
# @return [Asana::Client]
|
102
|
+
attr_reader :client
|
103
|
+
|
104
|
+
# @param current_section [String,nil]
|
105
|
+
# @param by_section [Hash]
|
106
|
+
# @param task [Asana::Resources::Task]
|
107
|
+
#
|
108
|
+
# @return [Array<(String, Hash)>]
|
63
109
|
def file_task_by_section(current_section, by_section, task)
|
64
110
|
if subtask_section?(task)
|
65
111
|
current_section = task.name
|
data/lib/checkoff/tags.rb
CHANGED
@@ -36,7 +36,8 @@ module Checkoff
|
|
36
36
|
extra_fields: [])
|
37
37
|
tag = tag_or_raise(workspace_name, tag_name)
|
38
38
|
|
39
|
-
options =
|
39
|
+
options = projects.task_options(extra_fields: extra_fields,
|
40
|
+
only_uncompleted: only_uncompleted)
|
40
41
|
|
41
42
|
params = build_params(options)
|
42
43
|
|
@@ -65,12 +66,6 @@ module Checkoff
|
|
65
66
|
|
66
67
|
attr_reader :workspaces, :projects, :client
|
67
68
|
|
68
|
-
def build_task_options(task_options, extra_fields, only_uncompleted)
|
69
|
-
task_options[:options][:fields] += extra_fields
|
70
|
-
task_options[:completed_since] = '9999-12-01' if only_uncompleted
|
71
|
-
task_options
|
72
|
-
end
|
73
|
-
|
74
69
|
def build_params(options)
|
75
70
|
{ limit: options[:per_page], completed_since: options[:completed_since] }.reject do |_, v|
|
76
71
|
v.nil? || Array(v).empty?
|
@@ -193,10 +193,8 @@ module Checkoff
|
|
193
193
|
# @return [Hash<Symbol, Object>]
|
194
194
|
def calculate_api_options(extra_fields)
|
195
195
|
# @type [Hash<Symbol, Object>]
|
196
|
-
|
197
|
-
|
198
|
-
options[:fields] += extra_fields
|
199
|
-
options
|
196
|
+
all_options = projects.task_options(extra_fields: ['custom_fields'] + extra_fields)
|
197
|
+
all_options[:options]
|
200
198
|
end
|
201
199
|
|
202
200
|
# bundle exec ./task_searches.rb
|
data/lib/checkoff/tasks.rb
CHANGED
@@ -156,10 +156,12 @@ module Checkoff
|
|
156
156
|
def task_by_gid(task_gid,
|
157
157
|
extra_fields: [],
|
158
158
|
only_uncompleted: true)
|
159
|
+
# @type [Hash{Symbol => Object}]
|
160
|
+
all_options = projects.task_options(extra_fields: extra_fields,
|
161
|
+
only_uncompleted: only_uncompleted)
|
159
162
|
# @type [Hash]
|
160
|
-
options =
|
161
|
-
options[:
|
162
|
-
options[:completed_since] = '9999-12-01' if only_uncompleted
|
163
|
+
options = all_options.fetch(:options, {})
|
164
|
+
options[:completed_since] = all_options[:completed_since] unless all_options[:completed_since].nil?
|
163
165
|
client.tasks.find_by_id(task_gid, options: options)
|
164
166
|
rescue Asana::Errors::NotFound => e
|
165
167
|
debug e
|
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.194.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-02-
|
11
|
+
date: 2024-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|