checkoff 0.36.1 → 0.37.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 +2 -16
- data/checkoff.gemspec +0 -1
- data/lib/checkoff/internal/search_url/parser.rb +6 -0
- data/lib/checkoff/internal/search_url/simple_param_converter.rb +34 -1
- data/lib/checkoff/projects.rb +33 -5
- data/lib/checkoff/task_searches.rb +11 -0
- data/lib/checkoff/version.rb +1 -1
- data/lib/checkoff/workspaces.rb +2 -0
- metadata +2 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78eb26c757cafb9c92eb8e1127e454a3d05a0ed16548483cf0dceeca53c22114
|
|
4
|
+
data.tar.gz: 39a81ddbcb197370af6e7328664ada5a26268cc434363f7291c518e3a7ce1621
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1455835c137f7ed819cd6d5b774d360ee8d72b841a193955ad0b9df665a3f53568c515910b07d8221d6981a9e6f416a089add42025179c0f260cf8cc612740b5
|
|
7
|
+
data.tar.gz: 31619893659ffe14a38183190f4d299c4354f5161ee41be0647eea5f4c45bc4f297d5051311d1e16fc1b300fdbf2ef6eefd88c21256e1ac0541e3b86312b446e
|
data/Gemfile.lock
CHANGED
|
@@ -12,7 +12,7 @@ GIT
|
|
|
12
12
|
PATH
|
|
13
13
|
remote: .
|
|
14
14
|
specs:
|
|
15
|
-
checkoff (0.
|
|
15
|
+
checkoff (0.37.0)
|
|
16
16
|
activesupport
|
|
17
17
|
asana (> 0.10.0)
|
|
18
18
|
cache_method
|
|
@@ -22,7 +22,7 @@ PATH
|
|
|
22
22
|
GEM
|
|
23
23
|
remote: https://rubygems.org/
|
|
24
24
|
specs:
|
|
25
|
-
activesupport (7.0.
|
|
25
|
+
activesupport (7.0.5)
|
|
26
26
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
27
27
|
i18n (>= 1.6, < 2)
|
|
28
28
|
minitest (>= 5.1)
|
|
@@ -145,19 +145,6 @@ GEM
|
|
|
145
145
|
reverse_markdown (2.1.1)
|
|
146
146
|
nokogiri
|
|
147
147
|
rexml (3.2.5)
|
|
148
|
-
rspec (3.11.0)
|
|
149
|
-
rspec-core (~> 3.11.0)
|
|
150
|
-
rspec-expectations (~> 3.11.0)
|
|
151
|
-
rspec-mocks (~> 3.11.0)
|
|
152
|
-
rspec-core (3.11.0)
|
|
153
|
-
rspec-support (~> 3.11.0)
|
|
154
|
-
rspec-expectations (3.11.1)
|
|
155
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
156
|
-
rspec-support (~> 3.11.0)
|
|
157
|
-
rspec-mocks (3.11.1)
|
|
158
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
159
|
-
rspec-support (~> 3.11.0)
|
|
160
|
-
rspec-support (3.11.1)
|
|
161
148
|
rubocop (1.36.0)
|
|
162
149
|
json (~> 2.3)
|
|
163
150
|
parallel (~> 1.10)
|
|
@@ -239,7 +226,6 @@ DEPENDENCIES
|
|
|
239
226
|
punchlist
|
|
240
227
|
rake (~> 13.0)
|
|
241
228
|
rbs (> 3.0.3)
|
|
242
|
-
rspec (>= 3.4)
|
|
243
229
|
rubocop (~> 1.36, < 1.44)
|
|
244
230
|
rubocop-minitest
|
|
245
231
|
rubocop-rake
|
data/checkoff.gemspec
CHANGED
|
@@ -46,7 +46,6 @@ Gem::Specification.new do |spec|
|
|
|
46
46
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
47
47
|
# ensure recent definitions
|
|
48
48
|
spec.add_development_dependency 'rbs', ['>3.0.3']
|
|
49
|
-
spec.add_development_dependency 'rspec', '>=3.4'
|
|
50
49
|
# I haven't adapted things to Gemspec/DevelopmentDependencies yet,
|
|
51
50
|
# which arrives in 1.44
|
|
52
51
|
spec.add_development_dependency 'rubocop', ['~> 1.36', '<1.44']
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
# frozen_string_literal: true
|
|
4
4
|
|
|
5
|
+
require 'cgi'
|
|
6
|
+
require 'uri'
|
|
5
7
|
require_relative 'simple_param_converter'
|
|
6
8
|
require_relative 'custom_field_param_converter'
|
|
7
9
|
|
|
@@ -17,7 +19,9 @@ module Checkoff
|
|
|
17
19
|
|
|
18
20
|
def convert_params(url)
|
|
19
21
|
url_params = CGI.parse(URI.parse(url).query)
|
|
22
|
+
# @sg-ignore
|
|
20
23
|
custom_field_params, simple_url_params = partition_url_params(url_params)
|
|
24
|
+
# @sg-ignore
|
|
21
25
|
custom_field_args, task_selector = convert_custom_field_params(custom_field_params)
|
|
22
26
|
simple_url_args = convert_simple_params(simple_url_params)
|
|
23
27
|
[custom_field_args.merge(simple_url_args), task_selector]
|
|
@@ -33,6 +37,8 @@ module Checkoff
|
|
|
33
37
|
CustomFieldParamConverter.new(custom_field_params: custom_field_params).convert
|
|
34
38
|
end
|
|
35
39
|
|
|
40
|
+
# @param url_params [Hash<String, String>]
|
|
41
|
+
# @return [Array(Hash<String, String>, Hash<String, String>)]
|
|
36
42
|
def partition_url_params(url_params)
|
|
37
43
|
url_params.to_a.partition do |key, _values|
|
|
38
44
|
key.start_with? 'custom_field_'
|
|
@@ -11,6 +11,8 @@ module Checkoff
|
|
|
11
11
|
module SimpleParam
|
|
12
12
|
# base class for handling different types of search url params
|
|
13
13
|
class SimpleParam
|
|
14
|
+
# @param key [String] the name of the search url param
|
|
15
|
+
# @param values [Array<String>] the values of the search url param
|
|
14
16
|
def initialize(key:, values:)
|
|
15
17
|
@key = key
|
|
16
18
|
@values = values
|
|
@@ -18,10 +20,13 @@ module Checkoff
|
|
|
18
20
|
|
|
19
21
|
private
|
|
20
22
|
|
|
23
|
+
# @sg-ignore
|
|
24
|
+
# @return [String] the single value of the search url param
|
|
21
25
|
def single_value
|
|
22
26
|
@single_value ||= begin
|
|
23
27
|
raise "Teach me how to handle #{key} = #{values}" if values.length != 1
|
|
24
28
|
|
|
29
|
+
# @type [String]
|
|
25
30
|
values.fetch(0)
|
|
26
31
|
end
|
|
27
32
|
end
|
|
@@ -34,6 +39,7 @@ module Checkoff
|
|
|
34
39
|
# 123~456 means "abc" and "def" projects
|
|
35
40
|
def parse_projects_and_sections(projects, sections)
|
|
36
41
|
single_value.split('~').each do |project_section_pair|
|
|
42
|
+
# @sg-ignore
|
|
37
43
|
project, section = project_section_pair.split('_column_')
|
|
38
44
|
if section.nil?
|
|
39
45
|
projects << project
|
|
@@ -106,15 +112,32 @@ module Checkoff
|
|
|
106
112
|
['tags.any', tag_ids.join(',')]
|
|
107
113
|
end
|
|
108
114
|
end
|
|
115
|
+
|
|
116
|
+
# Handle 'sort' search url param
|
|
117
|
+
class Sort < SimpleParam
|
|
118
|
+
def convert
|
|
119
|
+
# https://developers.asana.com/reference/searchtasksforworkspace
|
|
120
|
+
conversion = {
|
|
121
|
+
'last_modified' => 'modified_at',
|
|
122
|
+
'due_date' => 'due_date',
|
|
123
|
+
'creation_time' => 'created_at',
|
|
124
|
+
'completion_time' => 'completed_at',
|
|
125
|
+
'likes' => 'likes',
|
|
126
|
+
}
|
|
127
|
+
['sort_by', conversion.fetch(single_value)]
|
|
128
|
+
end
|
|
129
|
+
end
|
|
109
130
|
end
|
|
110
131
|
|
|
111
132
|
# Convert simple parameters - ones where the param name itself
|
|
112
133
|
# doesn't encode any parameters'
|
|
113
134
|
class SimpleParamConverter
|
|
135
|
+
# @param simple_url_params [Hash<String, Array<String>>] the simple params
|
|
114
136
|
def initialize(simple_url_params:)
|
|
115
137
|
@simple_url_params = simple_url_params
|
|
116
138
|
end
|
|
117
139
|
|
|
140
|
+
# @return [Hash<String, String>] the converted params
|
|
118
141
|
def convert
|
|
119
142
|
simple_url_params.to_a.flat_map do |key, values|
|
|
120
143
|
convert_arg(key, values).each_slice(2).to_a
|
|
@@ -123,6 +146,7 @@ module Checkoff
|
|
|
123
146
|
|
|
124
147
|
private
|
|
125
148
|
|
|
149
|
+
# @type [Hash<String, Class<SimpleParam::SimpleParam>>] the mapping from param name to class
|
|
126
150
|
ARGS = {
|
|
127
151
|
'any_projects.ids' => SimpleParam::AnyProjectsIds,
|
|
128
152
|
'not_projects.ids' => SimpleParam::NotProjectsIds,
|
|
@@ -130,12 +154,21 @@ module Checkoff
|
|
|
130
154
|
'not_tags.ids' => SimpleParam::NotTagsIds,
|
|
131
155
|
'any_tags.ids' => SimpleParam::AnyTagsIds,
|
|
132
156
|
'subtask' => SimpleParam::Subtask,
|
|
157
|
+
'sort' => SimpleParam::Sort,
|
|
133
158
|
}.freeze
|
|
134
159
|
|
|
135
160
|
# https://developers.asana.com/docs/search-tasks-in-a-workspace
|
|
161
|
+
# @sg-ignore
|
|
162
|
+
# @param key [String] the name of the search url param
|
|
163
|
+
# @param values [Array<String>] the values of the search url param
|
|
164
|
+
# @return [Hash<String, String>] the converted params
|
|
136
165
|
def convert_arg(key, values)
|
|
166
|
+
# @type [Class<SimpleParam::SimpleParam>]
|
|
137
167
|
clazz = ARGS.fetch(key)
|
|
138
|
-
|
|
168
|
+
# @type [SimpleParam::SimpleParam]
|
|
169
|
+
obj = clazz.new(key: key, values: values)
|
|
170
|
+
# @sg-ignore
|
|
171
|
+
obj.convert
|
|
139
172
|
end
|
|
140
173
|
|
|
141
174
|
attr_reader :simple_url_params
|
data/lib/checkoff/projects.rb
CHANGED
|
@@ -17,12 +17,19 @@ module Checkoff
|
|
|
17
17
|
# Work with projects in Asana
|
|
18
18
|
class Projects
|
|
19
19
|
MINUTE = 60
|
|
20
|
+
# @sg-ignore
|
|
20
21
|
HOUR = MINUTE * 60
|
|
21
22
|
DAY = 24 * HOUR
|
|
23
|
+
# @sg-ignore
|
|
22
24
|
REALLY_LONG_CACHE_TIME = HOUR * 1
|
|
25
|
+
# @sg-ignore
|
|
23
26
|
LONG_CACHE_TIME = MINUTE * 15
|
|
24
27
|
SHORT_CACHE_TIME = MINUTE
|
|
25
28
|
|
|
29
|
+
# @!parse
|
|
30
|
+
# extend CacheMethod::ClassMethods
|
|
31
|
+
|
|
32
|
+
# @param client [Asana::Client]
|
|
26
33
|
def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
|
|
27
34
|
client: Checkoff::Clients.new(config: config).client,
|
|
28
35
|
workspaces: Checkoff::Workspaces.new(config: config,
|
|
@@ -33,7 +40,7 @@ module Checkoff
|
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
# Default options used in Asana API to pull taskso
|
|
36
|
-
# @return [Hash]
|
|
43
|
+
# @return [Hash<Symbol, Object>]
|
|
37
44
|
def task_options
|
|
38
45
|
{
|
|
39
46
|
per_page: 100,
|
|
@@ -45,6 +52,9 @@ module Checkoff
|
|
|
45
52
|
end
|
|
46
53
|
|
|
47
54
|
# pulls an Asana API project class given a name
|
|
55
|
+
# @param [String] workspace_name
|
|
56
|
+
# @param [String] project_name
|
|
57
|
+
# @return [Asana::Resources::Project, nil]
|
|
48
58
|
def project(workspace_name, project_name)
|
|
49
59
|
if project_name.is_a?(Symbol) && project_name.to_s.start_with?('my_tasks')
|
|
50
60
|
my_tasks(workspace_name)
|
|
@@ -57,21 +67,30 @@ module Checkoff
|
|
|
57
67
|
end
|
|
58
68
|
cache_method :project, LONG_CACHE_TIME
|
|
59
69
|
|
|
60
|
-
# @
|
|
70
|
+
# @param workspace_name [String]
|
|
71
|
+
# @param project_name [String]
|
|
72
|
+
# @return [Asana::Resources::Project]
|
|
61
73
|
def project_or_raise(workspace_name, project_name)
|
|
62
|
-
|
|
63
|
-
raise "Could not find project #{project_name} under workspace #{workspace_name}." if
|
|
74
|
+
p = project(workspace_name, project_name)
|
|
75
|
+
raise "Could not find project #{project_name} under workspace #{workspace_name}." if p.nil?
|
|
64
76
|
|
|
65
|
-
|
|
77
|
+
p
|
|
66
78
|
end
|
|
67
79
|
cache_method :project_or_raise, LONG_CACHE_TIME
|
|
68
80
|
|
|
69
81
|
# find uncompleted tasks in a list
|
|
82
|
+
# @param [Array<Asana::Resources::Task>] tasks
|
|
83
|
+
# @return [Array<Asana::Resources::Task>]
|
|
70
84
|
def active_tasks(tasks)
|
|
71
85
|
tasks.select { |task| task.completed_at.nil? }
|
|
72
86
|
end
|
|
73
87
|
|
|
74
88
|
# pull task objects from a named project
|
|
89
|
+
# @sg-ignore
|
|
90
|
+
# @param [Asana::Resources::Project] project
|
|
91
|
+
# @param [Boolean] only_uncompleted
|
|
92
|
+
# @param [Array<String>] extra_fields
|
|
93
|
+
# @return [Array<Asana::Resources::Task>]
|
|
75
94
|
def tasks_from_project(project, only_uncompleted: true, extra_fields: [])
|
|
76
95
|
options = task_options
|
|
77
96
|
options[:completed_since] = '9999-12-01' if only_uncompleted
|
|
@@ -85,11 +104,15 @@ module Checkoff
|
|
|
85
104
|
|
|
86
105
|
attr_reader :client
|
|
87
106
|
|
|
107
|
+
# @sg-ignore
|
|
88
108
|
def projects
|
|
89
109
|
client.projects
|
|
90
110
|
end
|
|
91
111
|
cache_method :projects, LONG_CACHE_TIME
|
|
92
112
|
|
|
113
|
+
# @sg-ignore
|
|
114
|
+
# @param [String] workspace_name
|
|
115
|
+
# @return [Array<Asana::Resources::Project>]
|
|
93
116
|
def projects_by_workspace_name(workspace_name)
|
|
94
117
|
workspace = @workspaces.workspace_or_raise(workspace_name)
|
|
95
118
|
raise "Could not find workspace named #{workspace_name}" unless workspace
|
|
@@ -97,8 +120,13 @@ module Checkoff
|
|
|
97
120
|
projects.find_by_workspace(workspace: workspace.gid)
|
|
98
121
|
end
|
|
99
122
|
|
|
123
|
+
# @sg-ignore
|
|
124
|
+
# @param [String] workspace_name
|
|
125
|
+
# @return [Asana::Resources::Project]
|
|
100
126
|
def my_tasks(workspace_name)
|
|
101
127
|
workspace = @workspaces.workspace_or_raise(workspace_name)
|
|
128
|
+
# @sg-ignore
|
|
129
|
+
# @type [Asana::Resources::UserTaskList]
|
|
102
130
|
result = client.user_task_lists.get_user_task_list_for_user(user_gid: 'me',
|
|
103
131
|
workspace: workspace.gid)
|
|
104
132
|
gid = result.gid
|
|
@@ -19,9 +19,12 @@ module Checkoff
|
|
|
19
19
|
# Run task searches against the Asana API
|
|
20
20
|
class TaskSearches
|
|
21
21
|
MINUTE = 60
|
|
22
|
+
# @sg-ignore
|
|
22
23
|
HOUR = MINUTE * 60
|
|
23
24
|
DAY = 24 * HOUR
|
|
25
|
+
# @sg-ignore
|
|
24
26
|
REALLY_LONG_CACHE_TIME = HOUR * 1
|
|
27
|
+
# @sg-ignore
|
|
25
28
|
LONG_CACHE_TIME = MINUTE * 15
|
|
26
29
|
SHORT_CACHE_TIME = MINUTE
|
|
27
30
|
|
|
@@ -59,11 +62,15 @@ module Checkoff
|
|
|
59
62
|
client: client)
|
|
60
63
|
tasks.select { |task| task_selectors.filter_via_task_selector(task, task_selector) }
|
|
61
64
|
end
|
|
65
|
+
# @sg-ignore
|
|
62
66
|
cache_method :task_search, LONG_CACHE_TIME
|
|
63
67
|
|
|
64
68
|
private
|
|
65
69
|
|
|
70
|
+
# @param [Array<String>] extra_fields
|
|
71
|
+
# @return [Hash<Symbol, Object>]
|
|
66
72
|
def calculate_api_options(extra_fields)
|
|
73
|
+
# @type [Hash<Symbol, Object>]
|
|
67
74
|
options = projects.task_options[:options]
|
|
68
75
|
options[:fields] += ['custom_fields']
|
|
69
76
|
options[:fields] += extra_fields
|
|
@@ -74,7 +81,11 @@ module Checkoff
|
|
|
74
81
|
# :nocov:
|
|
75
82
|
class << self
|
|
76
83
|
def run
|
|
84
|
+
# @sg-ignore
|
|
85
|
+
# @type [String]
|
|
77
86
|
workspace_name = ARGV[0] || raise('Please pass workspace name as first argument')
|
|
87
|
+
# @sg-ignore
|
|
88
|
+
# @type [String]
|
|
78
89
|
url = ARGV[1] || raise('Please pass task search URL as second argument')
|
|
79
90
|
task_searches = Checkoff::TaskSearches.new
|
|
80
91
|
task_search = task_searches.task_search(workspace_name, url)
|
data/lib/checkoff/version.rb
CHANGED
data/lib/checkoff/workspaces.rb
CHANGED
|
@@ -36,6 +36,8 @@ module Checkoff
|
|
|
36
36
|
@asana_workspace.find_by_id(client, default_workspace_gid)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# @param [String] workspace_name
|
|
40
|
+
# @return [Asana::Resources::Workspace]
|
|
39
41
|
def workspace_or_raise(workspace_name)
|
|
40
42
|
workspace = workspace(workspace_name)
|
|
41
43
|
raise "Could not find workspace #{workspace_name}" if workspace.nil?
|
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.37.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: 2023-05-
|
|
11
|
+
date: 2023-05-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -254,20 +254,6 @@ dependencies:
|
|
|
254
254
|
- - ">"
|
|
255
255
|
- !ruby/object:Gem::Version
|
|
256
256
|
version: 3.0.3
|
|
257
|
-
- !ruby/object:Gem::Dependency
|
|
258
|
-
name: rspec
|
|
259
|
-
requirement: !ruby/object:Gem::Requirement
|
|
260
|
-
requirements:
|
|
261
|
-
- - ">="
|
|
262
|
-
- !ruby/object:Gem::Version
|
|
263
|
-
version: '3.4'
|
|
264
|
-
type: :development
|
|
265
|
-
prerelease: false
|
|
266
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
267
|
-
requirements:
|
|
268
|
-
- - ">="
|
|
269
|
-
- !ruby/object:Gem::Version
|
|
270
|
-
version: '3.4'
|
|
271
257
|
- !ruby/object:Gem::Dependency
|
|
272
258
|
name: rubocop
|
|
273
259
|
requirement: !ruby/object:Gem::Requirement
|