wework 0.3.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -1
  3. data/README.md +7 -0
  4. data/lib/wework.rb +15 -10
  5. data/lib/wework/api/agent.rb +15 -79
  6. data/lib/wework/api/base.rb +24 -32
  7. data/lib/wework/api/contact.rb +1 -75
  8. data/lib/wework/api/corp.rb +29 -0
  9. data/lib/wework/api/methods/agent.rb +49 -0
  10. data/lib/wework/api/methods/approval.rb +16 -0
  11. data/lib/wework/api/methods/batch.rb +34 -0
  12. data/lib/wework/api/methods/checkin.rb +19 -0
  13. data/lib/wework/api/methods/department.rb +27 -0
  14. data/lib/wework/api/methods/media.rb +20 -0
  15. data/lib/wework/api/methods/menu.rb +21 -0
  16. data/lib/wework/api/methods/message.rb +52 -0
  17. data/lib/wework/api/methods/provider.rb +16 -0
  18. data/lib/wework/api/methods/suite.rb +53 -0
  19. data/lib/wework/api/methods/user.rb +35 -0
  20. data/lib/wework/api/provider.rb +13 -0
  21. data/lib/wework/api/suite.rb +72 -0
  22. data/lib/wework/cipher.rb +3 -0
  23. data/lib/wework/mock_api.rb +34 -0
  24. data/lib/wework/request.rb +3 -1
  25. data/lib/wework/token/app_token.rb +21 -0
  26. data/lib/wework/token/base.rb +59 -0
  27. data/lib/wework/token/corp_token.rb +20 -0
  28. data/lib/wework/token/js_ticket.rb +25 -0
  29. data/lib/wework/token/provider_token.rb +21 -0
  30. data/lib/wework/token/suite_token.rb +21 -0
  31. data/lib/wework/version.rb +1 -1
  32. data/mock_responses/agent/get.json +29 -0
  33. data/mock_responses/agent/list.json +16 -0
  34. data/mock_responses/agent/set.json +4 -0
  35. data/mock_responses/batch/getresult.json +8 -0
  36. data/mock_responses/department/list.json +24 -0
  37. data/mock_responses/error.json +4 -0
  38. data/mock_responses/files/party.csv +12 -0
  39. data/mock_responses/files/sample.amr +0 -0
  40. data/mock_responses/files/sample.mp4 +0 -0
  41. data/mock_responses/files/sample.txt +1 -0
  42. data/mock_responses/files/user.csv +2 -0
  43. data/mock_responses/files/zhiren.png +0 -0
  44. data/mock_responses/get_jsapi_ticket.json +6 -0
  45. data/mock_responses/gettoken.json +6 -0
  46. data/mock_responses/menu/get.json +24 -0
  47. data/mock_responses/service/get.json +0 -0
  48. data/mock_responses/service/get_corp_token.json +4 -0
  49. data/mock_responses/service/get_login_info.json +34 -0
  50. data/mock_responses/service/get_permanent_code.json +54 -0
  51. data/mock_responses/service/get_pre_auth_code.json +6 -0
  52. data/mock_responses/service/get_provider_token.json +4 -0
  53. data/mock_responses/service/get_suite_token.json +4 -0
  54. data/mock_responses/success.json +4 -0
  55. data/mock_responses/user/convert_to_openid.json +6 -0
  56. data/mock_responses/user/convert_to_userid.json +5 -0
  57. data/mock_responses/user/get.json +18 -0
  58. data/mock_responses/user/getuserdetail.json +10 -0
  59. data/mock_responses/user/getuserinfo.json +8 -0
  60. data/mock_responses/user/list.json +22 -0
  61. data/mock_responses/user/simplelist.json +11 -0
  62. data/wework.gemspec +6 -2
  63. metadata +114 -19
  64. data/lib/wework/engine.rb +0 -31
  65. data/lib/wework/js_ticket/redis_store.rb +0 -41
  66. data/lib/wework/js_ticket/store.rb +0 -36
  67. data/lib/wework/provider.rb +0 -39
  68. data/lib/wework/token/redis_store.rb +0 -41
  69. data/lib/wework/token/store.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0c98841b29ce00aabf378c3af49d92a9630154ef
4
- data.tar.gz: e3b52725ac3c261041b0ee6c8a29ef1ab925b213
2
+ SHA256:
3
+ metadata.gz: 9599e4575016ec45c4efe18b2e9d80cb27873f3cb8675ff379e7a1f9da774954
4
+ data.tar.gz: fc49b09c054faecde4feb2e9eab2754e39b6340b1a1be78b6ab81c3bc1260679
5
5
  SHA512:
6
- metadata.gz: 9214b0af6797808be69002d24daa4090e863a9854add081e61f6d817789e6627275b44ec2bbcf27451e72bea0afa9987ca446b7930e866c23e1814e95577c17f
7
- data.tar.gz: f9f43733cb23887ad7490862378bb567f38b898abf0aa99a25188a3ed6d0f0acca720041a64693ec789c3c241a29da780b3522224bc3cea61dbf3b46a48eafd0
6
+ metadata.gz: 54a4da5b3fcd4f14c58ecb1f95e44348b95f80b970fc4ddf9b15491e80db824bcf39763ecce2473379c41500f308c8b51056120a26c8a1b9ba51b4dd74245859
7
+ data.tar.gz: 557479ed57faeae92f92f9633ca3a68fa0584a8529e2cc1a54afa273f1fb64a2f3fdf66a4e79692c5aa0e34d7080979487ecf36c0985cda26758fb881e5816d6
data/.gitignore CHANGED
@@ -8,5 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  *.gem
11
- config.yml
12
11
  .DS_Store
data/README.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  Wework is a ruby API wrapper for work wechat.
4
4
 
5
+ [![CircleCI](https://circleci.com/gh/mycolorway/wework/tree/suite.svg?style=svg)](https://circleci.com/gh/mycolorway/wework/tree/suite)
6
+
7
+ ## Version 1.1.0
8
+ * 支持第三方应用接口
9
+ * 支持小程序接口
10
+
11
+
5
12
  ## Version 0.1.4
6
13
  * 异步任务接口 [doc](https://work.weixin.qq.com/api/doc#10138)
7
14
 
data/lib/wework.rb CHANGED
@@ -2,22 +2,27 @@ require 'redis'
2
2
  require 'active_support/all'
3
3
  #require 'active_support/core_ext/object/blank'
4
4
 
5
- Dir["#{File.dirname(__FILE__)}/wework/*.rb"].each do |path|
6
- require path
7
- end
5
+ LIB_PATH = "#{File.dirname(__FILE__)}/wework"
6
+ Dir["#{LIB_PATH}/api/methods/*.rb", "#{LIB_PATH}/token/*.rb"].each { |path| require path }
8
7
 
8
+ require 'wework/version'
9
+ require 'wework/cipher'
10
+ require 'wework/config'
9
11
  require 'wework/api/base'
10
12
  require 'wework/api/agent'
11
13
  require 'wework/api/contact'
14
+ require 'wework/api/suite'
15
+ require 'wework/api/corp'
16
+ require 'wework/api/provider'
17
+
12
18
 
13
19
  module Wework
14
- API_ENDPOINT = 'https://qyapi.weixin.qq.com/cgi-bin/'.freeze
15
- AUTHORIZE_ENDPOINT = 'https://open.weixin.qq.com/connect/oauth2/authorize'.freeze
16
- ACCESS_TOKEN_PREFIX = 'WX_TOKEN'.freeze
17
- JSAPI_TOKEN_PREFIX = 'WX_JST'.freeze
18
- CONTACT_AGENT_ID = 'CONTACT'.freeze
19
- HTTP_OK_STATUS = [200, 201].freeze
20
- SUCCESS_CODE = 0
20
+ API_ENDPOINT = 'https://qyapi.weixin.qq.com/cgi-bin/'.freeze
21
+ AUTHORIZE_ENDPOINT = 'https://open.weixin.qq.com/connect/oauth2/authorize'.freeze
22
+ SSO_AUTHORIZE_ENDPOINT = 'https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect'.freeze
23
+ APP_AUTHORIZE_ENDPOINT = 'https://open.work.weixin.qq.com/3rdapp/install'.freeze
24
+ HTTP_OK_STATUS = [200, 201].freeze
25
+ SUCCESS_CODE = 0
21
26
 
22
27
  # Exceptions
23
28
  class RedisNotConfigException < RuntimeError; end
@@ -1,94 +1,30 @@
1
- require "erb"
2
-
3
1
  module Wework
4
2
  module Api
5
3
  class Agent < Base
6
- # user agent: UA is mozilla/5.0 (iphone; cpu iphone os 10_2 like mac os x) applewebkit/602.3.12 (khtml, like gecko) mobile/14c92 wxwork/1.3.2 micromessenger/6.2
7
-
8
- def authorize_url(redirect_uri, scope="snsapi_base", state="wxwork")
9
- uri = ERB::Util.url_encode(redirect_uri)
10
- "#{AUTHORIZE_ENDPOINT}?appid=#{corp_id}&redirect_uri=#{uri}&response_type=code&scope=#{scope}&agentid=#{app_id}&state=#{state}#wechat_redirect"
11
- end
12
-
13
- def get_oauth_userinfo code
14
- get 'user/getuserinfo', params: {code: code}
15
- end
16
-
17
- def get_jssign_package url
18
- timestamp = Time.now.to_i
19
- noncestr = SecureRandom.hex(8)
20
- str = "jsapi_ticket=#{jsapi_ticket}&noncestr=#{noncestr}&timestamp=#{timestamp}&url=#{url}"
21
- {
22
- "appId" => corp_id,
23
- "nonceStr" => noncestr,
24
- "timestamp" => timestamp,
25
- "url" => url,
26
- "signature" => Digest::SHA1.hexdigest(str),
27
- "rawString" => str
28
- }
29
- end
30
-
31
- def get_info
32
- get 'agent/get', params: {agentid: agent_id}
33
- end
34
-
35
- def set_info data={}
36
- post 'agent/set', data.merge(agentid: agent_id)
37
- end
38
-
39
- def menu_create menu
40
- post 'menu/create', menu, params: {agentid: agent_id}
41
- end
42
-
43
- def menu_get
44
- get 'menu/get', params: {agentid: agent_id}
45
- end
46
-
47
- def menu_delete
48
- get 'menu/delete', params: {agentid: agent_id}
49
- end
50
-
51
- def message_send user_ids, department_ids, payload={}
52
- payload[:agentid] = agent_id
53
- payload[:touser] = Array.wrap(user_ids).join('|') if user_ids.present?
54
- payload[:toparty] = Array.wrap(department_ids).join('|') if department_ids.present?
55
- post 'message/send', payload
56
- end
57
-
58
- def text_message_send user_ids, department_ids, content
59
- message_send user_ids, department_ids, {text: {content: content}, msgtype: 'text'}
60
- end
61
4
 
62
- def image_message_send user_ids, department_ids, media_id
63
- message_send user_ids, department_ids, {image: {media_id: media_id}, msgtype: 'image'}
64
- end
65
-
66
- def voice_message_send user_ids, department_ids, media_id
67
- message_send user_ids, department_ids, {voice: {media_id: media_id}, msgtype: 'voice'}
68
- end
5
+ include Methods::Agent
6
+ include Methods::Message
7
+ include Methods::Menu
8
+ include Methods::Checkin
9
+ include Methods::Approval
69
10
 
70
- def file_message_send user_ids, department_ids, media_id
71
- message_send user_ids, department_ids, {file: {media_id: media_id}, msgtype: 'file'}
72
- end
11
+ attr_reader :agent_id
73
12
 
74
- def video_message_send user_ids, department_ids, video={}
75
- message_send user_ids, department_ids, {video: video, msgtype: 'video'}
13
+ def initialize(options={})
14
+ @agent_id = options.delete(:agent_id)
15
+ @agent_id = @agent_id.to_i if @agent_id && @agent_id.match?(/\A\d+\Z/)
16
+ super(options)
76
17
  end
77
18
 
78
- def textcard_message_send user_ids, department_ids, textcard={}
79
- message_send user_ids, department_ids, {textcard: textcard, msgtype: 'textcard'}
80
- end
81
-
82
- def news_message_send user_ids, department_ids, news=[]
83
- message_send user_ids, department_ids, {news: {articles: news}, msgtype: 'news'}
19
+ def jsapi_ticket
20
+ jsticket_store.ticket
84
21
  end
85
22
 
86
23
  private
87
24
 
88
- def agent_id
89
- @app_id.to_i
25
+ def jsticket_store
26
+ @jsticket_store ||= Token::JsTicket.new self
90
27
  end
91
-
92
28
  end
93
29
  end
94
- end
30
+ end
@@ -1,24 +1,19 @@
1
- require 'wework/token/store'
2
- require 'wework/token/redis_store'
3
-
4
- require 'wework/js_ticket/store'
5
- require 'wework/js_ticket/redis_store'
1
+ require 'wework/request'
6
2
 
7
3
  module Wework
8
4
  module Api
9
5
  class Base
10
- include Wework::Cipher
11
6
 
12
- attr_reader :corp_id, :app_id, :app_secret
13
- attr_accessor :options
7
+ include Methods::Media
8
+ include Methods::User
9
+ include Methods::Department
14
10
 
15
- delegate :access_token, to: :token_store
16
- delegate :jsapi_ticket, to: :jsticket_store
11
+ attr_accessor :corp_id, :secret, :options
17
12
 
18
- def initialize(corp_id, app_id, app_secret, options={})
19
- @corp_id = corp_id
20
- @app_id = app_id
21
- @app_secret = app_secret
13
+ def initialize options={}
14
+ @corp_id = options.delete(:corp_id)
15
+ @secret = options.delete(:secret)
16
+ @token_store = options.delete(:token_store)
22
17
  @options = options
23
18
  end
24
19
 
@@ -27,58 +22,55 @@ module Wework
27
22
  end
28
23
 
29
24
  def valid?
30
- access_token.present?
25
+ return false if corp_id.nil?
26
+ token_store.token.present?
31
27
  rescue AccessTokenExpiredError
32
28
  false
33
29
  rescue => e
34
- Rails.logger.error "[WEWORK] (valid?) fetch access token error(#{corp_id}##{app_id}): #{e.inspect}" if defined?(Rails)
30
+ Rails.logger.error "[WEWORK] (valid?) fetch access token error(#{corp_id}): #{e.inspect}" if defined?(Rails)
35
31
  false
36
32
  end
37
33
 
38
34
  def get(path, headers = {})
39
- with_access_token(headers[:params]) do |params|
35
+ with_token(headers[:params]) do |params|
40
36
  request.get path, headers.merge(params: params)
41
37
  end
42
38
  end
43
39
 
44
40
  def post(path, payload, headers = {})
45
- with_access_token(headers[:params]) do |params|
41
+ with_token(headers[:params]) do |params|
46
42
  request.post path, payload, headers.merge(params: params)
47
43
  end
48
44
  end
49
45
 
50
46
  def post_file(path, file, headers = {})
51
- with_access_token(headers[:params]) do |params|
47
+ with_token(headers[:params]) do |params|
52
48
  request.post_file path, file, headers.merge(params: params)
53
49
  end
54
50
  end
55
51
 
56
- # public API
57
- def media_upload type, file
58
- post_file 'media/upload', file, params: { type: type }
59
- end
60
-
61
- def media_get(media_id)
62
- get 'media/get', params: { media_id: media_id }, as: :file
52
+ def access_token
53
+ token_store.token
63
54
  end
64
55
 
65
56
  private
66
57
 
67
- def with_access_token(params = {}, tries = 2)
58
+ def with_token(params = {}, tries = 2)
68
59
  params ||= {}
69
- yield(params.merge(access_token: access_token))
60
+ yield(params.merge(token_params))
70
61
  rescue AccessTokenExpiredError
71
- token_store.refresh_token
62
+ token_store.update_token
72
63
  retry unless (tries -= 1).zero?
73
64
  end
74
65
 
75
66
  def token_store
76
- @token_store ||= Token::RedisStore.new self
67
+ @token_store ||= Token::AppToken.new self
77
68
  end
78
69
 
79
- def jsticket_store
80
- @jsticket_store ||= JsTicket::RedisStore.new self
70
+ def token_params
71
+ {access_token: access_token}
81
72
  end
73
+
82
74
  end
83
75
  end
84
76
  end
@@ -1,81 +1,7 @@
1
1
  module Wework
2
2
  module Api
3
3
  class Contact < Base
4
-
5
- def initialize(corp_id, corp_secret)
6
- super(corp_id, CONTACT_AGENT_ID, corp_secret)
7
- end
8
-
9
- def user_create data={}
10
- post 'user/create', data
11
- end
12
-
13
- def user_get userid
14
- get 'user/get', params: {userid: userid}
15
- end
16
-
17
- def user_update userid, data={}
18
- post 'user/update', data.merge(userid: userid)
19
- end
20
-
21
- def user_delete userid
22
- get 'user/delete', params: {userid: userid}
23
- end
24
-
25
- def user_batchdelete useridlist=[]
26
- post 'user/batchdelete', {useridlist: useridlist}
27
- end
28
-
29
- def user_simplelist department_id, fetch_child=0
30
- get 'user/simplelist', params: {department_id: department_id, fetch_child: fetch_child}
31
- end
32
-
33
- def user_list department_id, fetch_child=0
34
- get 'user/list', params: {department_id: department_id, fetch_child: fetch_child}
35
- end
36
-
37
- def department_create data={}
38
- post 'department/create', data
39
- end
40
-
41
- def department_update department_id, data={}
42
- post 'department/update', data.merge(id: department_id)
43
- end
44
-
45
- def department_delete department_id
46
- get 'department/delete', params: {id: department_id}
47
- end
48
-
49
- def department_list department_id=0
50
- get 'department/list', params: {id: department_id}
51
- end
52
-
53
- def batch_syncuser media_id, callback_url=nil, token=nil, encodingaeskey=nil
54
- post 'batch/syncuser', batch_params(media_id, callback_url, token, encodingaeskey)
55
- end
56
-
57
- def batch_replaceuser media_id, callback_url=nil, token=nil, encodingaeskey=nil
58
- post 'batch/replaceuser', batch_params(media_id, callback_url, token, encodingaeskey)
59
- end
60
-
61
- def batch_replaceparty media_id, callback_url=nil, token=nil, encodingaeskey=nil
62
- post 'batch/replaceparty', batch_params(media_id, callback_url, token, encodingaeskey)
63
- end
64
-
65
- def batch_getresult job_id
66
- get 'batch/getresult', params: {jobid: job_id}
67
- end
68
-
69
- private
70
-
71
- def batch_params media_id, callback_url, token, encodingaeskey
72
- params = {media_id: media_id}
73
- if callback_url.present? && token.present? && encodingaeskey.present?
74
- params[:callback] = {url: callback_url, token: token, encodingaeskey: encodingaeskey}
75
- end
76
-
77
- params
78
- end
4
+ include Methods::Batch
79
5
  end
80
6
  end
81
7
  end
@@ -0,0 +1,29 @@
1
+ module Wework
2
+ module Api
3
+ class Corp < Base
4
+
5
+ include Wework::Cipher
6
+ include Methods::User
7
+ include Methods::Department
8
+
9
+ attr_reader :suite, :permanent_code
10
+
11
+ def initialize(options={})
12
+ @suite = options.delete(:suite)
13
+ @permanent_code = options.delete(:permanent_code)
14
+ super(options)
15
+ end
16
+
17
+ def agent(agent_id)
18
+ Wework::Api::Agent.new(corp_id: corp_id, agent_id: agent_id, token_store: token_store)
19
+ end
20
+
21
+ private
22
+
23
+ def token_store
24
+ @token_store ||= Token::CorpToken.new self
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ require "erb"
2
+
3
+ module Wework
4
+ module Api
5
+ module Methods
6
+ module Agent
7
+ def authorize_url(redirect_uri, scope="snsapi_base", state="wxwork")
8
+ # user agent: UA is mozilla/5.0 (iphone; cpu iphone os 10_2 like mac os x) applewebkit/602.3.12 (khtml, like gecko) mobile/14c92 wxwork/1.3.2 micromessenger/6.2
9
+ uri = ERB::Util.url_encode(redirect_uri)
10
+ "#{AUTHORIZE_ENDPOINT}?appid=#{corp_id}&redirect_uri=#{uri}&response_type=code&scope=#{scope}&agentid=#{agent_id}&state=#{state}#wechat_redirect"
11
+ end
12
+
13
+ def get_oauth_userinfo code
14
+ get 'user/getuserinfo', params: {code: code}
15
+ end
16
+
17
+ def get_user_detail user_ticket
18
+ post 'user/getuserdetail', {user_ticket: user_ticket}
19
+ end
20
+
21
+ def get_jssign_package url
22
+ timestamp = Time.now.to_i
23
+ noncestr = SecureRandom.hex(8)
24
+ str = "jsapi_ticket=#{jsapi_ticket}&noncestr=#{noncestr}&timestamp=#{timestamp}&url=#{url}"
25
+ {
26
+ "appId" => corp_id,
27
+ "nonceStr" => noncestr,
28
+ "timestamp" => timestamp,
29
+ "url" => url,
30
+ "signature" => Digest::SHA1.hexdigest(str),
31
+ "rawString" => str
32
+ }
33
+ end
34
+
35
+ def get_session_with_jscode(js_code, grant_type='authorization_code')
36
+ post 'miniprogram/jscode2session', {}, params: {js_code: js_code, grant_type: grant_type}
37
+ end
38
+
39
+ def get_agent
40
+ get 'agent/get', params: {agentid: agent_id}
41
+ end
42
+
43
+ def set_agent data={}
44
+ post 'agent/set', data.merge(agentid: agent_id)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end