dingtalk 0.1.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +33 -0
- data/lib/dingtalk.rb +77 -0
- data/lib/dingtalk/api.rb +3 -0
- data/lib/dingtalk/api/department.rb +21 -0
- data/lib/dingtalk/api/message.rb +29 -0
- data/lib/dingtalk/api/microapp.rb +15 -0
- data/lib/dingtalk/api/user.rb +14 -0
- data/lib/dingtalk/client.rb +61 -0
- data/lib/dingtalk/config.rb +29 -0
- data/lib/dingtalk/eco_api.rb +3 -0
- data/lib/dingtalk/eco_api/role.rb +13 -0
- data/lib/dingtalk/handler.rb +3 -0
- data/lib/dingtalk/handler/eco_result_handler.rb +56 -0
- data/lib/dingtalk/handler/global_code.rb +319 -0
- data/lib/dingtalk/handler/result_handler.rb +37 -0
- data/lib/dingtalk/token/object_store.rb +25 -0
- data/lib/dingtalk/token/redis_store.rb +37 -0
- data/lib/dingtalk/token/store.rb +69 -0
- data/lib/dingtalk/version.rb +3 -0
- data/lib/tasks/dingtalk_tasks.rake +4 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5c09a5bf48e4218e9d13e279d06c8cfd48a86a2e
|
4
|
+
data.tar.gz: e9c87c1c241cd7720c842ef4f58050f63ba2ffce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da08a027f6ed2fb3a7fec2d742bba04ac2e2ec2065419bb8656ad79486896dfac7285d015aff1e7b7db78cd6428124a1fd264e664291d6da021723091b151cbe
|
7
|
+
data.tar.gz: ecd25008d1d7344ffe2b6f160a5edf770b460ac2c7c70f5de95e2a3043028f6b8c07558b67ddc7479a9b273831d2578d6c29f35461ac6941706bb622348a8cde
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 ysllyfe
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Dingtalk
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'dingtalk'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install dingtalk
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Dingtalk'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/**/*_test.rb'
|
29
|
+
t.verbose = false
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
task default: :test
|
data/lib/dingtalk.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require "rest-client"
|
2
|
+
require "redis"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
require "dingtalk/version"
|
6
|
+
require "dingtalk/config"
|
7
|
+
require "dingtalk/handler"
|
8
|
+
require "dingtalk/api"
|
9
|
+
require "dingtalk/eco_api"
|
10
|
+
require "dingtalk/client"
|
11
|
+
|
12
|
+
module Dingtalk
|
13
|
+
|
14
|
+
module Token
|
15
|
+
autoload(:Store, "dingtalk/token/store")
|
16
|
+
autoload(:ObjectStore, "dingtalk/token/object_store")
|
17
|
+
autoload(:RedisStore, "dingtalk/token/redis_store")
|
18
|
+
end
|
19
|
+
|
20
|
+
OK_MSG = "ok".freeze
|
21
|
+
OK_CODE = 0.freeze
|
22
|
+
CUSTOM_ENDPOINT = "custom_endpoint".freeze
|
23
|
+
ECO_ENDPOINT = 'eco'.freeze
|
24
|
+
|
25
|
+
class << self
|
26
|
+
attr_accessor :current_endpoint
|
27
|
+
|
28
|
+
def eco?
|
29
|
+
@current_endpoint == ECO_ENDPOINT
|
30
|
+
end
|
31
|
+
|
32
|
+
def http_get_without_token(url, url_params={}, endpoint="api")
|
33
|
+
@current_endpoint = endpoint
|
34
|
+
load_json(resource(url).get(params: url_params), url)
|
35
|
+
end
|
36
|
+
|
37
|
+
def http_post_without_token(url, _post_body={}, url_params={}, endpoint="api")
|
38
|
+
@current_endpoint = endpoint
|
39
|
+
load_json(resource(url).post(JSON.dump(_post_body), params: url_params, content_type: :json), url)
|
40
|
+
end
|
41
|
+
|
42
|
+
def resource(url)
|
43
|
+
RestClient::Resource.new(endpoint_url(url), rest_client_options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_json(string, url)
|
47
|
+
result_hash = JSON.parse(string.force_encoding("UTF-8").gsub(/[\u0011-\u001F]/, ""))
|
48
|
+
if eco?
|
49
|
+
EcoResultHandler.new(url, result_hash)
|
50
|
+
else
|
51
|
+
code = result_hash.delete("errcode")
|
52
|
+
en_msg = result_hash.delete("errmsg")
|
53
|
+
ResultHandler.new(code, en_msg, result_hash)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def endpoint_url(url)
|
58
|
+
if eco?
|
59
|
+
eco_endpoint
|
60
|
+
else
|
61
|
+
"#{api_endpoint}" + url
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def api_endpoint
|
66
|
+
"https://oapi.dingtalk.com"
|
67
|
+
end
|
68
|
+
|
69
|
+
def eco_endpoint
|
70
|
+
"https://eco.taobao.com/router/rest"
|
71
|
+
end
|
72
|
+
|
73
|
+
def calculate_expire(expires_in)
|
74
|
+
Time.now.to_i + expires_in.to_i - key_expired.to_i
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/dingtalk/api.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module Api
|
3
|
+
module Department
|
4
|
+
# https://oapi.dingtalk.com/department/list?access_token=ACCESS_TOKEN
|
5
|
+
def list_department
|
6
|
+
list_url = "#{department_base_url}/list"
|
7
|
+
http_get(list_url)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_department(id)
|
11
|
+
get_url = "#{department_base_url}/get"
|
12
|
+
http_get(get_url, {id: id})
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def department_base_url
|
17
|
+
"/department"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module Api
|
3
|
+
module Message
|
4
|
+
def send_text(to_users = [], agentid = nil, message)
|
5
|
+
send_message(to_users, agentid, :msgtype => "text", :text => { :content => message})
|
6
|
+
end
|
7
|
+
|
8
|
+
def send_link(to_users = [], agentid = nil, opts = {})
|
9
|
+
# opts :messageUrl=>"",:picUrl=>"",:title=>"",:text=>""
|
10
|
+
send_message(to_users, agentid, :msgtype => "link", :link => opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def send_oa(to_users = [], agentid = nil)
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def send_message(to_users = [], agentid = nil, opts = {})
|
19
|
+
url = "#{message_base_url}/send"
|
20
|
+
body = {:touser=>to_users.join('|'), :agentid=>agentid}.merge(opts)
|
21
|
+
http_post(url, body)
|
22
|
+
end
|
23
|
+
|
24
|
+
def message_base_url
|
25
|
+
"/message"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module Api
|
3
|
+
module Microapp
|
4
|
+
def microapp_visible_scopes(agent_id)
|
5
|
+
url = "#{microapp_base_url}/visible_scopes"
|
6
|
+
http_post(url, {agentid: agent_id})
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def microapp_base_url
|
11
|
+
"/microapp"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module Api
|
3
|
+
module User
|
4
|
+
def user_simplelist(department_id, opt={})
|
5
|
+
simplelist_url = "#{user_base_url}/simplelist"
|
6
|
+
http_get(simplelist_url, opt.merge(department_id: department_id))
|
7
|
+
end
|
8
|
+
private
|
9
|
+
def user_base_url
|
10
|
+
"/user"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "monitor"
|
2
|
+
require "redis"
|
3
|
+
require 'digest/md5'
|
4
|
+
module Dingtalk
|
5
|
+
class Client
|
6
|
+
include MonitorMixin
|
7
|
+
include Api::Department
|
8
|
+
include Api::User
|
9
|
+
include Api::Microapp
|
10
|
+
include Api::Message
|
11
|
+
|
12
|
+
include EcoApi::Role
|
13
|
+
|
14
|
+
attr_accessor :app_id, :app_secret, :expired_at # Time.now + expires_in
|
15
|
+
attr_accessor :access_token, :redis_key
|
16
|
+
|
17
|
+
def initialize(app_id, app_secret, options={})
|
18
|
+
@app_id = app_id
|
19
|
+
@app_secret = app_secret
|
20
|
+
@expired_at = Time.now.to_i
|
21
|
+
@redis_key = security_redis_key(options[:redis_key] || "dingtalk_#{app_id}")
|
22
|
+
super()
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_access_token
|
26
|
+
synchronize{ token_store.access_token }
|
27
|
+
end
|
28
|
+
|
29
|
+
def is_valid?
|
30
|
+
token_store.valid?
|
31
|
+
end
|
32
|
+
|
33
|
+
def token_store
|
34
|
+
Token::Store.init_with(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def http_get(url, url_params={}, endpoint="plain")
|
38
|
+
url_params = endpoint == Dingtalk::ECO_ENDPOINT ? url_params.merge(eco_access_token_param) : url_params.merge(access_token_param)
|
39
|
+
Dingtalk.http_get_without_token(url, url_params, endpoint)
|
40
|
+
end
|
41
|
+
|
42
|
+
def http_post(url, post_body={}, url_params={}, endpoint="plain")
|
43
|
+
url_params = endpoint == Dingtalk::ECO_ENDPOINT ? eco_access_token_param.merge(url_params) : access_token_param.merge(url_params)
|
44
|
+
Dingtalk.http_post_without_token(url, post_body, url_params, endpoint)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def eco_access_token_param
|
50
|
+
{session: get_access_token, timestamp: Time.now.strftime("%Y-%m-%d %H:%M:%S"), format: 'json', v: '2.0'}
|
51
|
+
end
|
52
|
+
|
53
|
+
def access_token_param
|
54
|
+
{access_token: get_access_token}
|
55
|
+
end
|
56
|
+
|
57
|
+
def security_redis_key(key)
|
58
|
+
Digest::MD5.hexdigest(key.to_s).upcase
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
class << self
|
3
|
+
attr_accessor :config
|
4
|
+
def configure
|
5
|
+
yield self.config ||= Config.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def redis
|
9
|
+
return nil if config.nil?
|
10
|
+
@redis ||= config.redis
|
11
|
+
end
|
12
|
+
|
13
|
+
def key_expired
|
14
|
+
return 100 if config.nil?
|
15
|
+
config.key_expired || 100
|
16
|
+
end
|
17
|
+
|
18
|
+
def rest_client_options
|
19
|
+
if config.nil?
|
20
|
+
return {timeout: 5, open_timeout: 5, verify_ssl: true}
|
21
|
+
end
|
22
|
+
config.rest_client_options
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Config
|
27
|
+
attr_accessor :redis, :rest_client_options, :key_expired
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module EcoApi
|
3
|
+
module Role
|
4
|
+
def role_list
|
5
|
+
http_get('dingtalk.corp.role.list', {method: 'dingtalk.corp.role.list'}, 'eco')
|
6
|
+
end
|
7
|
+
|
8
|
+
def role_simplelist(role_id)
|
9
|
+
http_get('dingtalk.corp.role.simplelist', {method: 'dingtalk.corp.role.simplelist', role_id: role_id}, 'eco')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
class EcoResultHandler
|
3
|
+
attr_accessor :code, :cn_msg, :en_msg, :result, :response_name
|
4
|
+
|
5
|
+
def initialize(m, response={})
|
6
|
+
@response_name = "#{m.gsub(/\./, '_')}_response"
|
7
|
+
@response = package_result(response)
|
8
|
+
@result = @response[@response_name]
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_ok?
|
12
|
+
@response[:error_response].nil?
|
13
|
+
end
|
14
|
+
alias_method :ok?, :is_ok?
|
15
|
+
|
16
|
+
def code
|
17
|
+
@response[:error_response][:code]
|
18
|
+
end
|
19
|
+
|
20
|
+
def en_msg
|
21
|
+
@response[:error_response][:msg]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cn_msg
|
25
|
+
@response[:error_response][:sub_msg]
|
26
|
+
end
|
27
|
+
|
28
|
+
def sub_code
|
29
|
+
@response[:error_response][:sub_code]
|
30
|
+
end
|
31
|
+
|
32
|
+
def full_message
|
33
|
+
if is_ok?
|
34
|
+
"SUCCESS, Please use #result to get result."
|
35
|
+
else
|
36
|
+
"#{code}: #{en_msg}(#{sub_code}:#{cn_msg})."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
alias_method :full_messages, :full_message
|
40
|
+
|
41
|
+
def full_error_message
|
42
|
+
full_message if !is_ok?
|
43
|
+
end
|
44
|
+
alias_method :full_error_messages, :full_error_message
|
45
|
+
|
46
|
+
private
|
47
|
+
def package_result(response)
|
48
|
+
return response if !response.is_a?(Hash)
|
49
|
+
if defined?(Rails)
|
50
|
+
ActiveSupport::HashWithIndifferentAccess.new(response)
|
51
|
+
else
|
52
|
+
response
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
GLOBAL_CODES = {
|
3
|
+
-1 => "系统繁忙",
|
4
|
+
0 => "请求成功",
|
5
|
+
404 => "请求的URI地址不存在",
|
6
|
+
33001 => "无效的企业ID",
|
7
|
+
33002 => "无效的微应用的名称",
|
8
|
+
33003 => "无效的微应用的描述",
|
9
|
+
33004 => "无效的微应用的ICON",
|
10
|
+
33005 => "无效的微应用的移动端主页",
|
11
|
+
33006 => "无效的微应用的PC端主页",
|
12
|
+
33007 => "微应用的移动端的主页与PC端主页不同",
|
13
|
+
33008 => "无效的微应用OA后台的主页",
|
14
|
+
34001 => "无效的会话id",
|
15
|
+
34002 => "无效的会话消息的发送者",
|
16
|
+
34003 => "无效的会话消息的发送者的企业Id",
|
17
|
+
34004 => "无效的会话消息的类型",
|
18
|
+
34005 => "无效的会话音频消息的播放时间",
|
19
|
+
34006 => "发送者不在企业中",
|
20
|
+
34007 => "发送者不在会话中",
|
21
|
+
34008 => "图片不能为空",
|
22
|
+
34009 => "链接内容不能为空",
|
23
|
+
34010 => "文件不能为空",
|
24
|
+
34011 => "音频文件不能为空",
|
25
|
+
34012 => "找不到发送者的企业",
|
26
|
+
34013 => "找不到群会话对象",
|
27
|
+
34014 => "会话消息的json结构无效或不完整",
|
28
|
+
34015 => "发送群会话消息失败",
|
29
|
+
34016 => "消息内容长度超过限制",
|
30
|
+
40001 => "获取access_token时Secret错误,或者access_token无效",
|
31
|
+
40002 => "不合法的凭证类型",
|
32
|
+
40003 => "不合法的UserID",
|
33
|
+
40004 => "不合法的媒体文件类型",
|
34
|
+
40005 => "不合法的文件类型",
|
35
|
+
40006 => "不合法的文件大小",
|
36
|
+
40007 => "不合法的媒体文件id",
|
37
|
+
40008 => "不合法的消息类型",
|
38
|
+
40009 => "不合法的部门id",
|
39
|
+
40010 => "不合法的父部门id",
|
40
|
+
40011 => "不合法的排序order",
|
41
|
+
40012 => "不合法的发送者",
|
42
|
+
40013 => "不合法的corpid",
|
43
|
+
40014 => "不合法的access_token",
|
44
|
+
40015 => "发送者不在会话中",
|
45
|
+
40016 => "不合法的会话ID",
|
46
|
+
40017 => "在会话中没有找到与发送者在同一企业的人",
|
47
|
+
40018 => "不允许以递归方式查询部门用户列表",
|
48
|
+
40019 => "该手机号码对应的用户最多可以加入5个非认证企业",
|
49
|
+
40020 => "当前团队人数已经达到上限,用电脑登录钉钉企业管理后台,升级成为认证企业",
|
50
|
+
40021 => "更换的号码已注册过钉钉,无法使用该号码",
|
51
|
+
40022 => "企业中的手机号码和登陆钉钉的手机号码不一致,暂时不支持修改用户信息,可以删除后重新添加",
|
52
|
+
40023 => "部门人数达到上限",
|
53
|
+
40024 => "(安全校验不通过)保存失败,团队人数超限。请在手机钉钉绑定支付宝完成实名认证,或者申请企业认证,人数上限自动扩充。",
|
54
|
+
40025 => "无效的部门JSONArray对象,合法格式需要用中括号括起来,且如果属于多部门,部门id需要用逗号分隔",
|
55
|
+
40029 => "不合法的oauth_code",
|
56
|
+
40031 => "不合法的UserID列表",
|
57
|
+
40032 => "不合法的UserID列表长度",
|
58
|
+
40033 => "不合法的请求字符,不能包含\\uxxxx格式的字符",
|
59
|
+
40035 => "不合法的参数",
|
60
|
+
40038 => "不合法的请求格式",
|
61
|
+
40039 => "不合法的URL长度",
|
62
|
+
40048 => "url中包含不合法domain",
|
63
|
+
40055 => "不合法的agent结构",
|
64
|
+
40056 => "不合法的agentid",
|
65
|
+
40057 => "不合法的callbackurl",
|
66
|
+
40061 => "设置应用头像失败",
|
67
|
+
40062 => "不合法的应用模式",
|
68
|
+
40063 => "不合法的分机号",
|
69
|
+
40064 => "不合法的工作地址",
|
70
|
+
40065 => "不合法的备注",
|
71
|
+
40066 => "不合法的部门列表",
|
72
|
+
40067 => "标题长度不合法",
|
73
|
+
40068 => "不合法的偏移量",
|
74
|
+
40069 => "不合法的分页大小",
|
75
|
+
40070 => "不合法的排序参数",
|
76
|
+
40073 => "不存在的openid",
|
77
|
+
40077 => "不存在的预授权码",
|
78
|
+
40078 => "不存在的临时授权码",
|
79
|
+
40079 => "不存在的授权信息",
|
80
|
+
40080 => "不合法的suitesecret",
|
81
|
+
40082 => "不合法的suitetoken",
|
82
|
+
40083 => "不合法的suiteid",
|
83
|
+
40084 => "不合法的永久授权码",
|
84
|
+
40085 => "不存在的suiteticket",
|
85
|
+
40086 => "不合法的第三方应用appid",
|
86
|
+
40087 => "创建永久授权码失败",
|
87
|
+
40088 => "不合法的套件key或secret",
|
88
|
+
40089 => "不合法的corpid或corpsecret",
|
89
|
+
40090 => "套件已经不存在",
|
90
|
+
40091 => "用户授权码创建失败,需要用户重新授权",
|
91
|
+
41001 => "缺少access_token参数",
|
92
|
+
41002 => "缺少corpid参数",
|
93
|
+
41003 => "缺少refresh_token参数",
|
94
|
+
41004 => "缺少secret参数",
|
95
|
+
41005 => "缺少多媒体文件数据",
|
96
|
+
41006 => "缺少media_id参数",
|
97
|
+
41007 => "无效的ssocode",
|
98
|
+
41008 => "缺少oauth",
|
99
|
+
41009 => "缺少UserID",
|
100
|
+
41010 => "缺少url",
|
101
|
+
41011 => "缺少agentid",
|
102
|
+
41012 => "缺少应用头像mediaid",
|
103
|
+
41013 => "缺少应用名字",
|
104
|
+
41014 => "缺少应用描述",
|
105
|
+
41015 => "缺少Content",
|
106
|
+
41016 => "缺少标题",
|
107
|
+
41021 => "缺少suitekey",
|
108
|
+
41022 => "缺少suitetoken",
|
109
|
+
41023 => "缺少suiteticket",
|
110
|
+
41024 => "缺少suitesecret",
|
111
|
+
41025 => "缺少permanent_code",
|
112
|
+
41026 => "缺少tmp_auth_code",
|
113
|
+
41027 => "需要授权企业的corpid参数",
|
114
|
+
41028 => "禁止给全员发送消息",
|
115
|
+
41029 => "超过消息接收者人数上限",
|
116
|
+
41030 => "企业未对该套件授权",
|
117
|
+
41031 => "auth_corpid和permanent_code不匹配",
|
118
|
+
41044 => "禁止发送消息",
|
119
|
+
41045 => "超过发送全员消息的次数上限",
|
120
|
+
41046 => "超过发送全员消息的每分钟次数上限",
|
121
|
+
41047 => "超过给该企业发消息的每分钟次数上限",
|
122
|
+
41048 => "超过给企业发消息的每分钟次数总上限",
|
123
|
+
41049 => "包含违禁内容",
|
124
|
+
41050 => "无效的活动编码",
|
125
|
+
41051 => "活动权益的校验失败",
|
126
|
+
41100 => "时间参数不合法",
|
127
|
+
41101 => "数据内容过长",
|
128
|
+
41102 => "参数值过大",
|
129
|
+
42001 => "access_token超时",
|
130
|
+
42002 => "refresh_token超时",
|
131
|
+
42003 => "oauth_code超时",
|
132
|
+
42007 => "预授权码失效",
|
133
|
+
42008 => "临时授权码失效",
|
134
|
+
42009 => "suitetoken失效",
|
135
|
+
43001 => "需要GET请求",
|
136
|
+
43002 => "需要POST请求",
|
137
|
+
43003 => "需要HTTPS",
|
138
|
+
43004 => "无效的HTTP HEADER Content-Type",
|
139
|
+
43005 => "需要Content-Type为application/json;charset=UTF-8",
|
140
|
+
43007 => "需要授权",
|
141
|
+
43008 => "参数需要multipart类型",
|
142
|
+
43009 => "post参数需要json类型",
|
143
|
+
43010 => "需要处于回调模式",
|
144
|
+
43011 => "需要企业授权",
|
145
|
+
44001 => "多媒体文件为空",
|
146
|
+
44002 => "POST的数据包为空",
|
147
|
+
44003 => "图文消息内容为空",
|
148
|
+
44004 => "文本消息内容为空",
|
149
|
+
45001 => "多媒体文件大小超过限制",
|
150
|
+
45002 => "消息内容超过限制",
|
151
|
+
45003 => "标题字段超过限制",
|
152
|
+
45004 => "描述字段超过限制",
|
153
|
+
45005 => "链接字段超过限制",
|
154
|
+
45006 => "图片链接字段超过限制",
|
155
|
+
45007 => "语音播放时间超过限制",
|
156
|
+
45008 => "图文消息超过限制",
|
157
|
+
45009 => "接口调用超过限制",
|
158
|
+
45016 => "系统分组,不允许修改",
|
159
|
+
45017 => "分组名字过长",
|
160
|
+
45018 => "分组数量超过上限",
|
161
|
+
45024 => "账号数量超过上限",
|
162
|
+
46001 => "不存在媒体数据",
|
163
|
+
46004 => "不存在的员工",
|
164
|
+
47001 => "解析JSON/XML内容错误",
|
165
|
+
48002 => "Api禁用",
|
166
|
+
48003 => "suitetoken无效",
|
167
|
+
48004 => "授权关系无效",
|
168
|
+
49000 => "缺少chatid",
|
169
|
+
49001 => "绑定的微应用超过个数限制",
|
170
|
+
49002 => "一个群只能被一个ISV套件绑定一次",
|
171
|
+
49003 => "操作者必须为群主",
|
172
|
+
49004 => "添加成员列表和删除成员列表不能有交集",
|
173
|
+
49005 => "群人数超过人数限制",
|
174
|
+
49006 => "群成员列表必须包含群主",
|
175
|
+
49007 => "超过创建群的个数上限",
|
176
|
+
50001 => "redirect_uri未授权",
|
177
|
+
50002 => "员工不在权限范围",
|
178
|
+
50003 => "应用已停用",
|
179
|
+
50005 => "企业已禁用",
|
180
|
+
51000 => "跳转的域名未授权",
|
181
|
+
51001 => "跳转的corpid未授权",
|
182
|
+
51002 => "跳转请求不是来自钉钉客户端",
|
183
|
+
51003 => "跳转找不到用户信息",
|
184
|
+
51004 => "跳转找不到用户的企业信息",
|
185
|
+
51005 => "跳转用户不是企业管理员",
|
186
|
+
51006 => "跳转生成code失败",
|
187
|
+
51007 => "跳转获取用户企业身份失败",
|
188
|
+
51008 => "跳转url解码失败",
|
189
|
+
51009 => "要跳转的地址不是标准url",
|
190
|
+
52010 => "无效的corpid",
|
191
|
+
52011 => "jsapi ticket 读取失败",
|
192
|
+
52012 => "jsapi 签名生成失败",
|
193
|
+
52013 => "签名校验失败",
|
194
|
+
52014 => "无效的url参数",
|
195
|
+
52015 => "无效的随机字符串参数",
|
196
|
+
52016 => "无效的签名参数",
|
197
|
+
52017 => "无效的jsapi列表参数",
|
198
|
+
52018 => "无效的时间戳",
|
199
|
+
52019 => "无效的agentid",
|
200
|
+
60001 => "不合法的部门名称",
|
201
|
+
60002 => "部门层级深度超过限制",
|
202
|
+
60003 => "部门不存在",
|
203
|
+
60004 => "父亲部门不存在",
|
204
|
+
60005 => "不允许删除有成员的部门",
|
205
|
+
60006 => "不允许删除有子部门的部门",
|
206
|
+
60007 => "不允许删除根部门",
|
207
|
+
60008 => "父部门下该部门名称已存在",
|
208
|
+
60009 => "部门名称含有非法字符",
|
209
|
+
60010 => "部门存在循环关系",
|
210
|
+
60011 => "管理员权限不足,(user/department/agent)无权限",
|
211
|
+
60012 => "不允许删除默认应用",
|
212
|
+
60013 => "不允许关闭应用",
|
213
|
+
60014 => "不允许开启应用",
|
214
|
+
60015 => "不允许修改默认应用可见范围",
|
215
|
+
60016 => "部门id已经存在",
|
216
|
+
60017 => "不允许设置企业",
|
217
|
+
60018 => "不允许更新根部门",
|
218
|
+
60019 => "从部门查询人员失败",
|
219
|
+
60020 => "访问ip不在白名单之中",
|
220
|
+
60066 => "企业的设置不存在",
|
221
|
+
60067 => "部门的企业群群主不存在",
|
222
|
+
60068 => "部门的管理员不存在",
|
223
|
+
60102 => "UserID在公司中已存在",
|
224
|
+
60103 => "手机号码不合法",
|
225
|
+
60104 => "手机号码在公司中已存在",
|
226
|
+
60105 => "邮箱不合法",
|
227
|
+
60106 => "邮箱已存在",
|
228
|
+
60107 => "使用该手机登录钉钉的用户已经在企业中",
|
229
|
+
60110 => "部门个数超出限制",
|
230
|
+
60111 => "UserID不存在",
|
231
|
+
60112 => "用户name不合法",
|
232
|
+
60113 => "身份认证信息(手机/邮箱)不能同时为空",
|
233
|
+
60114 => "性别不合法",
|
234
|
+
60118 => "用户无有效邀请字段(邮箱,手机号)",
|
235
|
+
60119 => "不合法的position",
|
236
|
+
60120 => "用户已禁用",
|
237
|
+
60121 => "找不到该用户",
|
238
|
+
60122 => "不合法的extattr",
|
239
|
+
60123 => "不合法的jobnumber",
|
240
|
+
60124 => "用户不在此群中",
|
241
|
+
60125 => "CRM配置信息创建失败",
|
242
|
+
60126 => "CRM配置信息更新失败",
|
243
|
+
60127 => "CRM人员配置信息删除失败",
|
244
|
+
70001 => "企业不存在或者已经被解散",
|
245
|
+
70002 => "获取套件下的微应用失败",
|
246
|
+
70003 => "agentid对应微应用不存在",
|
247
|
+
70004 => "企业下没有对应该agentid的微应用",
|
248
|
+
70005 => "ISV激活套件失败",
|
249
|
+
71006 => "回调地址已经存在",
|
250
|
+
71007 => "回调地址已不存在",
|
251
|
+
71008 => "回调call_back_tag必须在指定的call_back_tag列表中",
|
252
|
+
71009 => "返回文本非success",
|
253
|
+
71010 => "POST的JSON数据不包含所需要的参数字段或包含的参数格式非法",
|
254
|
+
71011 => "传入的url参数不是合法的url格式",
|
255
|
+
71012 => "url地址访问异常,错误原因为:%s",
|
256
|
+
71013 => "此域名或IP不能注册或者接收回调事件",
|
257
|
+
72001 => "获取钉盘空间失败",
|
258
|
+
72002 => "授权钉盘空间访问权限失败",
|
259
|
+
80001 => "可信域名没有IPC备案,后续将不能在该域名下正常使用jssdk",
|
260
|
+
81001 => "两个用户没有任何关系,请先相互成为好友",
|
261
|
+
81002 => "用户拒收消息",
|
262
|
+
88005 => "管理日历个人日历操作失败",
|
263
|
+
89001 => "管理日历启动导出任务失败",
|
264
|
+
89011 => "管理日历写入数据失败",
|
265
|
+
89012 => "管理日历更新数据失败",
|
266
|
+
90001 => "您的服务器调用钉钉开放平台所有接口的请求都被暂时禁用了",
|
267
|
+
90002 => "您的服务器调用钉钉开放平台当前接口的所有请求都被暂时禁用了",
|
268
|
+
90003 => "您的企业调用钉钉开放平台所有接口的请求都被暂时禁用了,仅对企业自己的Accesstoken有效",
|
269
|
+
90004 => "您当前使用的CorpId及CorpSecret被暂时禁用了,仅对企业自己的Accesstoken有效",
|
270
|
+
90005 => "您的企业调用当前接口次数过多,请求被暂时禁用了,仅对企业自己的Accesstoken有效",
|
271
|
+
90006 => "您当前使用的CorpId及CorpSecret调用当前接口次数过多,请求被暂时禁用了,仅对企业自己的Accesstoken有效",
|
272
|
+
90007 => "您当前要调用的企业的接口次数过多,对该企业的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
273
|
+
90008 => "您当前要调用的企业的当前接口次数过多,对此企业下该接口的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
274
|
+
90009 => "您调用企业接口超过了限制,对所有企业的所有接口的请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
275
|
+
90010 => "您调用企业当前接口超过了限制,对所有企业的该接口的请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
276
|
+
90011 => "您的套件调用企业接口超过了限制,该套件的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
277
|
+
90012 => "您的套件调用企业当前接口超过了限制,该套件对此接口的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
278
|
+
90013 => "您的套件调用当前企业的接口超过了限制,该套件对此企业的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
279
|
+
90014 => "您的套件调用企业当前接口超过了限制,该套件对此企业该接口的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效",
|
280
|
+
900001 => "加密明文文本非法",
|
281
|
+
900002 => "加密时间戳参数非法",
|
282
|
+
900003 => "加密随机字符串参数非法",
|
283
|
+
900004 => "不合法的aeskey",
|
284
|
+
900005 => "签名不匹配",
|
285
|
+
900006 => "计算签名错误",
|
286
|
+
900007 => "计算加密文字错误",
|
287
|
+
900008 => "计算解密文字错误",
|
288
|
+
900009 => "计算解密文字长度不匹配",
|
289
|
+
900010 => "计算解密文字corpid不匹配",
|
290
|
+
420001 => "客户不存在",
|
291
|
+
420002 => "客户查询失败",
|
292
|
+
420003 => "联系人不存在",
|
293
|
+
420004 => "联系人查询失败",
|
294
|
+
420005 => "客户删除失败",
|
295
|
+
420006 => "联系人删除失败",
|
296
|
+
420007 => "跟进人绑定失败",
|
297
|
+
420008 => "客户id非法",
|
298
|
+
420009 => "跟进人id非法",
|
299
|
+
4200010 => "客户联系人id非法",
|
300
|
+
4200011 => "客户描述表单不存在",
|
301
|
+
4200012 => "客户描述表单查询失败",
|
302
|
+
4200013 => "联系人描述表单不存在",
|
303
|
+
4200014 => "联系人描述表单查询失败",
|
304
|
+
4200015 => "客户描述表单格式校验错误",
|
305
|
+
4200016 => "客户描述表单格缺少固定字段",
|
306
|
+
4200017 => "客户联系人描述表单格式校验错误",
|
307
|
+
4200018 => "客户联系人描述表单格缺少固定字段",
|
308
|
+
4200019 => "客户描述表单数据格式校验错误",
|
309
|
+
4200020 => "客户描述表单数据缺少固定字段",
|
310
|
+
4200021 => "客户联系人描述表单数据格式校验错误",
|
311
|
+
4200022 => "客户联系人描述表单数据缺少固定字段",
|
312
|
+
800001 => "仅限ISV调用",
|
313
|
+
41042 => "加密失败",
|
314
|
+
41043 => "解密失败",
|
315
|
+
40100 => "分机号已经存在",
|
316
|
+
40101 => "邮箱已经存在",
|
317
|
+
50004 => "企业部门不在授权范围"
|
318
|
+
} unless defined?(GLOBAL_CODES)
|
319
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
class ResultHandler
|
3
|
+
attr_accessor :code, :cn_msg, :en_msg, :result
|
4
|
+
|
5
|
+
def initialize(code, en_msg, result={})
|
6
|
+
@code = code || OK_CODE
|
7
|
+
@en_msg = en_msg || OK_MSG
|
8
|
+
@cn_msg = GLOBAL_CODES[@code.to_i]
|
9
|
+
@result = package_result(result)
|
10
|
+
end
|
11
|
+
|
12
|
+
def is_ok?
|
13
|
+
code == OK_CODE
|
14
|
+
end
|
15
|
+
alias_method :ok?, :is_ok?
|
16
|
+
|
17
|
+
def full_message
|
18
|
+
"#{code}: #{en_msg}(#{cn_msg})."
|
19
|
+
end
|
20
|
+
alias_method :full_messages, :full_message
|
21
|
+
|
22
|
+
def full_error_message
|
23
|
+
full_message if !is_ok?
|
24
|
+
end
|
25
|
+
alias_method :full_error_messages, :full_error_message
|
26
|
+
|
27
|
+
private
|
28
|
+
def package_result(result)
|
29
|
+
return result if !result.is_a?(Hash)
|
30
|
+
if defined?(Rails)
|
31
|
+
ActiveSupport::HashWithIndifferentAccess.new(result)
|
32
|
+
else
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Dingtalk
|
3
|
+
module Token
|
4
|
+
class ObjectStore < Store
|
5
|
+
|
6
|
+
def valid?
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def token_expired?
|
11
|
+
# 如果当前token过期时间小于现在的时间,则重新获取一次
|
12
|
+
client.expired_at <= Time.now.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def refresh_token
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def access_token
|
20
|
+
super
|
21
|
+
client.access_token
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module Token
|
3
|
+
class RedisStore < Store
|
4
|
+
|
5
|
+
def valid?
|
6
|
+
redis.del(client.redis_key)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def token_expired?
|
11
|
+
redis.hvals(client.redis_key).empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def refresh_token
|
15
|
+
super
|
16
|
+
redis.hmset(
|
17
|
+
client.redis_key, "access_token",
|
18
|
+
client.access_token, "expired_at",
|
19
|
+
client.expired_at
|
20
|
+
)
|
21
|
+
redis.expireat(client.redis_key, client.expired_at.to_i)
|
22
|
+
end
|
23
|
+
|
24
|
+
def access_token
|
25
|
+
super
|
26
|
+
client.access_token = redis.hget(client.redis_key, "access_token")
|
27
|
+
client.expired_at = redis.hget(client.redis_key, "expired_at")
|
28
|
+
client.access_token
|
29
|
+
end
|
30
|
+
|
31
|
+
def redis
|
32
|
+
Dingtalk.redis
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Dingtalk
|
2
|
+
module Token
|
3
|
+
class Store
|
4
|
+
attr_accessor :client
|
5
|
+
def initialize(client)
|
6
|
+
@client = client
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.init_with(client)
|
10
|
+
if Dingtalk.redis.nil?
|
11
|
+
ObjectStore.new(client)
|
12
|
+
else
|
13
|
+
RedisStore.new(client)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
authenticate["valid"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def refresh_token
|
22
|
+
handle_valid_exception
|
23
|
+
set_access_token
|
24
|
+
end
|
25
|
+
|
26
|
+
def authenticate
|
27
|
+
auth_result = http_get_access_token
|
28
|
+
auth = false
|
29
|
+
if auth_result.is_ok?
|
30
|
+
set_access_token(auth_result.result)
|
31
|
+
auth = true
|
32
|
+
end
|
33
|
+
{"valid" => auth, "handler" => auth_result}
|
34
|
+
end
|
35
|
+
|
36
|
+
def access_token
|
37
|
+
refresh_token if token_expired?
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_access_token(access_token_infos=nil)
|
41
|
+
token_infos = access_token_infos || http_get_access_token.result
|
42
|
+
client.access_token = token_infos["access_token"]
|
43
|
+
client.expired_at = Dingtalk.calculate_expire(token_infos["expires_in"])
|
44
|
+
end
|
45
|
+
|
46
|
+
def token_expired?
|
47
|
+
raise NotImplementedError, "Subclasses must implement a token_expired? method"
|
48
|
+
end
|
49
|
+
|
50
|
+
def http_get_access_token
|
51
|
+
Dingtalk.http_get_without_token("/gettoken", authenticate_headers)
|
52
|
+
end
|
53
|
+
|
54
|
+
def authenticate_headers
|
55
|
+
{corpid: client.app_id, corpsecret: client.app_secret}
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def handle_valid_exception
|
61
|
+
auth_result = authenticate
|
62
|
+
if !auth_result["valid"]
|
63
|
+
result_handler = auth_result["handler"]
|
64
|
+
raise ValidAccessTokenException, result_handler.full_error_message
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dingtalk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ysllyfe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: redis
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rest-client
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sqlite3
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Description of Dingtalk.
|
112
|
+
email:
|
113
|
+
- ysllyfe@163.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- MIT-LICENSE
|
119
|
+
- README.md
|
120
|
+
- Rakefile
|
121
|
+
- lib/dingtalk.rb
|
122
|
+
- lib/dingtalk/api.rb
|
123
|
+
- lib/dingtalk/api/department.rb
|
124
|
+
- lib/dingtalk/api/message.rb
|
125
|
+
- lib/dingtalk/api/microapp.rb
|
126
|
+
- lib/dingtalk/api/user.rb
|
127
|
+
- lib/dingtalk/client.rb
|
128
|
+
- lib/dingtalk/config.rb
|
129
|
+
- lib/dingtalk/eco_api.rb
|
130
|
+
- lib/dingtalk/eco_api/role.rb
|
131
|
+
- lib/dingtalk/handler.rb
|
132
|
+
- lib/dingtalk/handler/eco_result_handler.rb
|
133
|
+
- lib/dingtalk/handler/global_code.rb
|
134
|
+
- lib/dingtalk/handler/result_handler.rb
|
135
|
+
- lib/dingtalk/token/object_store.rb
|
136
|
+
- lib/dingtalk/token/redis_store.rb
|
137
|
+
- lib/dingtalk/token/store.rb
|
138
|
+
- lib/dingtalk/version.rb
|
139
|
+
- lib/tasks/dingtalk_tasks.rake
|
140
|
+
homepage: http://github.com/ysllyfe/dingtalk
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
metadata: {}
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
requirements: []
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 2.5.1
|
161
|
+
signing_key:
|
162
|
+
specification_version: 4
|
163
|
+
summary: Summary of Dingtalk.
|
164
|
+
test_files: []
|