Skip to content

Commit

Permalink
[feature] Pass current user and current visit to API data pipeline (#927
Browse files Browse the repository at this point in the history
)

# ability to reference `current_user` and `current_visit` in API Actions
<img width="1149" alt="Screen Shot 2022-07-12 at 5 26 48 PM" src="https://user-images.githubusercontent.com/35935196/178598407-8d166da3-d9a4-499d-a3fb-4e78299edf31.png">



Addresses: #457

## Demo

https://user-images.githubusercontent.com/25191509/178464446-6f296166-c7dd-4f36-a957-001231cd7b90.mp4



## Email action
![Screenshot from 2022-07-11 20-12-18](https://user-images.githubusercontent.com/35935196/178379475-76ed12b5-bf8b-4a35-8102-60e5c927d601.png)
![Screenshot from 2022-07-11 20-11-57](https://user-images.githubusercontent.com/35935196/178379476-534183df-d251-406b-b0e7-f7197bed3bbe.png)


## HTTP Action
![Screenshot from 2022-07-11 17-57-56](https://user-images.githubusercontent.com/35935196/178365888-45273665-9617-4d97-919f-e29772ee2d17.png)
## example usage
![Screenshot from 2022-07-11 17-58-10](https://user-images.githubusercontent.com/35935196/178365941-ad6136eb-24ba-47a2-9928-46b11580e549.png)


Co-authored-by: Prashant Khadka <prashant.khadka052@gmail.com>
  • Loading branch information
donrestarone and alis-khadka authored Jul 14, 2022
1 parent 04155b6 commit c70610b
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 33 deletions.
6 changes: 6 additions & 0 deletions app/controllers/comfy/admin/api_actions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Comfy::Admin::ApiActionsController < Comfy::Admin::Cms::BaseController
before_action :ensure_authority_to_manage_api
before_action :set_api_action, except: :new
before_action :set_current_user_and_visit

def new
@index = params[:index]
Expand Down Expand Up @@ -31,4 +32,9 @@ def set_api_action
@api_namespace = ApiNamespace.find_by(id: params[:api_namespace_id])
@api_action = @api_namespace.executed_api_actions.find_by(id: params[:id])
end

def set_current_user_and_visit
Current.user = current_user
Current.visit = current_visit
end
end
6 changes: 6 additions & 0 deletions app/controllers/concerns/api_actionable.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module ApiActionable
extend ActiveSupport::Concern
included do
before_action :set_current_user_and_visit
before_action :initialize_api_actions, only: [:update, :show, :destroy]
before_action :check_for_redirect_action, only: [:create, :update, :show, :destroy]
after_action :execute_api_actions, only: [:show, :create, :update, :destroy]
Expand Down Expand Up @@ -95,6 +96,11 @@ def clone_actions(action_name)
end
end

def set_current_user_and_visit
Current.user = current_user
Current.visit = current_visit
end

def load_api_actions_from_api_resource
@redirect_action = @api_resource.send(api_action_name).where(action_type: 'redirect').reorder(:created_at).last if @redirect_action.present?
@serve_file_action = @api_resource.send(api_action_name).where(action_type: 'serve_file').reorder(:created_at).last if @serve_file_action.present?
Expand Down
6 changes: 2 additions & 4 deletions app/models/api_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ApiAction < ApplicationRecord
include DynamicAttribute

attr_encrypted :bearer_token
attr_dynamic :email, :email_subject, :custom_message, :payload_mapping, :request_url, :redirect_url
attr_dynamic :email, :email_subject, :custom_message, :payload_mapping, :custom_headers, :request_url, :redirect_url

after_update :update_executed_actions_payload, if: Proc.new { api_namespace.present? && saved_change_to_payload_mapping? }

Expand All @@ -26,8 +26,6 @@ class ApiAction < ApplicationRecord
has_rich_text :custom_message

validates :http_method, inclusion: { in: ApiAction::HTTP_METHODS}, allow_blank: true

validates :payload_mapping, safe_executable: true

def self.children
['new_api_actions', 'create_api_actions', 'show_api_actions', 'update_api_actions', 'destroy_api_actions', 'error_api_actions']
Expand Down Expand Up @@ -75,7 +73,7 @@ def redirect;end
def serve_file;end

def request_headers
headers = custom_headers.to_json.gsub('SECRET_BEARER_TOKEN', bearer_token)
headers = custom_headers_evaluated.gsub('SECRET_BEARER_TOKEN', bearer_token)
{ 'Content-Type' => 'application/json' }.merge(JSON.parse(headers))
end

Expand Down
9 changes: 9 additions & 0 deletions app/models/concerns/dynamic_attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ def attribute_value_string(attribute)
# Deep copy of non-enumerable column like string-type would get passed and the evaluated value would get reflected as change.
value.is_a?(Enumerable) ? value.to_json : value.to_s.dup
end

# Fetching session specific data should be defined here.
def current_user
Current.user
end

def current_visit
Current.visit
end
end

class_methods do
Expand Down
4 changes: 4 additions & 0 deletions app/models/current.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Current < ActiveSupport::CurrentAttributes
attribute :user
attribute :visit
end
62 changes: 50 additions & 12 deletions app/views/comfy/admin/api_actions/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,66 @@
%strong Last API Resource Instance Attributes:
.d-block
= last_instance.properties.keys
.mt-2.non-redirect-fields-guide{ style: "#{'display: none' if (resource.redirect? && resource.dynamic_url?)}"}

.mt-2.send-email-guide{ style: "#{ 'display: none' unless resource.send_email? }"}
.d-block
Dynamic:
%code
\\#{api_resource.properties['your_custom_attribute_here']}
.mt-2.redirect-field-guide{ style: "#{'display: none' unless (resource.redirect? && resource.dynamic_url?)}"}
%strong
Dynamic Fields:
Email address, Subject, Custom Message
.d-block
%strong
Available Variables:
api_resource, current_user, current_visit
.d-block
%strong
Dynamic:
%li
Email address:
%code
\\#{api_resource.properties['your_custom_attribute_here']}
%li
Subject:
%code
\\#{api_resource.properties['your_custom_attribute_here']} welcome!
%li
Custom Message:
%code
\We can help you with \#{api_resource.properties['your_custom_attribute_here']} !

.mt-2.send-web-request-guide{ style: "#{ 'display: none' unless resource.send_web_request? }"}
.d-block
%strong
Dynamic Fields:
Request Url, Request Body, Headers
.d-block
%strong
Available Variables:
api_resource, current_user, current_visit
.d-block
%strong
Dynamic:
%li
Request Url:
%code
\www.example.com/\#{api_resource.api_namespace.metadata["my_custom_attribute"]}
%li
Request Body and Headers:
%code
\\#{current_user.email}, \#{current_visit.browser}

.mt-2.redirect-field-guide{ style: "#{'display: none' unless (resource.redirect? && resource.dynamic_url?)}"}
.d-block
%strong
Dynamic Fields:
Redirect url
.d-block
%strong
Available Variables:
api_resource, current_user, current_visit, rails-route-helpers (example: comfy_admin_cms_path)
.d-block
Dynamic:
%code
\\#{ api_resource.properties['your_custom_attribute_here'] == 'true' ? comfy_admin_cms_path : some_other_path }
\\#{ api_resource.properties['your_custom_attribute_here'] == 'true' ? comfy_admin_cms_path : some_other_path }

.send_email.col-12{style: "#{'display:none' unless resource.action_type == 'send_email'}", id: "send_email_fields_#{type}_#{index}"}
.form-group
Expand Down Expand Up @@ -147,13 +189,9 @@
function toggleDynamicRedirectUrlGuide(element) {
const extraDetailsContainer = $(element).parents('.card').find('.extra-details');
if ($(element).val() == 'cms_page' && $(element).is(':checked')) {
extraDetailsContainer.hide();
extraDetailsContainer.find('.non-redirect-fields-guide').show();
extraDetailsContainer.find('.redirect-field-guide').hide();
manageRelatedExtraDetails(element, '.redirect-field-guide', false);
} else if ($(element).val() == 'dynamic_url' && $(element).is(':checked')) {
extraDetailsContainer.show();
extraDetailsContainer.find('.non-redirect-fields-guide').hide();
extraDetailsContainer.find('.redirect-field-guide').show();
manageRelatedExtraDetails(element, '.redirect-field-guide');
}
}

Expand Down
37 changes: 20 additions & 17 deletions app/views/comfy/admin/api_actions/action_workflow.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,24 @@
= f.submit 'Save'

:javascript
const guideClassNames = ['.non-redirect-fields-guide', '.redirect-field-guide'];
const guideClassNames = ['.send-email-guide', '.send-web-request-guide', '.redirect-field-guide'];

function toggleApiActionFields(index, type) {
var fieldType = $("#action_type_field_" + type + '_' + index).val();
hideAllFields(index, type)
if (fieldType === 'send_email') {
$("#send_email_fields_" + type + '_' + index).show();
showRelatedExtraDetails($("#send_email_fields_" + type + '_' + index), '.non-redirect-fields-guide');
manageRelatedExtraDetails($("#send_email_fields_" + type + '_' + index), '.send-email-guide');
} else if (fieldType === 'redirect') {
$("#redirect_fields_" + type + '_' + index).show();
if ($('#api_namespace_' + type + '_attributes_' + index + '_redirect_type_dynamic_url').is(':checked')) {
showRelatedExtraDetails($("#redirect_fields_" + type + '_' + index), '.redirect-field-guide');
manageRelatedExtraDetails($("#redirect_fields_" + type + '_' + index), '.redirect-field-guide');
}
} else if (fieldType === 'serve_file') {
$("#serve_file_fields_" + type + '_' + index).show();
} else if (fieldType === 'send_web_request') {
$("#serve_web_request_fields_" + type + '_' + index).show();
$("#serve_web_request_fields_" + type + '_' + index).parents('.card').find('.extra-details').show();
showRelatedExtraDetails($("#serve_web_request_fields_" + type + '_' + index), '.non-redirect-fields-guide');
manageRelatedExtraDetails($("#serve_web_request_fields_" + type + '_' + index), '.send-web-request-guide');
}
}

Expand All @@ -56,9 +55,9 @@
$("#serve_file_fields_" + type + '_' + index).hide();
$("#serve_web_request_fields_" + type + '_' + index).hide();

// Hiding the extra-details section and resetting the inline-documentation part.
// Hiding the extra-details section.
// The parent of all fields (send-email/redirect/send-web-request/serve-file) is same.
$("#serve_web_request_fields_" + type + '_' + index).parents('.card').find('.extra-details').hide();
manageRelatedExtraDetails($("#serve_web_request_fields_" + type + '_' + index), '.send-web-request-guide', false)
}

function removeForm(form_id, destroy_field_id) {
Expand All @@ -78,16 +77,20 @@
});
}

function showRelatedExtraDetails(element, actionType) {
$(element).parents('.card').find('.extra-details').show();
function manageRelatedExtraDetails(element, actionType, show = true) {
if (show) {
$(element).parents('.card').find('.extra-details').show();

// Showing the required guide according to actionType
guideClassNames.forEach(function(className) {
if (actionType == className) {
$(element).parents('.card').find('.extra-details').find(className).show();
} else {
$(element).parents('.card').find('.extra-details').find(className).hide();
}
});
// Showing the required guide according to actionType
guideClassNames.forEach(function(className) {
if (actionType == className) {
$(element).parents('.card').find('.extra-details').find(className).show();
} else {
$(element).parents('.card').find('.extra-details').find(className).hide();
}
});
} else {
$(element).parents('.card').find('.extra-details').hide();
}
}

2 changes: 2 additions & 0 deletions app/views/comfy/admin/api_actions/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
.mr-3
Payload:
= @api_action.payload_mapping_evaluated
-# payload_mapping_evaluated & custom_headers_evaluated will show current_user & current_visit according to the logged-in user.
-# TO DO: show the data that was evaluated while making the web-request instead of reevaluating on every request.
- if @api_action.action_type == 'redirect'
.col-12.d-flex.mb-3
Expand Down
37 changes: 37 additions & 0 deletions test/controllers/resource_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,42 @@ class ResourceControllerTest < ActionDispatch::IntegrationTest
end
end

test 'should allow #create with the current_user & current_visit being available in the send_web_request action' do
@api_namespace.api_form.update(properties: { 'name': {'label': 'name', 'placeholder': 'Test', 'type_validation': 'tel'}})

api_action = api_actions(:one)
api_action.update!(
type: 'CreateApiAction',
bearer_token: 'test-token',
position: 0,
action_type: 'send_web_request',
request_url: "http://www.example.com/success",
payload_mapping: {"email": '#{current_user.email}'},
custom_headers: {"User-Id": '#{current_visit.user_id}'},
http_method: 'post'
)
@api_namespace.api_actions.where.not(id: api_action.id).destroy_all
user = users(:public)
sign_in(user)

stub_post = stub_request(:post, "http://www.example.com/success").with(headers: { 'User-Id' => user.id.to_s }, body: {'email' => user.email}).to_return(:body => "abc")

payload = {
data: {
properties: {
name: 123,
}
}
}

assert_difference "@api_namespace.api_resources.count", +1 do
post api_namespace_resource_index_url(api_namespace_id: @api_namespace.id), params: payload
end

# Provided current_user & current_visit variable are available through send_web_request api-action
assert_requested stub_post
end

test 'should allow #create and redirect to evaluated redirect_url if redirect_type is dynamic_url' do
payload = {
data: {
Expand Down Expand Up @@ -300,6 +336,7 @@ class ResourceControllerTest < ActionDispatch::IntegrationTest
}
}
}

assert_difference "api_namespace.api_resources.count", +1 do
post api_namespace_resource_index_url(api_namespace_id: api_namespace.id), params: payload
end
Expand Down

0 comments on commit c70610b

Please sign in to comment.