Improve flexibility and structure of send_to_api action
Dieser Commit ist enthalten in:
Ursprung
6ad821024a
Commit
30390e8264
10 geänderte Dateien mit 92 neuen und 56 gelöschten Zeilen
|
@ -11,6 +11,8 @@ export default Ember.Controller.extend({
|
||||||
showRemove: Ember.computed.not('isNew'),
|
showRemove: Ember.computed.not('isNew'),
|
||||||
showRedirectUri: Ember.computed.and('threeLeggedOauth', 'api.name'),
|
showRedirectUri: Ember.computed.and('threeLeggedOauth', 'api.name'),
|
||||||
responseIcon: null,
|
responseIcon: null,
|
||||||
|
contentTypes: ['application/json', 'application/x-www-form-urlencoded'],
|
||||||
|
successCodes: [100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 303, 304, 305, 306, 307, 308],
|
||||||
|
|
||||||
@computed('saveDisabled', 'api.authType', 'api.authUrl', 'api.tokenUrl', 'api.clientId', 'api.clientSecret', 'threeLeggedOauth')
|
@computed('saveDisabled', 'api.authType', 'api.authUrl', 'api.tokenUrl', 'api.clientId', 'api.clientSecret', 'threeLeggedOauth')
|
||||||
authDisabled(saveDisabled, authType, authUrl, tokenUrl, clientId, clientSecret, threeLeggedOauth) {
|
authDisabled(saveDisabled, authType, authUrl, tokenUrl, clientId, clientSecret, threeLeggedOauth) {
|
||||||
|
@ -24,7 +26,7 @@ export default Ember.Controller.extend({
|
||||||
return !name || !authType;
|
return !name || !authType;
|
||||||
},
|
},
|
||||||
|
|
||||||
authorizationTypes: ['basic', 'oauth_2', 'oauth_3'],
|
authorizationTypes: ['none', 'basic', 'oauth_2', 'oauth_3'],
|
||||||
isBasicAuth: Ember.computed.equal('api.authType', 'basic'),
|
isBasicAuth: Ember.computed.equal('api.authType', 'basic'),
|
||||||
|
|
||||||
@computed('api.authType')
|
@computed('api.authType')
|
||||||
|
@ -124,13 +126,15 @@ export default Ember.Controller.extend({
|
||||||
requiredParams = ['authUrl', 'tokenUrl', 'clientId', 'clientSecret'];
|
requiredParams = ['authUrl', 'tokenUrl', 'clientId', 'clientSecret'];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let rp of requiredParams) {
|
if (requiredParams) {
|
||||||
if (!api[rp]) {
|
for (let rp of requiredParams) {
|
||||||
let key = rp.replace('auth', '');
|
if (!api[rp]) {
|
||||||
error = `${I18n.t(`admin.wizard.api.auth.${key.underscore()}`)} is required for ${authType}`;
|
let key = rp.replace('auth', '');
|
||||||
break;
|
error = `${I18n.t(`admin.wizard.api.auth.${key.underscore()}`)} is required for ${authType}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data[rp.underscore()] = api[rp];
|
||||||
}
|
}
|
||||||
data[rp.underscore()] = api[rp];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = api.authParams;
|
const params = api.authParams;
|
||||||
|
|
|
@ -228,18 +228,28 @@
|
||||||
<li>
|
<li>
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="endpoint-">
|
<div class="endpoint-">
|
||||||
{{input value=endpoint.name
|
<div class="top">
|
||||||
placeholder=(i18n 'admin.wizard.api.endpoint.name')}}
|
{{input value=endpoint.name
|
||||||
{{combo-box content=endpointMethods
|
placeholder=(i18n 'admin.wizard.api.endpoint.name')}}
|
||||||
value=endpoint.method
|
{{input value=endpoint.url
|
||||||
none="admin.wizard.api.endpoint.method"}}
|
placeholder=(i18n 'admin.wizard.api.endpoint.url')
|
||||||
{{input value=endpoint.url
|
class='endpoint-url'}}
|
||||||
placeholder=(i18n 'admin.wizard.api.endpoint.url')
|
{{d-button action=(action "removeEndpoint")
|
||||||
class='endpoint-url'}}
|
actionParam=endpoint
|
||||||
{{d-button action=(action "removeEndpoint")
|
icon='times'
|
||||||
actionParam=endpoint
|
class='remove-endpoint'}}
|
||||||
icon='times'
|
</div>
|
||||||
class='remove-endpoint'}}
|
<div class="bottom">
|
||||||
|
{{combo-box content=endpointMethods
|
||||||
|
value=endpoint.method
|
||||||
|
none="admin.wizard.api.endpoint.method"}}
|
||||||
|
{{combo-box content=contentTypes
|
||||||
|
value=endpoint.content_type
|
||||||
|
none="admin.wizard.api.endpoint.content_type"}}
|
||||||
|
{{multi-select content=successCodes
|
||||||
|
values=endpoint.success_codes
|
||||||
|
none="admin.wizard.api.endpoint.success_codes"}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -446,14 +446,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.endpoint {
|
.endpoint {
|
||||||
display: flex;
|
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.top, .bottom {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.combo-box {
|
.combo-box {
|
||||||
width: 200px;
|
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-top: -2px;
|
width: 210px;
|
||||||
width: 150px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
@ -462,7 +467,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.endpoint-url {
|
.endpoint-url {
|
||||||
width: 300px;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.remove-endpoint {
|
.remove-endpoint {
|
||||||
|
|
|
@ -211,6 +211,8 @@ en:
|
||||||
name: "Endpoint name"
|
name: "Endpoint name"
|
||||||
method: "Select a method"
|
method: "Select a method"
|
||||||
url: "Enter a url"
|
url: "Enter a url"
|
||||||
|
content_type: "Select a content type"
|
||||||
|
success_codes: "Select success codes"
|
||||||
|
|
||||||
log:
|
log:
|
||||||
label: "Logs"
|
label: "Logs"
|
||||||
|
|
|
@ -64,7 +64,7 @@ class CustomWizard::Api::Authorization
|
||||||
PluginStore.remove("custom_wizard_api_#{api_name}", "authorization")
|
PluginStore.remove("custom_wizard_api_#{api_name}", "authorization")
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_header_authorization_string(name)
|
def self.authorization_string(name)
|
||||||
auth = CustomWizard::Api::Authorization.get(name)
|
auth = CustomWizard::Api::Authorization.get(name)
|
||||||
raise Discourse::InvalidParameters.new(:name) unless auth.present?
|
raise Discourse::InvalidParameters.new(:name) unless auth.present?
|
||||||
|
|
||||||
|
@ -72,9 +72,11 @@ class CustomWizard::Api::Authorization
|
||||||
raise Discourse::InvalidParameters.new(:username) unless auth.username.present?
|
raise Discourse::InvalidParameters.new(:username) unless auth.username.present?
|
||||||
raise Discourse::InvalidParameters.new(:password) unless auth.password.present?
|
raise Discourse::InvalidParameters.new(:password) unless auth.password.present?
|
||||||
"Basic #{Base64.strict_encode64((auth.username + ":" + auth.password).chomp)}"
|
"Basic #{Base64.strict_encode64((auth.username + ":" + auth.password).chomp)}"
|
||||||
else
|
elsif ['oauth_3', 'oauth_2'].include?(auth.auth_type)
|
||||||
raise Discourse::InvalidParameters.new(auth.access_token) unless auth.access_token.present?
|
raise Discourse::InvalidParameters.new(auth.access_token) unless auth.access_token.present?
|
||||||
"Bearer #{auth.access_token}"
|
"Bearer #{auth.access_token}"
|
||||||
|
else
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,9 @@ class CustomWizard::Api::Endpoint
|
||||||
:name,
|
:name,
|
||||||
:api_name,
|
:api_name,
|
||||||
:method,
|
:method,
|
||||||
:url
|
:url,
|
||||||
|
:content_type,
|
||||||
|
:success_codes
|
||||||
|
|
||||||
def initialize(api_name, data={})
|
def initialize(api_name, data={})
|
||||||
@api_name = api_name
|
@api_name = api_name
|
||||||
|
@ -62,40 +64,49 @@ class CustomWizard::Api::Endpoint
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.request(user, api_name, endpoint_id, body)
|
def self.request(user = Discourse.system_user, api_name, endpoint_id, body)
|
||||||
endpoint = self.get(api_name, endpoint_id)
|
endpoint = self.get(api_name, endpoint_id)
|
||||||
auth = CustomWizard::Api::Authorization.get_header_authorization_string(api_name)
|
auth_string = CustomWizard::Api::Authorization.authorization_string(api_name)
|
||||||
|
content_type = endpoint.content_type
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
headers["Authorization"] = auth_string if auth_string
|
||||||
|
headers["Content-Type"] = content_type if content_type
|
||||||
|
|
||||||
connection = Excon.new(
|
connection = Excon.new(URI.parse(URI.encode(endpoint.url)).to_s, headers: headers)
|
||||||
URI.parse(URI.encode(endpoint.url)).to_s,
|
|
||||||
:headers => {
|
|
||||||
"Authorization" => auth,
|
|
||||||
"Accept" => "application/json, */*",
|
|
||||||
"Content-Type" => "application/json"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
params = {
|
params = { method: endpoint.method }
|
||||||
method: endpoint.method
|
|
||||||
}
|
|
||||||
|
|
||||||
if body
|
if body
|
||||||
body = JSON.generate(body)
|
if content_type === "application/json"
|
||||||
body.delete! '\\'
|
body = JSON.generate(body)
|
||||||
|
elsif content_type === "application/x-www-form-urlencoded"
|
||||||
|
body = URI.encode_www_form(body)
|
||||||
|
end
|
||||||
|
|
||||||
params[:body] = body
|
params[:body] = body
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
response = connection.request(params)
|
||||||
response = connection.request(params)
|
|
||||||
log_params = {time: Time.now, user_id: user.id, status: 'SUCCESS', url: endpoint.url, error: ""}
|
if endpoint.success_codes.include?(response.status)
|
||||||
|
begin
|
||||||
|
result = JSON.parse(response.body)
|
||||||
|
rescue JSON::ParserError
|
||||||
|
result = response.body
|
||||||
|
end
|
||||||
|
|
||||||
CustomWizard::Api::LogEntry.set(api_name, log_params)
|
CustomWizard::Api::LogEntry.set(api_name, log_params(user, 'SUCCESS', endpoint.url))
|
||||||
return JSON.parse(response.body)
|
|
||||||
rescue
|
result
|
||||||
# TODO: improve error detail
|
else
|
||||||
log_params = {time: Time.now, user_id: user.id, status: 'FAILURE', url: endpoint.url, error: "API request failed"}
|
message = "API request failed"
|
||||||
CustomWizard::Api::LogEntry.set(api_name, log_params)
|
CustomWizard::Api::LogEntry.set(api_name, log_params(user, 'FAIL', endpoint.url, message))
|
||||||
return JSON.parse "[{\"error\":\"API request failed\"}]"
|
{ error: message }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.log_params(user, status, url, message = "")
|
||||||
|
{ time: Time.now, user_id: user.id, status: status, url: url, error: message }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -492,7 +492,7 @@ class CustomWizard::Builder
|
||||||
rescue JSON::ParserError
|
rescue JSON::ParserError
|
||||||
raise Discourse::InvalidParameters, "Invalid API body definition: #{action['api_body']} for #{action['title']}"
|
raise Discourse::InvalidParameters, "Invalid API body definition: #{action['api_body']} for #{action['title']}"
|
||||||
end
|
end
|
||||||
api_body = CustomWizard::Builder.fill_placeholders(JSON.generate(api_body_parsed), user, data)
|
api_body = JSON.parse(CustomWizard::Builder.fill_placeholders(JSON.generate(api_body_parsed), user, data))
|
||||||
end
|
end
|
||||||
|
|
||||||
result = CustomWizard::Api::Endpoint.request(user, action['api'], action['api_endpoint'], api_body)
|
result = CustomWizard::Api::Endpoint.request(user, action['api'], action['api_endpoint'], api_body)
|
||||||
|
|
|
@ -101,7 +101,7 @@ after_initialize do
|
||||||
load File.expand_path('../lib/api/api.rb', __FILE__)
|
load File.expand_path('../lib/api/api.rb', __FILE__)
|
||||||
load File.expand_path('../lib/api/authorization.rb', __FILE__)
|
load File.expand_path('../lib/api/authorization.rb', __FILE__)
|
||||||
load File.expand_path('../lib/api/endpoint.rb', __FILE__)
|
load File.expand_path('../lib/api/endpoint.rb', __FILE__)
|
||||||
load File.expand_path('../lib/api/logentry.rb', __FILE__)
|
load File.expand_path('../lib/api/log_entry.rb', __FILE__)
|
||||||
load File.expand_path('../controllers/api.rb', __FILE__)
|
load File.expand_path('../controllers/api.rb', __FILE__)
|
||||||
load File.expand_path('../serializers/api/api_serializer.rb', __FILE__)
|
load File.expand_path('../serializers/api/api_serializer.rb', __FILE__)
|
||||||
load File.expand_path('../serializers/api/authorization_serializer.rb', __FILE__)
|
load File.expand_path('../serializers/api/authorization_serializer.rb', __FILE__)
|
||||||
|
|
|
@ -2,7 +2,9 @@ class CustomWizard::Api::EndpointSerializer < ApplicationSerializer
|
||||||
attributes :id,
|
attributes :id,
|
||||||
:name,
|
:name,
|
||||||
:method,
|
:method,
|
||||||
:url
|
:url,
|
||||||
|
:content_type,
|
||||||
|
:success_codes
|
||||||
|
|
||||||
def method
|
def method
|
||||||
object.send('method')
|
object.send('method')
|
||||||
|
|
Laden …
In neuem Issue referenzieren