diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6
index 976501e5..75000d8b 100644
--- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6
+++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6
@@ -3,7 +3,8 @@ import { default as computed, observes } from 'ember-addons/ember-computed-decor
const ACTION_TYPES = [
{ id: 'create_topic', name: 'Create Topic' },
{ id: 'update_profile', name: 'Update Profile' },
- { id: 'send_message', name: 'Send Message' }
+ { id: 'send_message', name: 'Send Message' },
+ { id: 'send_to_api', name: 'Send to API' }
];
const PROFILE_FIELDS = [
@@ -26,6 +27,8 @@ export default Ember.Component.extend({
createTopic: Ember.computed.equal('action.type', 'create_topic'),
updateProfile: Ember.computed.equal('action.type', 'update_profile'),
sendMessage: Ember.computed.equal('action.type', 'send_message'),
+ sendToApi: Ember.computed.equal('action.type', 'send_to_api'),
+ apiEmpty: Ember.computed.empty('action.api'),
disableId: Ember.computed.not('action.isNew'),
@computed('currentStepId', 'wizard.save_submissions')
@@ -75,5 +78,21 @@ export default Ember.Component.extend({
toggleCustomCategoryWizardField() {
const user = this.get('action.custom_category_user_field');
if (user) this.set('action.custom_category_wizard_field', false);
+ },
+
+ @computed('wizard.apis')
+ availableApis(apis) {
+ return apis.map(a => {
+ return {
+ id: a.name,
+ name: a.title
+ };
+ });
+ },
+
+ @computed('wizard.apis', 'action.api')
+ availableEndpoints(apis, api) {
+ if (!api) return [];
+ return apis.find(a => a.name === api).endpoints;
}
});
diff --git a/assets/javascripts/discourse/controllers/admin-wizards-api.js.es6 b/assets/javascripts/discourse/controllers/admin-wizards-api.js.es6
index 926aa751..7306012e 100644
--- a/assets/javascripts/discourse/controllers/admin-wizards-api.js.es6
+++ b/assets/javascripts/discourse/controllers/admin-wizards-api.js.es6
@@ -78,7 +78,6 @@ export default Ember.Controller.extend({
if (api.title) data['title'] = api.title;
const originalTitle = this.get('api.originalTitle');
- console.log(api, originalTitle);
if (api.get('isNew') || (originalTitle && (api.title !== originalTitle))) {
refreshList = true;
}
diff --git a/assets/javascripts/discourse/routes/admin-wizard.js.es6 b/assets/javascripts/discourse/routes/admin-wizard.js.es6
index aeba38b0..a10f625e 100644
--- a/assets/javascripts/discourse/routes/admin-wizard.js.es6
+++ b/assets/javascripts/discourse/routes/admin-wizard.js.es6
@@ -33,7 +33,8 @@ export default Discourse.Route.extend({
afterModel(model) {
return Ember.RSVP.all([
this._getFieldTypes(model),
- this._getThemes(model)
+ this._getThemes(model),
+ this._getApis(model)
]);
},
@@ -48,6 +49,11 @@ export default Discourse.Route.extend({
});
},
+ _getApis(model) {
+ return ajax('/admin/wizards/apis')
+ .then((result) => model.set('apis', result));
+ },
+
setupController(controller, model) {
const newWizard = this.get('newWizard');
const steps = model.get('steps') || [];
diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs
index 7a7f3cfc..95384f64 100644
--- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs
+++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs
@@ -96,7 +96,7 @@
{{d-editor value=action.post_template
- placeholder='admin.wizard.action.post_builder.placeholder'
+ placeholder='admin.wizard.action.interpolate_fields'
classNames='post-builder-editor'}}
@@ -157,7 +157,7 @@
{{d-editor value=action.post_template
- placeholder='admin.wizard.action.post_builder.placeholder'
+ placeholder='admin.wizard.action.interpolate_fields'
classNames='post-builder-editor'}}
@@ -204,3 +204,41 @@
allowUserField=true}}
{{/if}}
+
+{{#if sendToApi}}
+
+
+
{{i18n "admin.wizard.action.send_to_api.api"}}
+
+
+ {{combo-box value=action.api
+ content=availableApis
+ none='admin.wizard.action.send_to_api.select_an_api'
+ isDisabled=action.custom_title_enabled}}
+
+
+
+
+
+
{{i18n "admin.wizard.action.send_to_api.endpoint"}}
+
+
+ {{combo-box value=action.api_endpoint
+ content=availableEndpoints
+ none='admin.wizard.action.send_to_api.select_an_endpoint'
+ isDisabled=apiEmpty}}
+
+
+
+
+
+
{{i18n "admin.wizard.action.send_to_api.body"}}
+
+
+
+
+ {{textarea value=action.api_body
+ placeholder=(i18n 'admin.wizard.action.interpolate_fields')}}
+
+
+{{/if}}
diff --git a/assets/stylesheets/wizard_custom_admin.scss b/assets/stylesheets/wizard_custom_admin.scss
index f97a4500..2ebbb253 100644
--- a/assets/stylesheets/wizard_custom_admin.scss
+++ b/assets/stylesheets/wizard_custom_admin.scss
@@ -117,6 +117,23 @@
margin-top: 5px;
padding: 5px;
}
+
+ .api-body {
+ width: 100%;
+
+ .setting-label {
+ max-width: 70px;
+ }
+
+ .setting-value {
+ width: calc(100% - 180px);
+ }
+
+ textarea {
+ width: 100%;
+ min-height: 150px;
+ }
+ }
}
.wizard-links {
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 700f50ca..e3388f57 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -103,6 +103,8 @@ en:
add_fields: "{{type}} Fields"
available_fields: "* If 'Save wizard submissions' is disabled, only the fields of the current step are available to the current step's actions."
topic_attr: "Topic Attribute"
+ interpolate_fields: "Insert wizard fields using the field_id in w{}. Insert user fields using field key in u{}."
+
skip_redirect:
label: "Skip Redirect"
description: "Don't redirect the user to this {{type}} after the wizard completes"
@@ -120,12 +122,19 @@ en:
label: "Builder"
user_fields: "User Fields: "
wizard_fields: "Wizard Fields: "
- placeholder: "Insert wizard fields using the field_id in w{}. Insert user fields using field key in u{}."
custom_title: "Custom Title"
custom_category:
label: "Custom Category"
wizard_field: "Wizard Field"
user_field: "User Field"
+ send_to_api:
+ label: "Send to API"
+ api: "API"
+ endpoint: "Endpoint"
+ select_an_api: "Select an API"
+ select_an_endpoint: "Select an endpoint"
+ body: "Request body JSON"
+
api:
label: "API"
nav_label: 'APIs'
diff --git a/controllers/api.rb b/controllers/api.rb
index 86fc6841..524f4e84 100644
--- a/controllers/api.rb
+++ b/controllers/api.rb
@@ -106,10 +106,10 @@ class CustomWizard::ApiController < ::ApplicationController
:client_secret,
:username,
:password,
- :params
+ :auth_params
)
- auth_data[:params] = JSON.parse(auth_data[:params]) if auth_data[:params].present?
+ auth_data[:auth_params] = JSON.parse(auth_data[:auth_params]) if auth_data[:auth_params].present?
@auth_data ||= auth_data
end
diff --git a/lib/api/authorization.rb b/lib/api/authorization.rb
index ac625475..7f702f6b 100644
--- a/lib/api/authorization.rb
+++ b/lib/api/authorization.rb
@@ -32,6 +32,8 @@ class CustomWizard::Api::Authorization
end
def self.set(api_name, new_data = {})
+ api_name = api_name.underscore
+
data = self.get(api_name, data_only: true) || {}
new_data.each do |k, v|
@@ -44,6 +46,8 @@ class CustomWizard::Api::Authorization
end
def self.get(api_name, opts = {})
+ api_name = api_name.underscore
+
if data = PluginStore.get("custom_wizard_api_#{api_name}", 'authorization')
if opts[:data_only]
data
@@ -60,22 +64,16 @@ class CustomWizard::Api::Authorization
end
def self.get_header_authorization_string(name)
- protocol = authentication_protocol(name)
- raise Discourse::InvalidParameters.new(:name) unless protocol.present?
- raise Discourse::InvalidParameters.new(:protocol) unless [BASIC_AUTH, OAUTH2_AUTH].include? protocol
+ auth = CustomWizard::Api::Authorization.get(name)
+ raise Discourse::InvalidParameters.new(:name) unless auth.present?
- if protocol = BASIC_AUTH
- username = username(name)
- raise Discourse::InvalidParameters.new(:username) unless username.present?
- password = password(name)
- raise Discourse::InvalidParameters.new(:password) unless password.present?
- authorization_string = (username + ":" + password).chomp
- "Basic #{Base64.strict_encode64(authorization_string)}"
+ if auth.auth_type === "basic"
+ raise Discourse::InvalidParameters.new(:username) unless auth.username.present?
+ raise Discourse::InvalidParameters.new(:password) unless auth.password.present?
+ "Basic #{Base64.strict_encode64((auth.username + ":" + auth.password).chomp)}"
else
- # must be OAUTH2
- access_token = access_token(name)
- raise Discourse::InvalidParameters.new(access_token) unless access_token.present?
- "Bearer #{access_token}"
+ raise Discourse::InvalidParameters.new(auth.access_token) unless auth.access_token.present?
+ "Bearer #{auth.access_token}"
end
end
diff --git a/lib/api/endpoint.rb b/lib/api/endpoint.rb
index 1d14d6ba..3f475301 100644
--- a/lib/api/endpoint.rb
+++ b/lib/api/endpoint.rb
@@ -16,8 +16,13 @@ class CustomWizard::Api::Endpoint
end
def self.set(api_name, new_data)
- data = new_data[:endpoint_id] ? self.get(api_name, new_data[:endpoint_id], data_only: true) : {}
- endpoint_id = new_data[:endpoint_id] || SecureRandom.hex(3)
+ if new_data['id']
+ data = self.get(api_name, new_data['id'], data_only: true)
+ endpoint_id = new_data['id']
+ else
+ data = {}
+ endpoint_id = SecureRandom.hex(3)
+ end
new_data.each do |k, v|
data[k.to_sym] = v
@@ -32,11 +37,10 @@ class CustomWizard::Api::Endpoint
return nil if !endpoint_id
if data = PluginStore.get("custom_wizard_api_#{api_name}", "endpoint_#{endpoint_id}")
- data[:id] = endpoint_id
-
if opts[:data_only]
data
else
+ data[:id] = endpoint_id
self.new(api_name, data)
end
else
@@ -48,8 +52,8 @@ class CustomWizard::Api::Endpoint
PluginStoreRow.where("plugin_name = 'custom_wizard_api_#{api_name}' AND key LIKE 'endpoint_%'").destroy_all
end
- def self.list
- PluginStoreRow.where("plugin_name LIKE 'custom_wizard_api_%' AND key LIKE 'endpoint_%'")
+ def self.list(api_name)
+ PluginStoreRow.where("plugin_name LIKE 'custom_wizard_api_#{api_name}' AND key LIKE 'endpoint_%'")
.map do |record|
api_name = record['plugin_name'].sub("custom_wizard_api_", "")
data = ::JSON.parse(record['value'])
@@ -57,4 +61,32 @@ class CustomWizard::Api::Endpoint
self.new(api_name, data)
end
end
+
+ def self.request(api_name, endpoint_id, body)
+ endpoint = self.get(api_name, endpoint_id)
+ auth = CustomWizard::Api::Authorization.get_header_authorization_string(api_name)
+
+ connection = Excon.new(
+ URI.parse(URI.encode(endpoint.url)).to_s,
+ :headers => {
+ "Authorization" => auth,
+ "Accept" => "application/json, */*",
+ "Content-Type" => "application/json"
+ }
+ )
+
+ params = {
+ method: endpoint.method
+ }
+
+ if body
+ body = JSON.generate(body)
+ body.delete! '\\'
+ params[:body] = body
+ end
+
+ response = connection.request(params)
+
+ JSON.parse(response.body)
+ end
end
diff --git a/lib/builder.rb b/lib/builder.rb
index ad4ef53a..bc873261 100644
--- a/lib/builder.rb
+++ b/lib/builder.rb
@@ -393,6 +393,17 @@ class CustomWizard::Builder
end
end
+ def send_to_api(user, action, data)
+ api_body = CustomWizard::Builder.fill_placeholders(JSON.generate(JSON.parse(action['api_body'])), user, data)
+ result = CustomWizard::Api::Endpoint.request(action['api'], action['api_endpoint'], api_body)
+
+ if result['error']
+ updater.errors.add(:send_message, result['error'])
+ else
+ ## add validation callback
+ end
+ end
+
def save_submissions(data, final_step)
if final_step
data['submitted_at'] = Time.now.iso8601
diff --git a/plugin.rb b/plugin.rb
index f0d7cfc6..da45683d 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -97,6 +97,7 @@ after_initialize do
load File.expand_path('../serializers/api/authorization_serializer.rb', __FILE__)
load File.expand_path('../serializers/api/basic_api_serializer.rb', __FILE__)
load File.expand_path('../serializers/api/endpoint_serializer.rb', __FILE__)
+ load File.expand_path('../serializers/api/basic_endpoint_serializer.rb', __FILE__)
::UsersController.class_eval do
def wizard_path
diff --git a/serializers/api/api_serializer.rb b/serializers/api/api_serializer.rb
index 0856b461..651e29fd 100644
--- a/serializers/api/api_serializer.rb
+++ b/serializers/api/api_serializer.rb
@@ -14,7 +14,7 @@ class CustomWizard::ApiSerializer < ApplicationSerializer
end
def endpoints
- if endpoints = CustomWizard::Api::Endpoint.list
+ if endpoints = CustomWizard::Api::Endpoint.list(object.name)
ActiveModel::ArraySerializer.new(
endpoints,
each_serializer: CustomWizard::Api::EndpointSerializer
diff --git a/serializers/api/basic_api_serializer.rb b/serializers/api/basic_api_serializer.rb
index 6f583f7d..d0214d65 100644
--- a/serializers/api/basic_api_serializer.rb
+++ b/serializers/api/basic_api_serializer.rb
@@ -1,3 +1,14 @@
class CustomWizard::BasicApiSerializer < ApplicationSerializer
- attributes :name, :title
+ attributes :name,
+ :title,
+ :endpoints
+
+ def endpoints
+ if endpoints = CustomWizard::Api::Endpoint.list(object.name)
+ ActiveModel::ArraySerializer.new(
+ endpoints,
+ each_serializer: CustomWizard::Api::BasicEndpointSerializer
+ )
+ end
+ end
end
diff --git a/serializers/api/basic_endpoint_serializer.rb b/serializers/api/basic_endpoint_serializer.rb
new file mode 100644
index 00000000..e2cc2262
--- /dev/null
+++ b/serializers/api/basic_endpoint_serializer.rb
@@ -0,0 +1,4 @@
+class CustomWizard::Api::BasicEndpointSerializer < ApplicationSerializer
+ attributes :id,
+ :name
+end