feishu-api 0.1.0 → 0.2.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: 13d0624f83504106d2aea9ab11e7f46ace5279b941b7c96d3b7079d46aa5192e
4
- data.tar.gz: 4cebc28b90e6dc24064b173e84f7b2ed4828c16ad88d662f3a80b3e54ccbd982
3
+ metadata.gz: 333130110a1c707a9e37a067af961e6608506ec4782d9fc691a9c7ff74885fd3
4
+ data.tar.gz: 792a76ba9109ee4399cc37cbb80b0a930dd19da5de110435a4ff3944deede8d7
5
5
  SHA512:
6
- metadata.gz: f3712e077e07abd86249f8e61743e849ffd07d0c8bf00e38c0f54d3603218888fc8e1ef5ff0a4d29b3f4836a27e19363d3e810f5dc80e4b15a5276e49ef4fe9b
7
- data.tar.gz: 24bfd38c27a267a439b912ebb313567695403396da4a71f07475509ee8faa220b3117fd1fc2b169942ca2bed558818f57a88e86f8b5abaa9e31290cc3ab78ac6
6
+ metadata.gz: 7090bd3836461e1f63fc4a541379ed236e0b8c6d318b3a29aca6d095625cc05e26ecef39339aa6da2514142bc6d6468e133c4aa46ec8e77e13023c054410aec7
7
+ data.tar.gz: 27a2edd16300e1da1dea63eb707f19c01148ae63f5c39703a304a09db583505efa56130b92405faeb32ddaa67d9fde11ae9de2439c2bd5819abd928a8ca646be
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
- # FeishuApi
1
+ # FeishuApi [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fatrox%2Fsync-dotenv%2Fbadge&label=build&logo=none)](https://actions-badge.atrox.dev/atrox/sync-dotenv/goto)
2
2
 
3
- FeishuApi is a integration of commonly used feishu open platform's APIs, easy to call.
3
+
4
+ FeishuApi is an integration of commonly used feishu open platform's APIs, easy to call.
5
+
6
+
7
+ English | [简体中文](./README-zh.md)
4
8
 
5
9
  ## Installation
6
10
 
@@ -12,6 +16,33 @@ If bundler is not being used to manage dependencies, install the gem by executin
12
16
 
13
17
  $ gem install feishu-api
14
18
 
19
+ ## Roadmap
20
+ - ✅ Messenger
21
+ - ✅ Group
22
+ - Docs
23
+ - Calendar
24
+ - Video Conferencing
25
+ - Rooms
26
+ - Attendance
27
+ - Approval
28
+ - Account
29
+ - Console
30
+ - Task
31
+ - Email
32
+ - App Information
33
+ - Company Information
34
+ - Search
35
+ - AI
36
+ - Admin
37
+ - HR
38
+ - OKR
39
+ - Real-name authentication
40
+ - Smart access control
41
+ - Enterprise Encyclopedia
42
+ - Contacts
43
+
44
+ ## Documentation
45
+ See detailed documentation at [feishu-api-doc](https://xiemala.com/s/DstEGj/feishu-api)
15
46
  ## Usage
16
47
 
17
48
  Add feishu-api.rb in config/initializers
@@ -8,6 +8,11 @@ module FeishuApi
8
8
  API_APP_ACCESS_TOKEN = '/auth/v3/app_access_token/internal'
9
9
  API_SEND_MESSAGES = '/im/v1/messages'
10
10
  API_CUSTOM_BOT_SEND = '/bot/v2/hook'
11
+ API_UPLOAD_IMAGE = '/im/v1/images'
12
+ API_UPLOAD_FILES = '/im/v1/files'
13
+ API_CHATS = '/im/v1/chats'
14
+ API_RESERVES = '/vc/v1/reserves'
15
+ API_MEETINGS = '/vc/v1/meetings'
11
16
 
12
17
  def api(interface)
13
18
  "#{API_HOST}#{interface}"
@@ -21,11 +26,74 @@ module FeishuApi
21
26
  verify: false)
22
27
  end
23
28
 
