feishu-api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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