Commit f9eb1336 by Francis Zhou

重构 Core::add_request 方法

parent 15cb4dfb
......@@ -26,6 +26,9 @@ module Dingtalk
class Request
include Auth
include AccessToken
attr_reader :app_key, :app_secret
def initialize(app_key:, app_secret:)
@app_key, @app_secret = app_key, app_secret
......
......@@ -3,15 +3,13 @@ require "dingtalk/request_url"
module Dingtalk
module AccessToken
class << self
extend Dingtalk::Core
# 获取 access_token
# @url https://ding-doc.dingtalk.com/doc#/serverapi2/eev437
add_request :get_access_token, :get, Dingtalk::RequestUrl::ACCESS_TOKEN do |request|
request.add_arg :appkey, required: true, in: :query
request.add_arg :appsecret, required: true, in: :query
end
request.add_const :appkey, ->(r) { r.app_key }, in: :query
request.add_const :appsecret, ->(r) { r.app_secret }, in: :query
end
end
end
\ No newline at end of file
require "dingtalk/core"
require "dingtalk/request_url"
require "active_support/core_ext/object/to_query"
module Dingtalk
module Auth
class << self
extend Dingtalk::Core
# 企业内部应用免登录 用户ID获取
......@@ -13,6 +13,20 @@ module Dingtalk
request.add_arg :access_token, required: true, in: :query
end
# 生成扫码登录跳转地址
# @url https://ding-doc.dingtalk.com/doc#/serverapi2/kymkv6
def get_qr_connect_uri(redirect_uri, state = "")
qs = {}.tap do |h|
h[:appid] = @app_key
h[:response_type] = "code"
h[:scope] = "snsapi_login"
h[:state] = state
h[:redirect_uri] = redirect_uri
end
"#{Dingtalk::RequestUrl::CONNECT_QR_REDIRECT}?#{qs.to_query}"
end
# 钉钉内免登录第三方网站 个人信息获取
# @url https://ding-doc.dingtalk.com/doc#/serverapi2/etaarr
add_request :get_3rd_login_free_user_profile, :post, Dingtalk::RequestUrl::GET_USER_INFO_SNS do |request|
......@@ -25,5 +39,4 @@ module Dingtalk
request.add_arg :tmp_auth_code, required: true, in: :body
end
end
end
end
\ No newline at end of file
......@@ -8,7 +8,7 @@ require "dingtalk"
module Dingtalk
module Core
class RequestBuilder
attr_reader :query_args, :body_args, :required_args
attr_reader :query_args, :body_args, :query_const, :body_const, :required_args
def initialize
@is_json = false
......@@ -16,7 +16,9 @@ module Dingtalk
@body_args = []
@query_args = []
@required_args = []
@with_key_and_secret = false
@body_const = {}
@query_const = {}
end
def is_json?
......@@ -27,12 +29,20 @@ module Dingtalk
@required_args.include? arg_name
end
def has_body_args?
!@body_args.empty?
def has_body?
!@body_args.empty? || !@body_const.empty?
end
def has_query?
!@query_args.empty? || !@query_const.empty?
end
def has_body_const?
!@body_const.empty?
end
def has_query_args?
!@query_args.empty?
def has_query_const?
!@query_const.empty?
end
def is_json=(b)
......@@ -46,11 +56,24 @@ module Dingtalk
when :query
@query_args << arg_name
else
raise Dingtalk::Error.new("unknown argument position")
raise Dingtalk::Error.new("unknown argument '#{arg_name}' position")
end
@required_args << arg_name if option[:required]
end
def add_const(arg_name, value, option)
const_hash = {arg_name => value}
case option[:in]
when :body
@body_const.merge! const_hash
when :query
@query_const.merge! const_hash
else
raise Dingtalk::Error.new("unknown argument '#{arg_name}' position")
end
end
end
def add_request(request_name, method, url)
......@@ -64,20 +87,25 @@ module Dingtalk
if method_args[arg].nil?
end
h[:body] = {} if builder.has_body_args?
h[:query] = {} if builder.has_query_args?
[:body, :query].each do |arg_pos|
h[arg_pos] = {} if builder.send(:"has_#{arg_pos}?")
builder.body_args.each do |arg|
h[:body][arg] = method_args[arg]
builder.send(:"#{arg_pos}_args").each do |arg|
h[arg_pos][arg] = method_args[arg]
end
builder.query_args.each do |arg|
h[:query][arg] = method_args[arg] unless method_args[arg].nil?
builder.send(:"#{arg_pos}_const").each do |arg_name, arg_value|
if arg_value.respond_to?(:call)
h[arg_pos][arg_name] = arg_value.call(self)
else
h[arg_pos][arg_name] = arg_value
end
end
end
if builder.is_json?
h[:body] = h[:body].to_json
h[:headers] = {:"Content-Type" => "application/json"} if builder.is_json?
h[:body] = h[:body].to_json if Hash === h[:body]
h[:headers] = {:"Content-Type" => "application/json"}
end
end
......
require "json"
require "dingtalk"
require "dingtalk/access_token"
RSpec.describe Dingtalk::AccessToken do
......@@ -7,6 +8,8 @@ RSpec.describe Dingtalk::AccessToken do
@app_secret = "mocked_app_secret"
@mocked_access_token = "mocked_access_token"
@dingtalk_request = Dingtalk::Request.new(app_key: @app_key, app_secret: @app_secret)
response_body = {}.tap do |h|
h[:errcode] = 0
h[:errmsg] = 0
......@@ -19,7 +22,7 @@ RSpec.describe Dingtalk::AccessToken do
end
it "should return correct access_token from request" do
response = Dingtalk::AccessToken.get_access_token appkey: @app_key, appsecret: @app_secret
response = @dingtalk_request.get_access_token
expect(response[:access_token]).to eq(@mocked_access_token)
end
......
require "cgi"
require "uri"
require "json"
require "securerandom"
require "dingtalk"
require "dingtalk/auth"
RSpec.describe Dingtalk::Auth do
......@@ -13,6 +18,8 @@ RSpec.describe Dingtalk::Auth do
@signature = Dingtalk.login_free_signature(@app_secret, timestamp: @timestamp)
@dingtalk_request = Dingtalk::Request.new(app_key: @app_key, app_secret: @app_secret)
# 企业内部免登 响应结果
get_user_info_response_body = {}.tap do |h|
h[:userid] = @int_user_id
......@@ -32,12 +39,20 @@ RSpec.describe Dingtalk::Auth do
end
stub_request(:get, /oapi.dingtalk.com\/user\/getuserinfo/)
.with(query: { code: @int_login_code, access_token: @access_token })
.with(
query: {
code: @int_login_code,
access_token: @access_token,
})
.to_return(status: 200, body: get_user_info_response_body.to_json)
stub_request(:post, /oapi.dingtalk.com\/sns\/getuserinfo_bycode/)
.with(
query: { accessKey: @app_key, timestamp: @timestamp.to_s, signature: @signature.to_s },
query: {
accessKey: @app_key,
timestamp: @timestamp.to_s,
signature: @signature.to_s,
},
body: { tmp_auth_code: "23152698ea18304da4d0ce1xxxxx" }.to_json,
headers: { :"Content-Type" => "application/json" }
)
......@@ -45,7 +60,7 @@ RSpec.describe Dingtalk::Auth do
end
it 'should get user id in internal app login-free scenario' do
response = Dingtalk::Auth.get_int_login_free_user_id(
response = @dingtalk_request.get_int_login_free_user_id(
code: @int_login_code,
access_token: @access_token,
)
......@@ -57,7 +72,7 @@ RSpec.describe Dingtalk::Auth do
# 详情见 https://ding-doc.dingtalk.com/doc#/serverapi2/etaarr
it 'should get user profile through temp auth code in login-free scenario' do
response = Dingtalk::Auth.get_3rd_login_free_user_profile(
response = @dingtalk_request.get_3rd_login_free_user_profile(
accessKey: @app_key,
timestamp: @timestamp,
signature: @signature.to_s,
......@@ -69,4 +84,17 @@ RSpec.describe Dingtalk::Auth do
expect(response[:user_info][:openid]).to eq("liSii8KCxxxxx")
expect(response[:user_info][:unionid]).to eq("7Huu46kk")
end
it 'should create connect qr scan page url in dingtalk.com' do
state = SecureRandom.hex(6)
redirect_uri = "http://example.org/callback"
qr_connect_uri = @dingtalk_request.get_qr_connect_uri(redirect_uri, state)
uri = URI(qr_connect_uri)
query = CGI::parse(uri.query)
expect(query["appid"].first).to eq(@app_key)
expect(query["state"].first).to eq(state)
expect(query["redirect_uri"].first).to eq(redirect_uri)
end
end
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment