timetree 0.2.0 → 1.0.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/{.rubocom.yml → .rubocop.yml} +12 -9
- data/CHANGELOG.md +36 -10
- data/README.md +49 -18
- data/Rakefile +8 -6
- data/lib/timetree.rb +12 -7
- data/lib/timetree/api_error.rb +1 -1
- data/lib/timetree/base_client.rb +52 -0
- data/lib/timetree/calendar_app/access_token.rb +25 -0
- data/lib/timetree/calendar_app/client.rb +228 -0
- data/lib/timetree/configuration.rb +11 -5
- data/lib/timetree/http_command.rb +12 -14
- data/lib/timetree/models/activity.rb +14 -2
- data/lib/timetree/models/application.rb +15 -0
- data/lib/timetree/models/base_model.rb +37 -28
- data/lib/timetree/models/calendar.rb +40 -4
- data/lib/timetree/models/event.rb +35 -9
- data/lib/timetree/models/label.rb +2 -0
- data/lib/timetree/models/user.rb +2 -0
- data/lib/timetree/oauth_app/client.rb +256 -0
- data/lib/timetree/version.rb +1 -1
- data/timetree.gemspec +9 -10
- metadata +42 -52
- data/lib/timetree/client.rb +0 -298
@@ -5,15 +5,21 @@ require 'logger'
|
|
5
5
|
module TimeTree
|
6
6
|
# TimeTree apis client configuration.
|
7
7
|
class Configuration
|
8
|
-
# @return [String]
|
9
|
-
attr_accessor :
|
8
|
+
# @return [String] OAuthApp's access token
|
9
|
+
attr_accessor :oauth_app_token
|
10
|
+
|
11
|
+
# @return [String] CalendarApp's app id
|
12
|
+
attr_accessor :calendar_app_application_id
|
13
|
+
# @return [String] CalendarApp's private key content#
|
14
|
+
# e.g. File.read('<YOUR_PATH_TO_PEM_FILE>')
|
15
|
+
attr_accessor :calendar_app_private_key
|
16
|
+
|
10
17
|
# @return [Logger]
|
11
18
|
attr_accessor :logger
|
12
19
|
|
13
20
|
def initialize
|
14
|
-
logger = Logger.new
|
15
|
-
logger.level = :warn
|
16
|
-
@logger = logger
|
21
|
+
@logger = Logger.new $stdout
|
22
|
+
@logger.level = :warn
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
@@ -15,22 +15,22 @@ module TimeTree
|
|
15
15
|
# @param path [String] String or URI to access.
|
16
16
|
# @param params [Hash] Hash of URI query unencoded key/value pairs.
|
17
17
|
def get(path, params = {})
|
18
|
-
logger.info "GET #{connection.build_url("#{@host}#{path}", params)}"
|
18
|
+
@logger.info "GET #{connection.build_url("#{@host}#{path}", params)}"
|
19
19
|
res = connection.get path, params
|
20
20
|
@client.update_ratelimit(res)
|
21
|
-
logger.debug "Response status:#{res.status}, body:#{res.body}"
|
21
|
+
@logger.debug "Response status:#{res.status}, body:#{res.body}"
|
22
22
|
res
|
23
23
|
end
|
24
24
|
|
25
25
|
# @param path [String] String or URI to access.
|
26
26
|
# @param body_params [Hash]
|
27
27
|
# The request bodythat will eventually be converted to JSON.
|
28
|
-
def post(path, body_params = {})
|
28
|
+
def post(path, body_params = {}, &block)
|
29
29
|
@logger.debug "POST #{@host}#{path} body:#{body_params}"
|
30
|
-
headers = {
|
31
|
-
res = connection.run_request :post, path, body_params.to_json, headers
|
30
|
+
headers = {'Content-Type' => 'application/json'}
|
31
|
+
res = connection.run_request :post, path, body_params.to_json, headers, &block
|
32
32
|
@client.update_ratelimit(res)
|
33
|
-
logger.debug "Response status:#{res.status}, body:#{res.body}"
|
33
|
+
@logger.debug "Response status:#{res.status}, body:#{res.body}"
|
34
34
|
res
|
35
35
|
end
|
36
36
|
|
@@ -38,11 +38,11 @@ module TimeTree
|
|
38
38
|
# @param body_params [Hash]
|
39
39
|
# The request bodythat will eventually be converted to JSON.
|
40
40
|
def put(path, body_params = {})
|
41
|
-
logger.debug "PUT #{@host}#{path} body:#{body_params}"
|
42
|
-
headers = {
|
41
|
+
@logger.debug "PUT #{@host}#{path} body:#{body_params}"
|
42
|
+
headers = {'Content-Type' => 'application/json'}
|
43
43
|
res = connection.run_request :put, path, body_params.to_json, headers
|
44
44
|
@client.update_ratelimit(res)
|
45
|
-
logger.debug "Response status:#{res.status}, body:#{res.body}"
|
45
|
+
@logger.debug "Response status:#{res.status}, body:#{res.body}"
|
46
46
|
res
|
47
47
|
end
|
48
48
|
|
@@ -52,20 +52,18 @@ module TimeTree
|
|
52
52
|
@logger.debug "DELETE #{@host}#{path} params:#{params}"
|
53
53
|
res = connection.delete path, params
|
54
54
|
@client.update_ratelimit(res)
|
55
|
-
logger.debug "Response status:#{res.status}, body:#{res.body}"
|
55
|
+
@logger.debug "Response status:#{res.status}, body:#{res.body}"
|
56
56
|
res
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
attr_reader :logger
|
59
|
+
private
|
62
60
|
|
63
61
|
def connection
|
64
62
|
Faraday.new(
|
65
63
|
url: @host,
|
66
64
|
headers: base_request_headers
|
67
65
|
) do |builder|
|
68
|
-
builder.response :json, parser_options: {
|
66
|
+
builder.response :json, parser_options: {symbolize_names: true}, content_type: /\bjson$/
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'timetree/models/base_model'
|
4
|
+
|
3
5
|
module TimeTree
|
4
6
|
# Model for TimeTree comment.
|
5
7
|
class Activity < BaseModel
|
@@ -29,7 +31,7 @@ module TimeTree
|
|
29
31
|
# @since 0.0.1
|
30
32
|
def create
|
31
33
|
check_client
|
32
|
-
|
34
|
+
_create
|
33
35
|
end
|
34
36
|
|
35
37
|
#
|
@@ -39,8 +41,18 @@ module TimeTree
|
|
39
41
|
# @since 0.0.1
|
40
42
|
def data_params
|
41
43
|
{
|
42
|
-
data: {
|
44
|
+
data: {attributes: {content: content}}
|
43
45
|
}
|
44
46
|
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def _create
|
51
|
+
if @client.is_a?(CalendarApp::Client)
|
52
|
+
@client.create_activity(event_id, data_params)
|
53
|
+
else
|
54
|
+
@client.create_activity(calendar_id, event_id, data_params)
|
55
|
+
end
|
56
|
+
end
|
45
57
|
end
|
46
58
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'timetree/models/base_model'
|
4
|
+
|
5
|
+
module TimeTree
|
6
|
+
# Model for TimeTree application.
|
7
|
+
class Application < BaseModel
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :name
|
10
|
+
# @return [String]
|
11
|
+
attr_accessor :description
|
12
|
+
# @return [String]
|
13
|
+
attr_accessor :image_url
|
14
|
+
end
|
15
|
+
end
|
@@ -4,7 +4,7 @@ require 'time'
|
|
4
4
|
|
5
5
|
module TimeTree
|
6
6
|
# TimeTree base model object.
|
7
|
-
class BaseModel
|
7
|
+
class BaseModel # rubocop:disable Metrics/ClassLength
|
8
8
|
# @return [Array<Hash<String,String>>]
|
9
9
|
attr_accessor :relationships
|
10
10
|
# @return [String]
|
@@ -15,15 +15,15 @@ module TimeTree
|
|
15
15
|
# @param data [Hash]
|
16
16
|
# TimeTree apis's response data.
|
17
17
|
# @param included [Hash]
|
18
|
-
# @param client [TimeTree::Client]
|
19
|
-
# @return [TimeTree::User, TimeTree::Label, TimeTree::Calendar, TimeTree::Event, TimeTree::Activity]
|
18
|
+
# @param client [TimeTree::OAuthApp::Client, TimeTree::CalendarApp::Client]
|
19
|
+
# @return [TimeTree::User, TimeTree::Label, TimeTree::Calendar, TimeTree::Event, TimeTree::Activity, Hash]
|
20
20
|
# A TimeTree model object that be based on the type.
|
21
|
-
# @raise [TimeTree::Error] if the type property is not set
|
21
|
+
# @raise [TimeTree::Error] if the type property is not set.
|
22
22
|
# @since 0.0.1
|
23
|
-
def self.to_model(data, included: nil, client: nil)
|
23
|
+
def self.to_model(data, included: nil, client: nil) # rubocop:disable all
|
24
24
|
id = data[:id]
|
25
25
|
type = data[:type]
|
26
|
-
raise Error
|
26
|
+
raise Error.new('type is required.') if type.nil?
|
27
27
|
|
28
28
|
attributes = data[:attributes] || {}
|
29
29
|
relationships = data[:relationships] || {}
|
@@ -37,22 +37,26 @@ module TimeTree
|
|
37
37
|
}
|
38
38
|
|
39
39
|
case type
|
40
|
-
when '
|
41
|
-
|
42
|
-
when '
|
43
|
-
|
40
|
+
when 'activity'
|
41
|
+
Activity.new(**params)
|
42
|
+
when 'application'
|
43
|
+
Application.new(**params)
|
44
44
|
when 'calendar'
|
45
45
|
Calendar.new(**params)
|
46
46
|
when 'event'
|
47
47
|
Event.new(**params)
|
48
|
-
when '
|
49
|
-
|
48
|
+
when 'label'
|
49
|
+
Label.new(**params)
|
50
|
+
when 'user'
|
51
|
+
User.new(**params)
|
50
52
|
else
|
51
|
-
|
53
|
+
TimeTree.configuration.logger.warn("type '#{type}' is unknown. id:#{id}")
|
54
|
+
# when unexpected model type, return the 'data' argument.
|
55
|
+
data
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
|
-
def initialize(type:, id: nil, client: nil, attributes: nil, relationships: nil, included: nil)
|
59
|
+
def initialize(type:, id: nil, client: nil, attributes: nil, relationships: nil, included: nil) # rubocop:disable Metrics/ParameterLists
|
56
60
|
@type = type
|
57
61
|
@id = id
|
58
62
|
@client = client
|
@@ -64,33 +68,29 @@ module TimeTree
|
|
64
68
|
"\#<#{self.class}:#{object_id} id:#{id}>"
|
65
69
|
end
|
66
70
|
|
67
|
-
|
71
|
+
private
|
68
72
|
|
69
73
|
def check_client
|
70
|
-
raise Error
|
74
|
+
raise Error.new('@client is nil.') if @client.nil?
|
71
75
|
end
|
72
76
|
|
73
77
|
def to_model(data)
|
74
78
|
self.class.to_model data, client: @client
|
75
79
|
end
|
76
80
|
|
77
|
-
def set_attributes(attributes)
|
81
|
+
def set_attributes(attributes) # rubocop:disable Naming/AccessorMethodName
|
78
82
|
return unless attributes.is_a? Hash
|
79
83
|
return if attributes.empty?
|
80
84
|
|
81
|
-
setter_methods = self.class.instance_methods.select { |method| method.to_s.end_with? '=' }
|
82
85
|
attributes.each do |key, value|
|
83
|
-
|
84
|
-
next unless setter_methods.include? setter
|
86
|
+
next unless respond_to?("#{key}=".to_sym)
|
85
87
|
|
86
|
-
if defined?(self.class::TIME_FIELDS) && self.class::TIME_FIELDS.include?(key)
|
87
|
-
value = Time.parse value
|
88
|
-
end
|
88
|
+
value = Time.parse value if defined?(self.class::TIME_FIELDS) && self.class::TIME_FIELDS.include?(key)
|
89
89
|
instance_variable_set "@#{key}", value
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
-
def set_relationships(relationships, included)
|
93
|
+
def set_relationships(relationships, included) # rubocop:disable all
|
94
94
|
return unless relationships.is_a? Hash
|
95
95
|
return if relationships.empty?
|
96
96
|
return unless defined? self.class::RELATIONSHIPS
|
@@ -112,21 +112,30 @@ module TimeTree
|
|
112
112
|
set_relationship_data_if_included(included)
|
113
113
|
end
|
114
114
|
|
115
|
-
def set_relationship_data_if_included(included)
|
115
|
+
def set_relationship_data_if_included(included) # rubocop:disable all
|
116
116
|
@_relation_data_dic = {}
|
117
117
|
included.each do |data|
|
118
118
|
item = to_model(data)
|
119
119
|
next unless item
|
120
120
|
|
121
|
-
|
122
|
-
|
121
|
+
if item.is_a? Hash
|
122
|
+
item_id = item[:id]
|
123
|
+
item_type = item[:type]
|
124
|
+
else
|
125
|
+
item_id = item.id
|
126
|
+
item_type = item.type
|
127
|
+
end
|
128
|
+
next unless item_id && item_type
|
129
|
+
|
130
|
+
@_relation_data_dic[item_type] ||= {}
|
131
|
+
@_relation_data_dic[item_type][item_id] = item
|
123
132
|
end
|
124
133
|
detect_relation_data = lambda { |type, id|
|
125
134
|
return unless @_relation_data_dic[type]
|
126
135
|
|
127
136
|
@_relation_data_dic[type][id]
|
128
137
|
}
|
129
|
-
|
138
|
+
relationships.each do |key, id_data|
|
130
139
|
relation_data = nil
|
131
140
|
if id_data.is_a? Array
|
132
141
|
relation_data = []
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'timetree/models/base_model'
|
4
|
+
|
3
5
|
module TimeTree
|
4
6
|
# Model for TimeTree calendar.
|
5
7
|
class Calendar < BaseModel
|
@@ -30,7 +32,7 @@ module TimeTree
|
|
30
32
|
# @since 0.0.1
|
31
33
|
def event(event_id)
|
32
34
|
check_client
|
33
|
-
|
35
|
+
get_event(event_id)
|
34
36
|
end
|
35
37
|
|
36
38
|
#
|
@@ -46,7 +48,7 @@ module TimeTree
|
|
46
48
|
# @since 0.0.1
|
47
49
|
def upcoming_events(days: 7, timezone: 'UTC')
|
48
50
|
check_client
|
49
|
-
|
51
|
+
get_upcoming_event(days, timezone)
|
50
52
|
end
|
51
53
|
|
52
54
|
#
|
@@ -60,7 +62,7 @@ module TimeTree
|
|
60
62
|
return @members if defined? @members
|
61
63
|
|
62
64
|
check_client
|
63
|
-
@members =
|
65
|
+
@members = get_members
|
64
66
|
end
|
65
67
|
|
66
68
|
#
|
@@ -74,7 +76,41 @@ module TimeTree
|
|
74
76
|
return @labels if defined? @labels
|
75
77
|
|
76
78
|
check_client
|
77
|
-
@labels =
|
79
|
+
@labels = get_labels
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def get_event(event_id)
|
85
|
+
if @client.is_a?(CalendarApp::Client)
|
86
|
+
@client.event(event_id)
|
87
|
+
else
|
88
|
+
@client.event(id, event_id)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_upcoming_event(days, timezone)
|
93
|
+
if @client.is_a?(CalendarApp::Client)
|
94
|
+
@client.upcoming_events(days: days, timezone: timezone)
|
95
|
+
else
|
96
|
+
@client.upcoming_events(id, days: days, timezone: timezone)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_members
|
101
|
+
if @client.is_a?(CalendarApp::Client)
|
102
|
+
@client.calendar_members
|
103
|
+
else
|
104
|
+
@client.calendar_members(id)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_labels
|
109
|
+
if @client.is_a?(CalendarApp::Client)
|
110
|
+
raise Error.new 'CalendarApp does not support label api'
|
111
|
+
else
|
112
|
+
@client.calendar_labels(id)
|
113
|
+
end
|
78
114
|
end
|
79
115
|
end
|
80
116
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'timetree/models/base_model'
|
4
|
+
|
3
5
|
module TimeTree
|
4
6
|
# Model for TimeTree event or keep.
|
5
7
|
class Event < BaseModel
|
@@ -54,7 +56,7 @@ module TimeTree
|
|
54
56
|
# @since 0.0.1
|
55
57
|
def create
|
56
58
|
check_client
|
57
|
-
|
59
|
+
_create_event
|
58
60
|
end
|
59
61
|
|
60
62
|
#
|
@@ -66,7 +68,7 @@ module TimeTree
|
|
66
68
|
# @since 0.0.1
|
67
69
|
def update
|
68
70
|
check_client
|
69
|
-
|
71
|
+
_update_event
|
70
72
|
end
|
71
73
|
|
72
74
|
#
|
@@ -78,7 +80,7 @@ module TimeTree
|
|
78
80
|
# @since 0.0.1
|
79
81
|
def delete
|
80
82
|
check_client
|
81
|
-
|
83
|
+
_delete_event
|
82
84
|
end
|
83
85
|
|
84
86
|
#
|
@@ -90,7 +92,7 @@ module TimeTree
|
|
90
92
|
# @since 0.0.1
|
91
93
|
def create_comment(message)
|
92
94
|
check_client
|
93
|
-
params = {
|
95
|
+
params = {type: 'activity', attributes: {calendar_id: calendar_id, event_id: id, content: message}}
|
94
96
|
activity = to_model params
|
95
97
|
activity.create
|
96
98
|
end
|
@@ -120,15 +122,39 @@ module TimeTree
|
|
120
122
|
}
|
121
123
|
end
|
122
124
|
|
123
|
-
|
125
|
+
private
|
124
126
|
|
125
127
|
def relationships_params
|
126
|
-
current_label = label ? {
|
127
|
-
current_attendees = attendees ? attendees.map { |u| {
|
128
|
+
current_label = label ? {type: 'label', id: label.id} : relationships[:label]
|
129
|
+
current_attendees = attendees ? attendees.map { |u| {type: 'user', id: u.id} } : relationships[:attendees]
|
128
130
|
{
|
129
|
-
label: {
|
130
|
-
attendees: {
|
131
|
+
label: {data: current_label},
|
132
|
+
attendees: {data: current_attendees}
|
131
133
|
}
|
132
134
|
end
|
135
|
+
|
136
|
+
def _create_event
|
137
|
+
if @client.is_a?(CalendarApp::Client)
|
138
|
+
@client.create_event(data_params)
|
139
|
+
else
|
140
|
+
@client.create_event(calendar_id, data_params)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def _update_event
|
145
|
+
if @client.is_a?(CalendarApp::Client)
|
146
|
+
@client.update_event(id, data_params)
|
147
|
+
else
|
148
|
+
@client.update_event(calendar_id, id, data_params)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def _delete_event
|
153
|
+
if @client.is_a?(CalendarApp::Client)
|
154
|
+
@client.delete_event(id)
|
155
|
+
else
|
156
|
+
@client.delete_event(calendar_id, id)
|
157
|
+
end
|
158
|
+
end
|
133
159
|
end
|
134
160
|
end
|