checkoff 0.45.1 → 0.46.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/lib/checkoff/internal/search_url/custom_field_param_converter.rb +25 -16
- data/lib/checkoff/internal/search_url/date_param_converter.rb +61 -0
- data/lib/checkoff/internal/search_url/parser.rb +41 -7
- data/lib/checkoff/internal/search_url/results_merger.rb +40 -0
- data/lib/checkoff/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a65e8d9c8d8e3012cbe1821983bc48e5151f6c666a454ce627c0084edaac8b46
|
4
|
+
data.tar.gz: 35f49e9a77c9409278b3f68a6c84f6afefc68727510b13ac322a1988360163af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70162bcc35ac9bb35d3006e7334a0abd36c5b9853b148e3f9ae720761691bb00af8de7f065969f144c01cc5563f78c6a53e90c92f7811ab5bf269eabb30986bc
|
7
|
+
data.tar.gz: 3b49077f074571a0b09c7a167601ed7bc99f59707505ef10deb187215dcc059cbd1ea04cff64669ae5e7bbf2007a5d0054aeb62658129ff15e93f3a5baf87534
|
data/Gemfile.lock
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'custom_field_variant'
|
4
|
+
require_relative 'results_merger'
|
4
5
|
|
5
6
|
module Checkoff
|
6
7
|
module Internal
|
@@ -8,44 +9,41 @@ module Checkoff
|
|
8
9
|
# Convert custom field parameters from an Asana search URL into
|
9
10
|
# API search arguments and Checkoff task selectors
|
10
11
|
class CustomFieldParamConverter
|
12
|
+
# @param custom_field_params [Hash<String, Array<String>>]
|
11
13
|
def initialize(custom_field_params:)
|
12
14
|
@custom_field_params = custom_field_params
|
13
15
|
end
|
14
16
|
|
17
|
+
# @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
|
15
18
|
def convert
|
19
|
+
# @type args [Hash<String, String>]
|
16
20
|
args = {}
|
21
|
+
# @type task_selector [Array<[Symbol, Array]>]
|
17
22
|
task_selector = []
|
18
23
|
by_custom_field.each do |gid, single_custom_field_params|
|
24
|
+
# @sg-ignore
|
19
25
|
new_args, new_task_selector = convert_single_custom_field_params(gid,
|
20
26
|
single_custom_field_params)
|
21
|
-
|
22
|
-
|
27
|
+
|
28
|
+
args = ResultsMerger.merge_args(args, new_args)
|
29
|
+
|
30
|
+
# @sg-ignore
|
31
|
+
task_selector = ResultsMerger.merge_task_selectors(task_selector, new_task_selector)
|
23
32
|
end
|
24
33
|
[args, task_selector]
|
25
34
|
end
|
26
35
|
|
27
36
|
private
|
28
37
|
|
38
|
+
# @sg-ignore
|
39
|
+
# @return [Hash<String, Hash>]
|
29
40
|
def by_custom_field
|
30
41
|
custom_field_params.group_by do |key, _value|
|
31
42
|
gid_from_custom_field_key(key)
|
32
43
|
end.transform_values(&:to_h)
|
33
44
|
end
|
34
45
|
|
35
|
-
|
36
|
-
final_args = args.merge(new_args)
|
37
|
-
|
38
|
-
final_task_selector = if new_task_selector == []
|
39
|
-
task_selector
|
40
|
-
elsif task_selector == []
|
41
|
-
new_task_selector
|
42
|
-
else
|
43
|
-
[:and, task_selector, new_task_selector]
|
44
|
-
end
|
45
|
-
|
46
|
-
[final_args, final_task_selector]
|
47
|
-
end
|
48
|
-
|
46
|
+
# @type [Hash<String, Class<CustomFieldVariant>]
|
49
47
|
VARIANTS = {
|
50
48
|
'is' => CustomFieldVariant::Is,
|
51
49
|
'no_value' => CustomFieldVariant::NoValue,
|
@@ -58,22 +56,33 @@ module Checkoff
|
|
58
56
|
'contains_all' => CustomFieldVariant::ContainsAll,
|
59
57
|
}.freeze
|
60
58
|
|
59
|
+
# @param gid [String]
|
60
|
+
# @param single_custom_field_params [Hash<String, Array<String>>]
|
61
|
+
# @sg-ignore
|
62
|
+
# @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
|
61
63
|
def convert_single_custom_field_params(gid, single_custom_field_params)
|
62
64
|
variant_key = "custom_field_#{gid}.variant"
|
63
65
|
variant = single_custom_field_params.fetch(variant_key)
|
64
66
|
remaining_params = single_custom_field_params.reject { |k, _v| k == variant_key }
|
65
67
|
raise "Teach me how to handle #{variant_key} = #{variant}" unless variant.length == 1
|
66
68
|
|
69
|
+
# @sg-ignore
|
70
|
+
# @type variant_class [Class<CustomFieldVariant>]
|
67
71
|
variant_class = VARIANTS[variant[0]]
|
72
|
+
# @type [Array(Hash<String, String>, Array<[Symbol, Array]>)]
|
73
|
+
# @sg-ignore
|
68
74
|
return variant_class.new(gid, remaining_params).convert unless variant_class.nil?
|
69
75
|
|
70
76
|
raise "Teach me how to handle #{variant_key} = #{variant}"
|
71
77
|
end
|
72
78
|
|
79
|
+
# @param key [String]
|
80
|
+
# @return [String]
|
73
81
|
def gid_from_custom_field_key(key)
|
74
82
|
key.split('_')[2].split('.')[0]
|
75
83
|
end
|
76
84
|
|
85
|
+
# @return [Hash<String, Array<String>>]
|
77
86
|
attr_reader :custom_field_params
|
78
87
|
end
|
79
88
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'custom_field_param_converter'
|
4
|
+
|
5
|
+
module Checkoff
|
6
|
+
module Internal
|
7
|
+
module SearchUrl
|
8
|
+
# Convert date parameters - ones where the param name itself
|
9
|
+
# doesn't encode any parameters'
|
10
|
+
class DateParamConverter
|
11
|
+
# @param date_url_params [Hash<String, Array<String>>] the simple params
|
12
|
+
def initialize(date_url_params:)
|
13
|
+
@date_url_params = date_url_params
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array(Hash<String, String>, Array<[Symbol, Array]>)] See https://developers.asana.com/docs/search-tasks-in-a-workspace
|
17
|
+
def convert
|
18
|
+
return [{}, []] if date_url_params.empty?
|
19
|
+
|
20
|
+
# example params:
|
21
|
+
# due_date.operator=through_next
|
22
|
+
# due_date.value=0
|
23
|
+
# due_date.unit=day
|
24
|
+
validate_due_date_through_next!
|
25
|
+
|
26
|
+
value = date_url_params.fetch('due_date.value').fetch(0).to_i
|
27
|
+
|
28
|
+
# @sg-ignore
|
29
|
+
# @type [Date]
|
30
|
+
before = Date.today + value
|
31
|
+
|
32
|
+
validate_unit_is_day!
|
33
|
+
|
34
|
+
# 'due_on.before' => '2023-01-01',
|
35
|
+
# 'due_on.after' => '2023-01-01',
|
36
|
+
# [{ 'due_on.before' => '2023-09-01' }, []]
|
37
|
+
[{ 'due_on.before' => before.to_s }, []]
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @return [void]
|
43
|
+
def validate_unit_is_day!
|
44
|
+
unit = date_url_params.fetch('due_date.unit').fetch(0)
|
45
|
+
|
46
|
+
raise 'Teach me how to handle other time units' unless unit == 'day'
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [void]
|
50
|
+
def validate_due_date_through_next!
|
51
|
+
return if date_url_params.fetch('due_date.operator') == ['through_next']
|
52
|
+
|
53
|
+
raise 'Teach me how to handle other date modes'
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [Hash<String, Array<String>>]
|
57
|
+
attr_reader :date_url_params
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -6,6 +6,8 @@ require 'cgi'
|
|
6
6
|
require 'uri'
|
7
7
|
require_relative 'simple_param_converter'
|
8
8
|
require_relative 'custom_field_param_converter'
|
9
|
+
require_relative 'results_merger'
|
10
|
+
require_relative 'date_param_converter'
|
9
11
|
|
10
12
|
module Checkoff
|
11
13
|
module Internal
|
@@ -13,36 +15,68 @@ module Checkoff
|
|
13
15
|
# Parse Asana search URLs into parameters suitable to pass into
|
14
16
|
# the /workspaces/{workspace_gid}/tasks/search endpoint
|
15
17
|
class Parser
|
18
|
+
# @param _deps [Hash]
|
16
19
|
def initialize(_deps = {})
|
17
20
|
# allow dependencies to be passed in by tests
|
18
21
|
end
|
19
22
|
|
23
|
+
# @param url [String]
|
24
|
+
# @return [Array(Hash<String, String>, Hash<String, String>)]
|
20
25
|
def convert_params(url)
|
21
26
|
url_params = CGI.parse(URI.parse(url).query)
|
27
|
+
# @type custom_field_params [Hash<String, Array<String>>]
|
28
|
+
# @type date_url_params [Hash<String, Array<String>>]
|
29
|
+
# @type simple_url_params [Hash<String, Array<String>>]
|
30
|
+
# @sg-ignore
|
31
|
+
custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
|
32
|
+
# @type custom_field_args [Hash<String, String>]
|
33
|
+
# @type custom_field_task_selector [Hash<String, String>]
|
22
34
|
# @sg-ignore
|
23
|
-
|
35
|
+
custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
|
36
|
+
# @type date_args [Hash<String, String>]
|
37
|
+
# @type date_task_selector [Hash<String, String>]
|
24
38
|
# @sg-ignore
|
25
|
-
|
39
|
+
date_url_args, date_task_selector = convert_date_params(date_url_params)
|
26
40
|
simple_url_args = convert_simple_params(simple_url_params)
|
27
|
-
|
41
|
+
# raise 'merge these things'
|
42
|
+
[ResultsMerger.merge_args(custom_field_args, date_url_args, simple_url_args),
|
43
|
+
ResultsMerger.merge_task_selectors(date_task_selector, custom_field_task_selector)]
|
28
44
|
end
|
29
45
|
|
30
46
|
private
|
31
47
|
|
48
|
+
# @param date_url_params [Hash<String, Array<String>>]
|
49
|
+
# @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
|
50
|
+
def convert_date_params(date_url_params)
|
51
|
+
DateParamConverter.new(date_url_params: date_url_params).convert
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param simple_url_params [Hash<String, Array<String>>]
|
55
|
+
# @return [Hash<String, String>]
|
32
56
|
def convert_simple_params(simple_url_params)
|
33
57
|
SimpleParamConverter.new(simple_url_params: simple_url_params).convert
|
34
58
|
end
|
35
59
|
|
60
|
+
# @param custom_field_params [Hash<String, Array<String>>]
|
61
|
+
# @return [Array(Hash<String, String>, Array<[Symbol, Array]>)]
|
36
62
|
def convert_custom_field_params(custom_field_params)
|
37
63
|
CustomFieldParamConverter.new(custom_field_params: custom_field_params).convert
|
38
64
|
end
|
39
65
|
|
40
66
|
# @param url_params [Hash<String, String>]
|
41
|
-
# @return [Array(Hash<String, String>, Hash<String, String>)]
|
67
|
+
# @return [Array(Hash<String, String>, Hash<String, String>, Hash<String, String>)]
|
42
68
|
def partition_url_params(url_params)
|
43
|
-
url_params.to_a.
|
44
|
-
key.start_with? 'custom_field_'
|
45
|
-
|
69
|
+
groups = url_params.to_a.group_by do |key, _values|
|
70
|
+
if key.start_with? 'custom_field_'
|
71
|
+
:custom_field
|
72
|
+
elsif key.include? '_date'
|
73
|
+
:date
|
74
|
+
else
|
75
|
+
:simple
|
76
|
+
end
|
77
|
+
end.transform_values(&:to_h)
|
78
|
+
# @sg-ignore
|
79
|
+
[groups.fetch(:custom_field, {}), groups.fetch(:date, {}), groups.fetch(:simple, {})]
|
46
80
|
end
|
47
81
|
end
|
48
82
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Checkoff
|
4
|
+
module Internal
|
5
|
+
module SearchUrl
|
6
|
+
# Merge task selectors and search API arguments
|
7
|
+
class ResultsMerger
|
8
|
+
# @param args [Array<[Hash<String, String>]>]
|
9
|
+
# @return [Hash<String, String>
|
10
|
+
def self.merge_args(*args)
|
11
|
+
# first element of args
|
12
|
+
# @sg-ignore
|
13
|
+
# @type [Hash<String, String>]
|
14
|
+
f = args.fetch(0)
|
15
|
+
# rest of args
|
16
|
+
r = args.drop(0)
|
17
|
+
f.merge(*r)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param task_selectors [Array<Array<[Symbol, Array]>>]
|
21
|
+
# @return [Array<[Symbol, Array]>]
|
22
|
+
def self.merge_task_selectors(*task_selectors)
|
23
|
+
return [] if task_selectors.empty?
|
24
|
+
|
25
|
+
first_task_selector = task_selectors.fetch(0)
|
26
|
+
|
27
|
+
return merge_task_selectors(*task_selectors.drop(1)) if first_task_selector.empty?
|
28
|
+
|
29
|
+
return first_task_selector if task_selectors.length == 1
|
30
|
+
|
31
|
+
rest_task_selectors = merge_task_selectors(*task_selectors.drop(1))
|
32
|
+
|
33
|
+
return first_task_selector if rest_task_selectors.empty?
|
34
|
+
|
35
|
+
[:and, first_task_selector, rest_task_selectors]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
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.46.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-
|
11
|
+
date: 2023-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -135,7 +135,9 @@ files:
|
|
135
135
|
- lib/checkoff/internal/search_url.rb
|
136
136
|
- lib/checkoff/internal/search_url/custom_field_param_converter.rb
|
137
137
|
- lib/checkoff/internal/search_url/custom_field_variant.rb
|
138
|
+
- lib/checkoff/internal/search_url/date_param_converter.rb
|
138
139
|
- lib/checkoff/internal/search_url/parser.rb
|
140
|
+
- lib/checkoff/internal/search_url/results_merger.rb
|
139
141
|
- lib/checkoff/internal/search_url/simple_param_converter.rb
|
140
142
|
- lib/checkoff/internal/task_selector_evaluator.rb
|
141
143
|
- lib/checkoff/my_tasks.rb
|