docbase 2.1.2 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20af66cc5d5085854e9aef5f65e57383291a8f217961a4fa6cead0bb2e678941
4
- data.tar.gz: 24cf39072ac1eaf9c4cc700f6ee2bcc694939b5c4d26427cb932aedeabf499f0
3
+ metadata.gz: db7bc6f5163f765c5a16ec85c3a190c894e87b484acac0901458f44b81ca0355
4
+ data.tar.gz: 0eaace24913ca86fa825a2da026da6f9aff7e3a5cad1af5df1f505a91ec39d6e
5
5
  SHA512:
6
- metadata.gz: 12a494552034d86ba01f68a95e30a438ed068307223d83dd23b9e92fa23f15a85dc98cee60577342696b123ec2b5153f0935d77b58a3887f810da919beb7b0f8
7
- data.tar.gz: d5dc0fea1f5d08a13ea5df13c38c504e11a80b5a82f121ce9afe7d087cb1d4b06d48188434939bd41758a67029aacc692fd7db8466fd5db9c1f2fe6023a3ef7c
6
+ metadata.gz: 84a27324711539c8ffaea3365cbb1b75b8b2d6041d9f385b4994099657e183d4d42929c873701b4fed2e682c4164e240a03e5417f89c5897d20c2be3efd90fb4
7
+ data.tar.gz: 7a715b93cad6b2167bb98ca766698924e87ad63aa3034afe977fc60a97c07130cbb10c6f259e4a80c4fcad674abdea15b6a422faffa157378af5305d2e40c9f0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## 3.1.0
2
+
3
+ * faradayを2.14.4以上3未満に変更し、faraday_middlewareへの依存を削除(faraday 2.14.3以前では使えなくなります)
4
+ * `access_token`を差し替えても古いトークンで送信される不具合を修正
5
+ * IDやチーム名が不正なときはURLに埋め込まず`ArgumentError`にするように
6
+ * 利用制限時のリトライに上限を追加(3回まで、1回の待ちは60秒まで)。有効な`X-RateLimit-Reset`がない429はリトライしない
7
+
8
+ ## 3.0.0
9
+
10
+ * DocBase API v3対応
11
+ * プロフィール、所属グループ一覧、メンバー削除、コメント一覧、メモ本文部分更新、グッジョブAPIを追加
12
+ * `users`の`include_user_groups`引数を削除(v3で廃止)
13
+ * Ruby 3.4以降向けに`base64`依存を追加
14
+ * `X-Api-Version`ヘッダを削除(v3トークンでAPIバージョンが決まる)
15
+ * `create_comment`が`post_id`をリクエストボディに含めてしまう不具合を修正
16
+ * バイナリ取得用コネクションがJSON用と共有されていた不具合を修正
17
+
1
18
  ## 2.1.2
2
19
 
3
20
  * 利用制限時にリトライできるように
data/README.md CHANGED
@@ -35,6 +35,13 @@ client = DocBase::Client.new(access_token: 'your_access_token', team: 'your_team
35
35
  * retry_on_rate_limit_exceeded
36
36
  * [#16](https://github.com/krayinc/docbase-ruby/issues/16)
37
37
  * true or false
38
+ * When true, a 429 response is retried after waiting until `X-RateLimit-Reset`, up to 3 times and at most 60 seconds per wait. A 429 response without a valid `X-RateLimit-Reset` is returned without retrying.
39
+
40
+ ### profile
41
+
42
+ ```ruby
43
+ client.profile.body
44
+ ```
38
45
 
39
46
  ### users
40
47
 
@@ -42,7 +49,21 @@ client = DocBase::Client.new(access_token: 'your_access_token', team: 'your_team
42
49
  client.users(q: 'name')
43
50
  client.users(q: 'name', page: 2)
44
51
  client.users(q: 'name', page: 1, per_page: 100)
45
- client.users(q: 'name', page: 1, per_page: 100, include_user_groups: true)
52
+ ```
53
+
54
+ 所属グループはv3ではユーザー検索APIのレスポンスに含まれません。`user_groups`を利用してください。
55
+
56
+ #### User groups
57
+
58
+ ```ruby
59
+ client.user_groups(1).body
60
+ client.user_groups(1, page: 2, per_page: 20).body
61
+ ```
62
+
63
+ #### Delete user
64
+
65
+ ```ruby
66
+ client.delete_user(1)
46
67
  ```
47
68
 
48
69
  ### tags
@@ -150,6 +171,25 @@ params = {
150
171
  client.update_post(params)
151
172
  ```
152
173
 
174
+ #### Partial body update
175
+
176
+ ```ruby
177
+ params = {
178
+ id: 1,
179
+ operations: [
180
+ {
181
+ start: 3,
182
+ end: 5,
183
+ old_content: "line3\r\nline4\r\nline5",
184
+ content: 'new text',
185
+ },
186
+ ],
187
+ notice: true,
188
+ }
189
+
190
+ client.update_post_body(params)
191
+ ```
192
+
153
193
  #### Archive
154
194
 
155
195
  ```ruby
@@ -170,6 +210,13 @@ client.delete_post(1)
170
210
 
171
211
  ### Comment
172
212
 
213
+ #### List
214
+
215
+ ```ruby
216
+ client.comments(1).body
217
+ client.comments(1, page: 2, per_page: 20, order: 'desc').body
218
+ ```
219
+
173
220
  #### Create
174
221
 
175
222
  ```ruby
@@ -188,6 +235,28 @@ client.create_comment(params)
188
235
  client.delete_comment(1)
189
236
  ```
190
237
 
238
+ ### good jobs
239
+
240
+ #### List
241
+
242
+ ```ruby
243
+ client.good_jobs(1).body
244
+ client.good_jobs(1, page: 2, per_page: 100, order: 'desc').body
245
+ ```
246
+
247
+ #### Create
248
+
249
+ ```ruby
250
+ client.create_good_job(1)
251
+ client.create_good_job(1, notice: false)
252
+ ```
253
+
254
+ #### Delete
255
+
256
+ ```ruby
257
+ client.delete_good_job(1, 111)
258
+ ```
259
+
191
260
  ### attachments
192
261
 
193
262
  #### Create
data/docbase.gemspec CHANGED
@@ -17,6 +17,6 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_dependency 'faraday', '>= 0.15.2'
21
- spec.add_dependency 'faraday_middleware', '>= 0.12.2'
20
+ spec.add_dependency 'base64'
21
+ spec.add_dependency 'faraday', '>= 2.14.4', '< 3'
22
22
  end
@@ -1,7 +1,11 @@
1
1
  module DocBase
2
2
  class Client
3
3
  DEFAULT_URL = 'https://api.docbase.io'
4
+ TEAM_FORMAT = /\A[a-z0-9]+(-[a-z0-9]+)*\z/
5
+ ID_FORMAT = /\A[1-9][0-9]*\z/
4
6
  USER_AGENT = "DocBase Ruby Gem #{DocBase::VERSION}"
7
+ MAX_RATE_LIMIT_RETRIES = 3
8
+ MAX_RATE_LIMIT_WAIT_SECONDS = 60
5
9
 
6
10
  class NotSetTeamError < StandardError; end
7
11
  class NotSetPostIdError < StandardError; end
@@ -18,11 +22,33 @@ module DocBase
18
22
 
19
23
  def team!
20
24
  raise NotSetTeamError unless @team
25
+ raise ArgumentError, "invalid team: #{@team.inspect}" unless TEAM_FORMAT.match?(@team.to_s)
26
+
21
27
  @team
22
28
  end
23
29
 
24
- def users(q: nil, page: 1, per_page: 100, include_user_groups: false)
25
- request(method: :get, path: "/teams/#{team!}/users", params: { q: q, page: page, per_page: per_page, include_user_groups: include_user_groups })
30
+ def profile
31
+ request(method: :get, path: "/teams/#{team!}/profile")
32
+ end
33
+
34
+ def users(q: nil, page: 1, per_page: 100)
35
+ request(
36
+ method: :get,
37
+ path: "/teams/#{team!}/users",
38
+ params: { q: q, page: page, per_page: per_page }
39
+ )
40
+ end
41
+
42
+ def user_groups(user_id, page: 1, per_page: 20)
43
+ request(
44
+ method: :get,
45
+ path: "/teams/#{team!}/users/#{id_segment(user_id)}/groups",
46
+ params: { page: page, per_page: per_page }
47
+ )
48
+ end
49
+
50
+ def delete_user(id)
51
+ request(method: :delete, path: "/teams/#{team!}/users/#{id_segment(id)}")
26
52
  end
27
53
 
28
54
  def tags
@@ -34,7 +60,7 @@ module DocBase
34
60
  end
35
61
 
36
62
  def group(id)
37
- request(method: :get, path: "/teams/#{team!}/groups/#{id}")
63
+ request(method: :get, path: "/teams/#{team!}/groups/#{id_segment(id)}")
38
64
  end
39
65
 
40
66
  def create_group(params)
@@ -58,7 +84,7 @@ module DocBase
58
84
  end
59
85
 
60
86
  def post(id)
61
- request(method: :get, path: "/teams/#{team!}/posts/#{id}")
87
+ request(method: :get, path: "/teams/#{team!}/posts/#{id_segment(id)}")
62
88
  end
63
89
 
64
90
  def posts(q: '*', page: 1, per_page: 20)
@@ -71,34 +97,78 @@ module DocBase
71
97
 
72
98
  def update_post(params)
73
99
  post_id = params[:id].to_i
74
- raise NotSetTeamError if post_id <= 0
100
+ raise NotSetPostIdError if post_id <= 0
75
101
 
76
102
  post_params = except(params, :id)
77
103
  request(method: :patch, path: "/teams/#{team!}/posts/#{post_id}", params: post_params)
78
104
  end
79
105
 
106
+ def update_post_body(params)
107
+ post_id = params[:id].to_i
108
+ raise NotSetPostIdError if post_id <= 0
109
+
110
+ body_params = except(params, :id)
111
+ request(method: :patch, path: "/teams/#{team!}/posts/#{post_id}/body", params: body_params)
112
+ end
113
+
80
114
  def delete_post(id)
81
- request(method: :delete, path: "/teams/#{team!}/posts/#{id}")
115
+ request(method: :delete, path: "/teams/#{team!}/posts/#{id_segment(id)}")
82
116
  end
83
117
 
84
118
  def archive_post(id)
85
- request(method: :put, path: "/teams/#{team!}/posts/#{id}/archive")
119
+ request(method: :put, path: "/teams/#{team!}/posts/#{id_segment(id)}/archive")
86
120
  end
87
121
 
88
122
  def unarchive_post(id)
89
- request(method: :put, path: "/teams/#{team!}/posts/#{id}/unarchive")
123
+ request(method: :put, path: "/teams/#{team!}/posts/#{id_segment(id)}/unarchive")
124
+ end
125
+
126
+ def comments(post_id, page: 1, per_page: 20, order: 'asc', created_after: nil, created_before: nil)
127
+ request(
128
+ method: :get,
129
+ path: "/teams/#{team!}/posts/#{id_segment(post_id)}/comments",
130
+ params: {
131
+ page: page,
132
+ per_page: per_page,
133
+ order: order,
134
+ created_after: created_after,
135
+ created_before: created_before,
136
+ }
137
+ )
90
138
  end
91
139
 
92
140
  def create_comment(params)
93
141
  post_id = params[:post_id].to_i
94
- raise NotSetTeamError if post_id <= 0
142
+ raise NotSetPostIdError if post_id <= 0
95
143
 
96
144
  comment_params = except(params, :post_id)
97
- request(method: :post, path: "/teams/#{team!}/posts/#{post_id}/comments", params: params)
145
+ request(method: :post, path: "/teams/#{team!}/posts/#{post_id}/comments", params: comment_params)
98
146
  end
99
147
 
100
148
  def delete_comment(id)
101
- request(method: :delete, path: "/teams/#{team!}/comments/#{id}")
149
+ request(method: :delete, path: "/teams/#{team!}/comments/#{id_segment(id)}")
150
+ end
151
+
152
+ def good_jobs(post_id, page: 1, per_page: 100, order: 'asc', created_after: nil, created_before: nil)
153
+ request(
154
+ method: :get,
155
+ path: "/teams/#{team!}/posts/#{id_segment(post_id)}/good_jobs",
156
+ params: {
157
+ page: page,
158
+ per_page: per_page,
159
+ order: order,
160
+ created_after: created_after,
161
+ created_before: created_before,
162
+ }
163
+ )
164
+ end
165
+
166
+ def create_good_job(post_id, params = {})
167
+ request(method: :post, path: "/teams/#{team!}/posts/#{id_segment(post_id)}/good_jobs", params: params)
168
+ end
169
+
170
+ def delete_good_job(post_id, good_job_id)
171
+ request(method: :delete, path: "/teams/#{team!}/posts/#{id_segment(post_id)}/good_jobs/#{id_segment(good_job_id)}")
102
172
  end
103
173
 
104
174
  def upload(paths)
@@ -116,11 +186,24 @@ module DocBase
116
186
  end
117
187
 
118
188
  def attachment(id)
119
- request(method: :get, path: "/teams/#{team!}/attachments/#{id}", for_binary: true)
189
+ request(method: :get, path: "/teams/#{team!}/attachments/#{path_segment(id)}", for_binary: true)
120
190
  end
121
191
 
122
192
  private
123
193
 
194
+ def id_segment(id)
195
+ raise ArgumentError, "invalid id: #{id.inspect}" unless ID_FORMAT.match?(id.to_s)
196
+
197
+ id.to_s
198
+ end
199
+
200
+ def path_segment(value)
201
+ value = value.to_s
202
+ raise ArgumentError, "invalid id: #{value.inspect}" if value.empty? || value == '.' || value == '..'
203
+
204
+ URI.encode_www_form_component(value).gsub('+', '%20')
205
+ end
206
+
124
207
  def except(hash, reject_key)
125
208
  hash.reject { |key, _| key == reject_key }
126
209
  end
@@ -134,7 +217,7 @@ module DocBase
134
217
  end
135
218
 
136
219
  def connection_for_binary
137
- @connection ||= Faraday.new({ url: @url, headers: headers }) do |faraday|
220
+ @connection_for_binary ||= Faraday.new({ url: @url, headers: headers }) do |faraday|
138
221
  faraday.request :json
139
222
  faraday.adapter Faraday.default_adapter
140
223
  end
@@ -142,28 +225,35 @@ module DocBase
142
225
 
143
226
  def headers
144
227
  {
145
- 'Accept' => 'application/json',
146
- 'User-Agent' => USER_AGENT,
147
- 'X-DocBaseToken' => access_token,
148
- 'X-Api-Version' => '2',
228
+ 'Accept' => 'application/json',
229
+ 'User-Agent' => USER_AGENT,
149
230
  }
150
231
  end
151
232
 
152
233
  def request(method:, path:, params: nil, for_binary: false)
153
- response = for_binary ? connection_for_binary.send(method, path, params) : connection.send(method, path, params)
154
- raise TooManyRequestError if retry_on_rate_limit_exceeded && response.status == 429
155
- response
156
- rescue TooManyRequestError
157
- reset_time = response.headers['x-ratelimit-reset'].to_i
158
- puts "DocBase API Rate limit exceeded: will retry at #{Time.at(reset_time).strftime("%Y/%m/%d %H:%M:%S")}."
159
- wait_for(reset_time)
160
- retry
234
+ retries = 0
235
+ loop do
236
+ conn = for_binary ? connection_for_binary : connection
237
+ response = conn.send(method, path, params, 'X-DocBaseToken' => access_token)
238
+ return response unless retry_on_rate_limit_exceeded && response.status == 429
239
+
240
+ reset_time = rate_limit_reset_time(response)
241
+ return response if reset_time.nil? || retries >= MAX_RATE_LIMIT_RETRIES
242
+
243
+ retries += 1
244
+ wait_for(reset_time)
245
+ end
246
+ end
247
+
248
+ def rate_limit_reset_time(response)
249
+ reset_time = Integer(response.headers['x-ratelimit-reset'].to_s, exception: false)
250
+ reset_time if reset_time && reset_time > 0
161
251
  end
162
252
 
163
253
  def wait_for(reset_time)
164
- wait_time = reset_time - Time.now.to_i
165
- return if wait_time <= 0
166
- sleep wait_time
254
+ wait_time = (reset_time - Time.now.to_i).clamp(0, MAX_RATE_LIMIT_WAIT_SECONDS)
255
+ puts "DocBase API Rate limit exceeded: will retry at #{(Time.now + wait_time).strftime("%Y/%m/%d %H:%M:%S")}."
256
+ sleep wait_time if wait_time > 0
167
257
  end
168
258
  end
169
259
  end
@@ -1,3 +1,3 @@
1
1
  module DocBase
2
- VERSION = '2.1.2'
2
+ VERSION = '3.1.0'
3
3
  end
data/lib/docbase.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'base64'
2
2
  require 'faraday'
3
- require 'faraday_middleware'
4
3
  require 'docbase/version'
5
4
  require 'docbase/client'
metadata CHANGED
@@ -1,43 +1,48 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ttakuru88
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2021-05-11 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: faraday
13
+ name: base64
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 0.15.2
18
+ version: '0'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: 0.15.2
25
+ version: '0'
27
26
  - !ruby/object:Gem::Dependency
28
- name: faraday_middleware
27
+ name: faraday
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - ">="
32
31
  - !ruby/object:Gem::Version
33
- version: 0.12.2
32
+ version: 2.14.4
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '3'
34
36
  type: :runtime
35
37
  prerelease: false
36
38
  version_requirements: !ruby/object:Gem::Requirement
37
39
  requirements:
38
40
  - - ">="
39
41
  - !ruby/object:Gem::Version
40
- version: 0.12.2
42
+ version: 2.14.4
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '3'
41
46
  description: DocBase API Client, written in Ruby
42
47
  email:
43
48
  - asaumi+docbase-ruby@kray.jp
@@ -64,7 +69,6 @@ homepage: https://github.com/krayinc/docbase-ruby
64
69
  licenses:
65
70
  - MIT
66
71
  metadata: {}
67
- post_install_message:
68
72
  rdoc_options: []
69
73
  require_paths:
70
74
  - lib
@@ -79,8 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
83
  - !ruby/object:Gem::Version
80
84
  version: '0'
81
85
  requirements: []
82
- rubygems_version: 3.1.4
83
- signing_key:
86
+ rubygems_version: 4.0.20
84
87
  specification_version: 4
85
88
  summary: DocBase API Client, written in Ruby
86
89
  test_files: []