24
- def post_with_token(url, data, _timeout = 30)
25
- headers = { Authorization: "Bearer #{tenant_access_token}" }
26
- post(url,
27
- data,
28
- headers)
29
+ def post_with_token(url, data, headers = {}, timeout = 30)
30
+ HTTParty.post(api(url),
31
+ body: data,
32
+ headers: { Authorization: "Bearer #{tenant_access_token}" }.merge(headers),
33
+ timeout: timeout)
34
+ end
35
+
36
+ def post_with_user_token(url, user_access_token, data, headers = {}, timeout = 30)
37
+ HTTParty.post(api(url),
38
+ body: data,
39
+ headers: { Authorization: "Bearer #{user_access_token}" }.merge(headers),
40
+ timeout: timeout)
41
+ end
42
+
43
+ def get_with_token(url, data = {}, headers = {}, timeout = 30)
44
+ HTTParty.get(api(url),
45
+ body: data,
46
+ headers: { Authorization: "Bearer #{tenant_access_token}" }.merge(headers),
47
+ timeout: timeout)
48
+ end
49
+
50
+ def get_with_user_token(url, user_access_token, data = {}, headers = {}, timeout = 30)
51
+ HTTParty.get(api(url),
52
+ body: data,
53
+ headers: { Authorization: "Bearer #{user_access_token}" }.merge(headers),
54
+ timeout: timeout)
55
+ end
56
+
57
+ def put_with_token(url, data = {}, headers = {}, timeout = 30)
58
+ HTTParty.put(api(url),
59
+ body: data,
60
+ headers: { Authorization: "Bearer #{tenant_access_token}" }.merge(headers),
61
+ timeout: timeout)
62
+ end
63
+
64
+ def put_with_user_token(url, user_access_token, data = {}, headers = {}, timeout = 30)
65
+ HTTParty.put(api(url),
66
+ body: data,
67
+ headers: { Authorization: "Bearer #{user_access_token}" }.merge(headers),
68
+ timeout: timeout)
69
+ end
70
+
71
+ def delete_with_token(url, data = {}, headers = {}, timeout = 30)
72
+ HTTParty.delete(api(url),
73
+ body: data,
74
+ headers: { Authorization: "Bearer #{tenant_access_token}" }.merge(headers),
75
+ timeout: timeout)
76
+ end
77
+
78
+ def delete_with_user_token(url, user_access_token, data = {}, headers = {}, timeout = 30)
79
+ HTTParty.delete(api(url),
80
+ body: data,
81
+ headers: { Authorization: "Bearer #{user_access_token}" }.merge(headers),
82
+ timeout: timeout)
83
+ end
84
+
85
+ def patch_with_token(url, data = {}, headers = {}, timeout = 30)
86
+ HTTParty.patch(api(url),
87
+ body: data,
88
+ headers: { Authorization: "Bearer #{tenant_access_token}" }.merge(headers),
89
+ timeout: timeout)
90
+ end
91
+
92
+ def patch_with_user_token(url, user_access_token, data = {}, headers = {}, timeout = 30)
93
+ HTTParty.patch(api(url),
94
+ body: data,
95
+ headers: { Authorization: "Bearer #{user_access_token}" }.merge(headers),
96
+ timeout: timeout)
29
97
  end
30
98
 
31
99
  def tenant_access_token
@@ -61,6 +129,7 @@ module FeishuApi
61
129
  def send_message(receive_type, receive_id, msg_type, content)
62
130
  res = post_with_token("#{API_SEND_MESSAGES}?receive_id_type=#{receive_type}",
63
131
  { receive_id: receive_id, msg_type: msg_type, content: content })
132
+ # p res
64
133
  return nil if res.code != 200
65
134
 
66
135
  JSON.parse(res.body)
@@ -76,6 +145,210 @@ module FeishuApi
76
145
  send_message_by_group(receive_id, 'text', JSON.generate({ text: text }))
77
146
  end
78
147
 
