timetree 0.0.1

This diff has not been reviewed by any users.
Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bd2bf9fe5f866b70a0d08f66a937091892d8d4f3ab09002887eeab9cb6695158
4
+ data.tar.gz: d27d7eda7746d390feee7f167226ef444e1ed9a0e837cf9ad4510aa577cba340
5
+ SHA512:
6
+ metadata.gz: 5d8e892ce5c8a12ca0629cab12f15228a28dc2df3d5d0abce51570c3714838aa4a05da1c96575972e4a0af3197057cf2780380d16e31ec364b58513558de5e2c
7
+ data.tar.gz: c793202b5743b3818fea43bdc1ca6c2b44483d197098d0191181f5bada1dd27a862f6675fa183d959eee696294ba8e6bb680fef1f8ae9753542409ba43314a3b
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ Gemfile.lock
@@ -0,0 +1,69 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Layout/AccessModifierIndentation:
5
+ EnforcedStyle: outdent
6
+
7
+ Layout/HashAlignment:
8
+ Enabled: false
9
+
10
+ Layout/DotPosition:
11
+ EnforcedStyle: trailing
12
+
13
+ Layout/SpaceInsideHashLiteralBraces:
14
+ EnforcedStyle: no_space
15
+
16
+ Lint/SuppressedException:
17
+ Enabled: false
18
+
19
+ Metrics/BlockLength:
20
+ Enabled: false
21
+
22
+ Metrics/BlockNesting:
23
+ Max: 2
24
+
25
+ Layout/LineLength:
26
+ AllowURI: true
27
+ Enabled: false
28
+
29
+ Metrics/MethodLength:
30
+ CountComments: false
31
+ Max: 15
32
+
33
+ Metrics/ParameterLists:
34
+ Max: 4
35
+ CountKeywordArgs: true
36
+
37
+ Metrics/AbcSize:
38
+ Enabled: false
39
+
40
+ Style/CollectionMethods:
41
+ PreferredMethods:
42
+ map: 'collect'
43
+ reduce: 'inject'
44
+ find: 'detect'
45
+ find_all: 'select'
46
+
47
+ Style/Documentation:
48
+ Enabled: false
49
+
50
+ Style/DoubleNegation:
51
+ Enabled: false
52
+
53
+ Style/EachWithObject:
54
+ Enabled: false
55
+
56
+ Style/Encoding:
57
+ Enabled: false
58
+
59
+ Style/ExpandPathArguments:
60
+ Enabled: false
61
+
62
+ Style/HashSyntax:
63
+ EnforcedStyle: hash_rockets
64
+
65
+ Style/Lambda:
66
+ Enabled: false
67
+
68
+ Style/RaiseArgs:
69
+ EnforcedStyle: compact
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.3
6
+ before_install: gem install bundler -v 2.1.4
@@ -0,0 +1,3 @@
1
+ # 0.0.1
2
+
3
+ - Initial release
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at koshikawa2009@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in timetree.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Kenji Koshikawa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ # TimeTree Api Client
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/timetree.svg)](http://badge.fury.io/rb/timetree)
4
+
5
+ ## About
6
+
7
+ These client libraries are created for [TimeTree APIs](https://developers.timetreeapp.com/en).
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'timetree'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install timetree
24
+
25
+ ## Usage
26
+
27
+ The Api client needs access token.
28
+ Set `access_token` to the value you got by above:
29
+
30
+ ```ruby
31
+ # using configure
32
+ TimeTree.configure do |config|
33
+ config.access_token = '<YOUR_ACCESS_TOKEN>'
34
+ end
35
+ client = TimeTree::Client.new
36
+
37
+ # using initializer
38
+ client = TimeTree::Client.new('<YOUR_ACCESS_TOKEN>')
39
+
40
+ # TODO
41
+ ```
42
+
43
+ ## Contributing
44
+
45
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/koshilife/timetree-api-ruby-client). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
46
+
47
+ ## License
48
+
49
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
50
+
51
+ ## Code of Conduct
52
+
53
+ Everyone interacting in the TimeTree Api Client project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/koshilife/timetree-api-ruby-client/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "timetree"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[
4
+ File.join(
5
+ File.dirname(__FILE__),
6
+ 'timetree',
7
+ '*'
8
+ )
9
+ ].sort.each do |f|
10
+ require f
11
+ end
12
+
13
+ module TimeTree
14
+ class << self
15
+ def configure
16
+ yield configuration
17
+ end
18
+
19
+ def configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+ end
23
+
24
+ class Error < StandardError
25
+ end
26
+ end
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'faraday'
5
+ require 'faraday_middleware'
6
+
7
+ module TimeTree
8
+ class Client
9
+ API_HOST = 'https://timetreeapis.com'
10
+
11
+ attr_reader :ratelimit_limit
12
+ attr_reader :ratelimit_remaining
13
+ attr_reader :ratelimit_reset_at
14
+
15
+ def initialize(access_token = nil)
16
+ config = TimeTree.configuration
17
+ @access_token = access_token || config.access_token
18
+ @logger = config.logger
19
+ end
20
+
21
+ def inspect
22
+ limit_info = nil
23
+ if @ratelimit_limit
24
+ limit_info = " ratelimit:#{@ratelimit_remaining}/#{@ratelimit_limit}"
25
+ end
26
+ if @ratelimit_reset_at
27
+ limit_info = "#{limit_info}, reset_at:#{@ratelimit_reset_at.strftime('%m/%d %R')}"
28
+ end
29
+ "\#<#{self.class}:#{object_id}#{limit_info}>"
30
+ end
31
+
32
+ #
33
+ # User
34
+ #
35
+
36
+ def user
37
+ res = get '/user'
38
+ raise if res.status != 200
39
+
40
+ to_model res.body[:data]
41
+ end
42
+
43
+ #
44
+ # Calendar
45
+ #
46
+
47
+ def calendar(cal_id, include_relationships: nil)
48
+ params = relationships_params(include_relationships, Calendar::RELATIONSHIPS)
49
+ res = get "/calendars/#{cal_id}", params
50
+ raise if res.status != 200
51
+
52
+ to_model(res.body[:data], included: res.body[:included])
53
+ end
54
+
55
+ def calendars(include_relationships: nil)
56
+ params = relationships_params(include_relationships, Calendar::RELATIONSHIPS)
57
+ res = get '/calendars', params
58
+ raise if res.status != 200
59
+
60
+ included = res.body[:included]
61
+ res.body[:data].map { |item| to_model(item, included: included) }
62
+ end
63
+
64
+ def calendar_labels(cal_id)
65
+ res = get "/calendars/#{cal_id}/labels"
66
+ raise if res.status != 200
67
+
68
+ res.body[:data].map { |item| to_model(item) }
69
+ end
70
+
71
+ def calendar_members(cal_id)
72
+ res = get "/calendars/#{cal_id}/members"
73
+ raise if res.status != 200
74
+
75
+ res.body[:data].map { |item| to_model item }
76
+ end
77
+
78
+ #
79
+ # Schedule/Keep
80
+ #
81
+
82
+ def event(cal_id, event_id, include_relationships: nil)
83
+ params = relationships_params(include_relationships, Event::RELATIONSHIPS)
84
+ res = get "/calendars/#{cal_id}/events/#{event_id}", params
85
+ raise if res.status != 200
86
+
87
+ ev = to_model(res.body[:data], included: res.body[:included])
88
+ ev.calendar_id = cal_id
89
+ ev
90
+ end
91
+
92
+ def upcoming_events(cal_id, days: 7, timezone: 'UTC', include_relationships: nil)
93
+ params = relationships_params(include_relationships, Event::RELATIONSHIPS)
94
+ params.merge!(days: days, timezone: timezone)
95
+ res = get "/calendars/#{cal_id}/upcoming_events", params
96
+ raise if res.status != 200
97
+
98
+ included = res.body[:included]
99
+ res.body[:data].map do |item|
100
+ ev = to_model(item, included: included)
101
+ ev.calendar_id = cal_id
102
+ ev
103
+ end
104
+ end
105
+
106
+ def create_event(cal_id, params)
107
+ res = post "/calendars/#{cal_id}/events", params
108
+ raise if res.status != 201
109
+
110
+ ev = to_model res.body[:data]
111
+ ev.calendar_id = cal_id
112
+ ev
113
+ end
114
+
115
+ def update_event(cal_id, event_id, params)
116
+ res = put "/calendars/#{cal_id}/events/#{event_id}", params
117
+ raise if res.status != 200
118
+
119
+ ev = to_model res.body[:data]
120
+ ev.calendar_id = cal_id
121
+ ev
122
+ end
123
+
124
+ def delete_event(cal_id, event_id)
125
+ res = delete "/calendars/#{cal_id}/events/#{event_id}"
126
+ raise if res.status != 204
127
+
128
+ true
129
+ end
130
+
131
+ #
132
+ # Activity
133
+ #
134
+
135
+ def create_activity(cal_id, event_id, params)
136
+ res = post "/calendars/#{cal_id}/events/#{event_id}/activities", params
137
+ raise if res.status != 201
138
+
139
+ activity = to_model res.body[:data]
140
+ activity.calendar_id = cal_id
141
+ activity.event_id = event_id
142
+ activity
143
+ end
144
+
145
+ private
146
+
147
+ attr_reader :logger
148
+
149
+ def to_model(data, included: nil)
150
+ TimeTree::BaseModel.to_model data, client: self, included: included
151
+ end
152
+
153
+ def relationships_params(relationships, default)
154
+ params = {}
155
+ relationships ||= default
156
+ params[:include] = relationships.join ',' if relationships.is_a? Array
157
+ params
158
+ end
159
+
160
+ def update_ratelimit(res)
161
+ limit = res.headers['x-ratelimit-limit']
162
+ remaining = res.headers['x-ratelimit-remaining']
163
+ reset = res.headers['x-ratelimit-reset']
164
+ @ratelimit_limit = limit.to_i if limit
165
+ @ratelimit_remaining = remaining.to_i if remaining
166
+ @ratelimit_reset_at = Time.at reset.to_i if reset
167
+ end
168
+
169
+ def get(path, params = {})
170
+ logger.info "GET #{connection.build_url("#{API_HOST}#{path}", params)}"
171
+ res = connection.get path, params
172
+ update_ratelimit(res)
173
+ logger.debug "Response status:#{res.status}, body:#{res.body}"
174
+ res
175
+ end
176
+
177
+ def put(path, params = {})
178
+ logger.debug "PUT #{API_HOST}#{path} body:#{params}"
179
+ res = connection.put path do |req|
180
+ req.headers['Content-Type'] = 'application/json'
181
+ req.body = params.to_json
182
+ end
183
+ update_ratelimit(res)
184
+ logger.debug "Response status:#{res.status}, body:#{res.body}"
185
+ res
186
+ end
187
+
188
+ def post(path, params = {})
189
+ @logger.debug "POST #{API_HOST}#{path} body:#{params}"
190
+ res = connection.post path, params do |req|
191
+ req.headers['Content-Type'] = 'application/json'
192
+ req.body = params.to_json
193
+ end
194
+ update_ratelimit(res)
195
+ logger.debug "Response status:#{res.status}, body:#{res.body}"
196
+ res
197
+ end
198
+
199
+ def delete(path, params = {})
200
+ @logger.debug "DELETE #{API_HOST}#{path} params:#{params}"
201
+ res = connection.delete path, params
202
+ update_ratelimit(res)
203
+ logger.debug "Response status:#{res.status}, body:#{res.body}"
204
+ res
205
+ end
206
+
207
+ def connection
208
+ Faraday.new(
209
+ url: API_HOST,
210
+ headers: {
211
+ 'Accept' => 'application/vnd.timetree.v1+json',
212
+ 'Authorization' => "Bearer #{@access_token}"
213
+ }
214
+ ) do |builder|
215
+ builder.response :json, parser_options: { symbolize_names: true }, content_type: /\bjson$/
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module TimeTree
6
+ class Configuration
7
+ attr_accessor :access_token
8
+ attr_accessor :logger
9
+ def initialize
10
+ logger = Logger.new(STDOUT)
11
+ logger.level = :warn
12
+ @logger = logger
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module TimeTree
6
+ class BaseModel
7
+ attr_reader :id
8
+ attr_reader :type
9
+ attr_accessor :relationships
10
+
11
+ # @param data [Hash]
12
+ # @param client [TimeTree::Client]
13
+ # @return [TimeTree::BaseModel]
14
+ def self.to_model(data, included: nil, client: nil)
15
+ id = data[:id]
16
+ type = data[:type]
17
+ return if type.nil?
18
+
19
+ attributes = data[:attributes] || {}
20
+ relationships = data[:relationships] || {}
21
+ params = {
22
+ id: id,
23
+ type: type,
24
+ client: client,
25
+ attributes: attributes,
26
+ relationships: relationships,
27
+ included: included
28
+ }
29
+
30
+ case type
31
+ when 'user'
32
+ User.new(**params)
33
+ when 'label'
34
+ Label.new(**params)
35
+ when 'event'
36
+ Event.new(**params)
37
+ when 'calendar'
38
+ Calendar.new(**params)
39
+ when 'activity'
40
+ Activity.new(**params)
41
+ end
42
+ end
43
+
44
+ def initialize(id:, type:, client: nil, attributes: nil, relationships: nil, included: nil)
45
+ @id = id
46
+ @type = type
47
+ @client = client
48
+ set_attributes attributes
49
+ set_relationships relationships, included
50
+ end
51
+
52
+ def inspect
53
+ "\#<#{self.class}:#{object_id} id:#{id}>"
54
+ end
55
+
56
+ private
57
+
58
+ def to_model(data)
59
+ self.class.to_model data, client: @client
60
+ end
61
+
62
+ def set_attributes(attributes)
63
+ return unless attributes.is_a? Hash
64
+ return if attributes.empty?
65
+
66
+ setter_methods = self.class.instance_methods.select { |method| method.to_s.end_with? '=' }
67
+ attributes.each do |key, value|
68
+ setter = "#{key.to_sym}=".to_sym
69
+ next unless setter_methods.include? setter
70
+
71
+ if defined?(self.class::TIME_FIELDS) && self.class::TIME_FIELDS.include?(key)
72
+ value = Time.parse value
73
+ end
74
+ instance_variable_set "@#{key}", value
75
+ end
76
+ end
77
+
78
+ def set_relationships(relationships, included)
79
+ return unless relationships.is_a? Hash
80
+ return if relationships.empty?
81
+ return unless defined? self.class::RELATIONSHIPS
82
+ return if self.class::RELATIONSHIPS.empty?
83
+
84
+ self.class::RELATIONSHIPS.each do |key|
85
+ relation = relationships[key]
86
+ next unless relation
87
+ next unless relation[:data]
88
+
89
+ @relationships ||= {}
90
+ @relationships[key] = relation[:data]
91
+ end
92
+
93
+ return if included.nil?
94
+ return unless included.is_a? Array
95
+ return if included.empty?
96
+
97
+ set_relationship_data_if_included(included)
98
+ end
99
+
100
+ def set_relationship_data_if_included(included)
101
+ @_relation_data_dic = {}
102
+ included.each do |data|
103
+ item = to_model(data)
104
+ next unless item
105
+
106
+ @_relation_data_dic[item.type] ||= {}
107
+ @_relation_data_dic[item.type][item.id] = item
108
+ end
109
+ detect_relation_data = lambda { |type, id|
110
+ return unless @_relation_data_dic[type]
111
+
112
+ @_relation_data_dic[type][id]
113
+ }
114
+ @relationships.each do |key, id_data|
115
+ relation_data = nil
116
+ if id_data.is_a? Array
117
+ relation_data = []
118
+ id_data.each do |d|
119
+ item = detect_relation_data.call(d[:type], d[:id])
120
+ relation_data << item if item
121
+ end
122
+ elsif id_data.is_a? Hash
123
+ relation_data = detect_relation_data.call(id_data[:type], id_data[:id])
124
+ end
125
+ instance_variable_set "@#{key}", relation_data if relation_data
126
+ end
127
+ end
128
+ end
129
+
130
+ class User < BaseModel
131
+ attr_accessor :name
132
+ attr_accessor :description
133
+ attr_accessor :image_url
134
+ end
135
+
136
+ class Label < BaseModel
137
+ attr_accessor :name
138
+ attr_accessor :color
139
+ end
140
+
141
+ class Calendar < BaseModel
142
+ attr_accessor :name
143
+ attr_accessor :description
144
+ attr_accessor :color
145
+ attr_accessor :order
146
+ attr_accessor :image_url
147
+ attr_accessor :created_at
148
+
149
+ TIME_FIELDS = %i[created_at].freeze
150
+ RELATIONSHIPS = %i[labels members].freeze
151
+
152
+ def event(event_id)
153
+ return if @client.nil?
154
+
155
+ @client.event id, event_id
156
+ end
157
+
158
+ def upcoming_events(days: 7, timezone: 'UTC')
159
+ return if @client.nil?
160
+
161
+ @client.upcoming_events id, days: days, timezone: timezone
162
+ end
163
+
164
+ def labels
165
+ return @labels if defined? @labels
166
+ return if @client.nil?
167
+
168
+ @labels = @client.calendar_labels id
169
+ end
170
+
171
+ def members
172
+ return @members if defined? @members
173
+ return if @client.nil?
174
+
175
+ @members = @client.calendar_members id
176
+ end
177
+ end
178
+
179
+ class Event < BaseModel
180
+ attr_accessor :category
181
+ attr_accessor :title
182
+ attr_accessor :all_day
183
+ attr_accessor :start_at
184
+ attr_accessor :start_timezone
185
+ attr_accessor :end_at
186
+ attr_accessor :end_timezone
187
+ attr_accessor :recurrences
188
+ attr_accessor :recurring_uuid
189
+ attr_accessor :description
190
+ attr_accessor :location
191
+ attr_accessor :url
192
+ attr_accessor :updated_at
193
+ attr_accessor :created_at
194
+ attr_accessor :calendar_id
195
+
196
+ attr_reader :creator
197
+ attr_reader :label
198
+ attr_reader :attendees
199
+
200
+ TIME_FIELDS = %i[start_at end_at updated_at created_at].freeze
201
+ RELATIONSHIPS = %i[creator label attendees].freeze
202
+
203
+ def create
204
+ return if @client.nil?
205
+
206
+ @client.create_event calendar_id, data_params
207
+ end
208
+
209
+ def create_comment(message)
210
+ return if @client.nil?
211
+
212
+ params = { type: 'activity', attributes: { calendar_id: calendar_id, event_id: id, content: message } }
213
+ activity = to_model params
214
+ return if activity.nil?
215
+
216
+ activity.create
217
+ end
218
+
219
+ def update
220
+ return if @client.nil?
221
+ return if id.nil?
222
+
223
+ @client.update_event calendar_id, id, data_params
224
+ end
225
+
226
+ def delete
227
+ return if @client.nil?
228
+ return if id.nil?
229
+
230
+ @client.delete_event calendar_id, id
231
+ end
232
+
233
+ def data_params
234
+ attributes_params = {
235
+ category: category,
236
+ title: title,
237
+ all_day: all_day,
238
+ start_at: start_at.iso8601,
239
+ start_timezone: start_timezone,
240
+ end_at: end_at.iso8601,
241
+ end_timezone: end_timezone,
242
+ description: description,
243
+ location: location,
244
+ url: url
245
+ }
246
+ relationhips_params = {}
247
+ if @relationships[:label]
248
+ label_data = { id: @relationships[:label], type: 'label' }
249
+ relationhips_params[:label] = { data: label_data }
250
+ end
251
+ if @relationships[:attendees]
252
+ attendees_data = @relationships[:attendees].map { |_id| { id: _id, type: 'user' } }
253
+ relationhips_params[:attendees] = { data: attendees_data }
254
+ end
255
+ {
256
+ data: { attributes: attributes_params, relationships: relationhips_params }
257
+ }
258
+ end
259
+ end
260
+
261
+ class Activity < BaseModel
262
+ attr_accessor :content
263
+ attr_accessor :updated_at
264
+ attr_accessor :created_at
265
+ attr_accessor :calendar_id
266
+ attr_accessor :event_id
267
+
268
+ TIME_FIELDS = %i[updated_at created_at].freeze
269
+
270
+ def create
271
+ return if @client.nil?
272
+
273
+ @client.create_activity calendar_id, event_id, data_params
274
+ end
275
+
276
+ def data_params
277
+ {
278
+ data: { attributes: { content: content } }
279
+ }
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TimeTree
4
+ VERSION = '0.0.1'
5
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/timetree/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'timetree'
7
+ spec.version = TimeTree::VERSION
8
+ spec.authors = ['Kenji Koshikawa']
9
+ spec.email = ['koshikawa2009@gmail.com']
10
+
11
+ spec.description = 'Client for accessing TimeTree APIs'
12
+ spec.summary = spec.description
13
+ spec.homepage = 'https://github.com/koshilife/timetree-api-ruby-client'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/koshilife/timetree-api-ruby-client'
19
+ spec.metadata['changelog_uri'] = "#{spec.metadata['source_code_uri']}/blob/master/CHANGELOG.md"
20
+ spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/timetree/'
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ end
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_runtime_dependency 'faraday', '~> 1.0.1'
32
+ spec.add_runtime_dependency 'faraday_middleware', '~> 1.0.0'
33
+
34
+ spec.add_development_dependency 'bundler', '~> 2.0'
35
+ spec.add_development_dependency 'minitest', '~> 5.14.0'
36
+ spec.add_development_dependency 'minitest-reporters', '~> 1.4.2'
37
+ spec.add_development_dependency 'rake', '~> 12.0'
38
+ spec.add_development_dependency 'webmock', '~> 3.7.6'
39
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timetree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kenji Koshikawa
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-06-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday_middleware
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 5.14.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 5.14.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.4.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.4.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '12.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '12.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.7.6
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.7.6
111
+ description: Client for accessing TimeTree APIs
112
+ email:
113
+ - koshikawa2009@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rubocom.yml"
120
+ - ".travis.yml"
121
+ - CHANGELOG.md
122
+ - CODE_OF_CONDUCT.md
123
+ - Gemfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/setup
129
+ - lib/timetree.rb
130
+ - lib/timetree/client.rb
131
+ - lib/timetree/configuration.rb
132
+ - lib/timetree/models.rb
133
+ - lib/timetree/version.rb
134
+ - timetree.gemspec
135
+ homepage: https://github.com/koshilife/timetree-api-ruby-client
136
+ licenses:
137
+ - MIT
138
+ metadata:
139
+ homepage_uri: https://github.com/koshilife/timetree-api-ruby-client
140
+ source_code_uri: https://github.com/koshilife/timetree-api-ruby-client
141
+ changelog_uri: https://github.com/koshilife/timetree-api-ruby-client/blob/master/CHANGELOG.md
142
+ documentation_uri: https://www.rubydoc.info/gems/timetree/
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: 2.4.0
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubygems_version: 3.1.4
159
+ signing_key:
160
+ specification_version: 4
161
+ summary: Client for accessing TimeTree APIs
162
+ test_files: []