148
+ # 上传图片
149
+ def upload_image(path)
150
+ post_with_token(API_UPLOAD_IMAGE.to_s, { image_type: 'message', image: File.new(path) },
151
+ { 'Content-Type' => 'multipart/formdata', 'Accept' => 'application/json' })
152
+ end
153
+
154
+ # 下载图片
155
+ def download_image(image_key)
156
+ get_with_token("#{API_UPLOAD_IMAGE}/#{image_key}")
157
+ end
158
+
159
+ # 上传文件
160
+ def upload_file(path, file_type)
161
+ post_with_token(API_UPLOAD_FILES.to_s,
162
+ { file_type: file_type, file_name: File.basename(path), file: File.new(path) },
163
+ { 'Content-Type' => 'multipart/formdata' })
164
+ end
165
+
166
+ # 下载文件
167
+ def download_file(file_key)
168
+ HTTParty.get("#{API_HOST}#{API_UPLOAD_FILES}/#{file_key}",
169
+ headers: { Authorization: "Bearer #{tenant_access_token}" })
170
+ end
171
+
172
+ # 发文件消息到指定群聊
173
+ def send_file_by_group(receive_id, file_key)
174
+ send_message_by_group(receive_id, 'file', JSON.generate({ file_key: file_key }))
175
+ end
176
+
177
+ # 撤回消息
178
+ def withdraw_message(message_id)
179
+ delete_with_token("#{API_SEND_MESSAGES}/#{message_id}")
180
+ end
181
+
182
+ # 查询消息已读信息
183
+ def check_reader(message_id)
184
+ get_with_token("#{API_SEND_MESSAGES}/#{message_id}/read_users?user_id_type=open_id")
185
+ end
186
+
187
+ # 发图片消息到指定群聊
188
+ def send_image_by_group(receive_id, image_key)
189
+ send_message_by_group(receive_id, 'image', JSON.generate({ image_key: image_key }))
190
+ end
191
+
192
+ # 回复消息
193
+ def reply_message(message_id)
194
+ post_with_token("#{API_SEND_MESSAGES}/#{message_id}/reply",
195
+ { content: '{"text":" test content"}', msg_type: 'text' })
196
+ end
197
+
198
+ # 获取会话(历史)消息
199
+ def get_chat_messages(container_id)
200
+ get_with_token("#{API_SEND_MESSAGES}?container_id_type=chat&container_id=#{container_id}")
201
+ end
202
+
203
+ # 获取指定消息的内容
204
+ def get_message_content(message_id)
205
+ get_with_token("#{API_SEND_MESSAGES}/#{message_id}")
206
+ end
207
+
208
+ # 发送应用内加急消息 (需要相关权限)
209
+ def send_urgent_app_message(message_id, user_id)
210
+ patch_with_token("#{API_SEND_MESSAGES}/#{message_id}/urgent_app?user_id_type=user_id",
211
+ { user_id_list: [user_id] })
212
+ end
213
+
214
+ # 添加消息表情回复
215
+ def add_message_reactions(message_id, emoji_type)
216
+ post_with_token("#{API_SEND_MESSAGES}/#{message_id}/reactions",
217
+ {
218
+ reaction_type: {
219
+ emoji_type: emoji_type.to_s
220
+ }
221
+ }.to_json, { 'Content-Type' => 'application/json' })
222
+ end
223
+
224
+ # 获取消息表情回复
225
+ def get_message_reactions(message_id)
226
+ get_with_token("#{API_SEND_MESSAGES}/#{message_id}/reactions")
227
+ end
228
+
229
+ # 删除消息表情回复
230
+ def delete_message_reactions(message_id)
231
+ delete_with_token("#{API_SEND_MESSAGES}/#{message_id}/reactions")
232
+ end
233
+
234
+ # 获取用户或者机器人所在群列表
235
+ def bot_chat_list
236
+ get_with_token(API_CHATS.to_s)
237
+ end
238
+
239
+ # 搜索对用户或机器人可见的群列表
240
+ def search_chat_list(query)
241
+ get_with_token("#{API_CHATS}/search?query=#{query}")
242
+ end
243
+
244
+ # 灵缇高级管家 chat_id:oc_31e9100a2673814ecba937f0772b8ebc
245
+ # 获取群成员发言权限
246
+ def get_member_permission(chat_id)
247
+ get_with_token("#{API_CHATS}/#{chat_id}/moderation")
248
+ end
249
+
250
+ # 更新群成员发言权限
251
+ def update_member_permission(chat_id)
252
+ put_with_token("#{API_CHATS}/#{chat_id}/moderation")
253
+ end
254
+
255
+ # 更新群置顶
256
+ def update_group_top_notice(chat_id, message_id)
257
+ post_with_token("#{API_CHATS}/#{chat_id}/top_notice/put_top_notice",
258
+ {
259
+ chat_top_notice: [
260
+ {
261
+ action_type: '1',
262
+ message_id: message_id.to_s
263
+ }
264
+ ]
265
+ }.to_json, { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
266
+ end
267
+
268
+ # 撤销群置顶
269
+ def delete_group_top_notice(chat_id)
270
+ delete_with_token("#{API_CHATS}/#{chat_id}/top_notice/delete_top_notice")
271
+ end
272
+
273
+ # 创建群
274
+ def create_group(name)
275
+ post_with_token(API_CHATS.to_s,
276
+ { name: name.to_s })
277
+ end
278
+
279
+ # 获取群信息
280
+ def get_group_info(chat_id)
281
+ get_with_token("#{API_CHATS}/#{chat_id}")
282
+ end
283
+
284
+ # 更新群信息
285
+ def update_group_info(chat_id, description)
286
+ put_with_token("#{API_CHATS}/#{chat_id}", { description: description.to_s })
287
+ end
288
+
289
+ # 解散群
290
+ def dissolve_group(chat_id)
291
+ delete_with_token("#{API_CHATS}/#{chat_id}")
292
+ end
293
+
294
+ # 将用户或机器人拉入群聊
295
+ def add_group_member(chat_id, id_list)
296
+ post_with_token("#{API_CHATS}/#{chat_id}/members",
297
+ { id_list: id_list }.to_json, { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
298
+ end
299
+
300
+ # 将用户或机器人移出群聊
301
+ def delete_group_member(chat_id, id_list)
302
+ delete_with_token("#{API_CHATS}/#{chat_id}/members",
303
+ { id_list: id_list }.to_json, { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
304
+ end
305
+
306
+ # 用户或机器人主动加入群聊
307
+ # 需要打开群设置:公开
308
+ def join_group(chat_id)
309
+ patch_with_token("#{API_CHATS}/#{chat_id}/members/me_join")
310
+ end
311
+
312
+ # 判断用户或机器人是否在群里
313
+ def member_is_in_chat(chat_id)
314
+ get_with_token("#{API_CHATS}/#{chat_id}/members/is_in_chat")
315
+ end
316
+
317
+ # 指定群管理员
318
+ def add_group_managers(chat_id, manager_ids)
319
+ post_with_token("#{API_CHATS}/#{chat_id}/managers/add_managers",
320
+ { manager_ids: manager_ids }.to_json, { 'Content-Type' => 'application/json' })
321
+ end
322
+
323
+ # 删除群管理员
324
+ def delete_group_managers(chat_id, manager_ids)
325
+ post_with_token("#{API_CHATS}/#{chat_id}/managers/delete_managers",
326
+ { manager_ids: manager_ids }.to_json, { 'Content-Type' => 'application/json' })
327
+ end
328
+
329
+ # 获取群成员列表
330
+ def get_group_members(chat_id)
331
+ get_with_token("#{API_CHATS}/#{chat_id}/members")
332
+ end
333
+
334
+ # 获取群公告信息
335
+ def get_group_announcement(chat_id)
336
+ get_with_token("#{API_CHATS}/#{chat_id}/announcement")
337
+ end
338
+
339
+ # 更新群公告信息
340
+ # rubocop:disable all
341
+ def update_group_announcement(chat_id)
342
+ patch_with_token("#{API_CHATS}/#{chat_id}/announcement",
343
+ {
344
+ "revision": "0",
345
+ "requests": [
346
+ "{\"requestType\":\"UpdateTitleRequestType\",\"updateTitleRequest\":{\"payload\":\"{\\\"elements\\\":[{\\\"type\\\":\\\"textRun\\\",\\\"textRun\\\":{\\\"text\\\":\\\"Updated Document Title\\\",\\\"style\\\":{}}}],\\\"style\\\":{}}\"}}"
347
+ ]
348
+ }.to_json, { 'Content-Type' => 'application/json'})
349
+ end
350
+ # rubocop:enable all
351
+
79
352
  # 通过邮箱识别用户, 发消息到指定用户
80
353
  def send_message_by_email(receive_id, msg_type, content)
81
354
  send_message('email', receive_id, msg_type, content)
@@ -89,6 +362,102 @@ module FeishuApi
89
362
  JSON.parse(res.body)
90
363
  end
91
364
 
365
+ # 预约会议
366
+ def reserve_meeting(token, end_time, check_list, topic)
367
+ post_with_user_token("#{API_RESERVES}/apply", token, {
368
+ end_time: Time.strptime(end_time, '%Y-%m-%d %H:%M:%S').to_i,
369
+ meeting_settings: {
370
+ topic: topic,
371
+ action_permissions: [
372
+ {
373
+ permission: 1,
374
+ permission_checkers: [
375
+ {
376
+ check_field: 1,
377
+ check_mode: 1,
378
+ check_list: check_list
379
+ }
380
+ ]
381
+ }
382
+ ],
383
+ meeting_initial_type: 1,
384
+ call_setting: {
385
+ callee: {
386
+ id: check_list[0],
387
+ user_type: 1,
388
+ pstn_sip_info: {
389
+ nickname: 'dodo',
390
+ main_address: '+86-02187654321'
391
+ }
392
+ }
393
+ },
394
+ auto_record: true
395
+ }
396
+ }.to_json, { 'Content-Type' => 'application/json' })
397
+ end
398
+
399
+ # 更新预约
400
+ def update_reserve(token, reserve_id, topic, check_list, end_time)
401
+ put_with_user_token("#{API_RESERVES}/#{reserve_id}", token,
402
+ {
403
+ end_time: Time.strptime(end_time, '%Y-%m-%d %H:%M:%S').to_i,
404
+ meeting_settings: {
405
+ topic: topic,
406
+ action_permissions: [
407
+ {
408
+ permission: 1,
409
+ permission_checkers: [
410
+ {
411
+ check_field: 1,
412
+ check_mode: 1,
413
+ check_list: check_list
414
+ }
415
+ ]
416
+ }
417
+ ],
418
+ meeting_initial_type: 1,
419
+ call_setting: {
420
+ callee: {
421
+ id: check_list[0],
422
+ user_type: 1,
423
+ pstn_sip_info: {
424
+ nickname: 'dodo',
425
+ main_address: '+86-02187654321'
426
+ }
427
+ }
428
+ },
429
+ auto_record: true
430
+ }
431
+ }.to_json, { 'Content-Type' => 'application/json' })
432
+ end
433
+
434
+ # 删除预约
435
+ def delete_reserve(token, reserve_id)
436
+ delete_with_user_token("#{API_RESERVES}/#{reserve_id}", token)
437
+ end
438
+
439
+ # 获取预约
440
+ def get_reserve_info(token, reserve_id)
441
+ get_with_user_token("#{API_RESERVES}/#{reserve_id}", token)
442
+ end
443
+
444
+ # 获取活跃会议
445
+ def get_active_meeting(token, reserve_id)
446
+ get_with_user_token("#{API_RESERVES}/#{reserve_id}/get_active_meeting", token)
447
+ end
448
+
449
+ # 获取会议详情
450
+ def get_meeting_info(meeting_id)
451
+ get_with_token("#{API_MEETINGS}/#{meeting_id}")
452
+ end
453
+
454
+ # 获取与会议号相关联的会议列表
455
+ def get_list_by_no(meeting_number, start_time, end_time)
456
+ end_time_unix = Time.strptime(end_time, '%Y-%m-%d %H:%M:%S').to_i
457
+ start_time_unix = Time.strptime(start_time, '%Y-%m-%d %H:%M:%S').to_i
458
+ get_with_token("#{API_MEETINGS}/list_by_no?end_time=#{end_time_unix}&start_time=#{start_time_unix}&meeting_no=#{meeting_number}")
459
+ end
460
+
92
461
  # 自定义机器人接口 发送文本消息
93
462
  def custom_robot_send_text(text, hook_id)
94
463
  custom_robot_send({
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FeishuApi
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feishu-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - msk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-15 00:00:00.000000000 Z
11
+ date: 2022-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty