diff --git a/custom_connectors/custom_auth/kizen.rb b/custom_connectors/custom_auth/kizen.rb index 95bd3228..528027ac 100644 --- a/custom_connectors/custom_auth/kizen.rb +++ b/custom_connectors/custom_auth/kizen.rb @@ -56,6 +56,87 @@ input end, + format_schema: lambda do |schema| + if schema.is_a?(Array) + schema.map do |array_value| + call('format_schema', array_value) + end + elsif schema.is_a?(Hash) + schema.map do |key, value| + if %w[name].include?(key.to_s) + value = call('replace_special_characters', value.to_s) + elsif %w[properties toggle_field].include?(key.to_s) + value = call('format_schema', value) + end + { key => value } + end.inject(:merge) + end + end, + + replace_special_characters: lambda do |input| + input.gsub(/[-<>!@#$%^&*()+={}:;'"`~,.?|]/, + '-' => '__hyp__', + '<' => '__lt__', + '>' => '__gt__', + '!' => '__excl__', + '@' => '__at__', + '#' => '__hashtag__', + '$' => '__dollar__', + '%' => '__percent__', + '^' => '__pwr__', + '&' => '__amper__', + '*' => '__star__', + '(' => '__lbracket__', + ')' => '__rbracket__', + '+' => '__plus__', + '=' => '__eq__', + '{' => '__rcrbrack__', + '}' => '__lcrbrack__', + ';' => '__semicol__', + '\'' => '__apost__', + '`' => '__bckquot__', + '~' => '__tilde__', + ',' => '__comma__', + '.' => '__period__', + '?' => '__qmark__', + '|' => '__pipe__', + ':' => '__colon__', + '\"' => '__quote__') + end, + + inject_special_characters: lambda do |input| + input.gsub( + /(__hyp__|__lt__|__gt__|__excl__|__at__|__hashtag__|__dollar__|\__percent__|__pwr__|__amper__|__star__|__lbracket__|__rbracket__|__plus__|__eq__|__rcrbrack__|__lcrbrack__|__semicol__|__apost__|__bckquot__|__tilde__|__comma__|__period__|__qmark__|__pipe__|__colon__|__quote__|__slash__|__bslash__)/, + '__hyp__' => '-', + '__lt__' => '<', + '__gt__' => '>', + '__excl__' => '!', + '__at__' => '@', + '__hashtag__' => '#', + '__dollar__' => '$', + '__percent__' => '%', + '__pwr__' => '^', + '__amper__' => '&', + '__star__' => '*', + '__lbracket__' => '(', + '__rbracket__' => ')', + '__plus__' => '+', + '__eq__' => '=', + '__rcrbrack__' => '{', + '__lcrbrack__' => '}', + '__semicol__' => ';', + '__apost__' => '\'', + '__bckquot__' => '`', + '__tilde__' => '~', + '__comma__' => ',', + '__period__' => '.', + '__qmark__' => '?', + '__pipe__' => '|', + '__colon__' => ':', + '__quote__' => '"' + ) + end, + format_output: lambda do |result| if result['custom_fields'].present? result['custom_fields'] = result['custom_fields'] @@ -90,6 +171,119 @@ object_definitions: { + log_activity_input: { + fields: lambda do |_| + custom_fields = get('/api/activity-type')&. + map do |field| + { name: "#{field['id']}~#{field['uid']}", + label: field['name'], type: field['type'] } + end + standard_fields = [ + { name: 'client', label: 'Contact ID', optional: false }, + { name: 'activity_type_id', + label: 'Activity', + control_type: 'select', + pick_list: 'activities', + optional: false }, + { name: 'custom_fields', + type: 'object', properties: custom_fields } + ] + call('format_schema', standard_fields) + end + }, + + contact_fields_output: { + fields: lambda do |_| + custom_fields = get('/api/client-field')&. + map do |field| + { name: field['id'], + label: field['name'], type: field['type'] } + end + standard_fields = [ + { name: 'id', type: 'integer', control_type: 'number', + label: 'Contact id' }, + { name: 'first_name' }, + { name: 'last_name' }, + { name: 'email' }, + { name: 'mobile_phone' }, + { name: 'company', + hint: 'The company at which the candidate currently works' }, + { name: 'titles', hint: 'The candidate’s current title' }, + { name: 'created', type: 'date_time', control_type: 'date_time' }, + { name: 'custom_fields', + type: 'object', properties: custom_fields } + ] + call('format_schema', standard_fields) + end + }, + + company_fields_trigger_output: { + fields: lambda do |_| + custom_fields = get('/api/company-field')&. + map do |field| + { name: field['handle'], + label: field['name'], type: field['type'] } + end + standard_fields = [ + { name: 'id', type: 'integer', control_type: 'number', + label: 'Company id' }, + { name: 'name', label: 'Company Name' }, + { name: 'business_phone' }, + { name: 'email' }, + { name: 'mobile_phone' }, + { name: 'custom', label: 'Custom fields', + type: 'object', properties: custom_fields } + ] + call('format_schema', standard_fields) + end + }, + + contact_fields_trigger_output: { + fields: lambda do |_| + custom_fields = get('/api/client-field')&. + map do |field| + { name: field['handle'], + label: field['name'], type: field['type'] } + end + standard_fields = [ + { name: 'id', label: 'Contact id' }, + { name: 'first_name' }, + { name: 'last_name' }, + { name: 'email' }, + { name: 'mobile_phone' }, + { name: 'company', + hint: 'The company at which the candidate currently works' }, + { name: 'titles', hint: 'The candidate’s current title' }, + { name: 'created', type: 'date_time', control_type: 'date_time' }, + { name: 'custom', label: 'Custom fields', + type: 'object', properties: custom_fields } + ] + call('format_schema', standard_fields) + end + }, + + deal_fields_trigger_output: { + fields: lambda do |_| + custom_fields = get('/api/deal-custom-field')&. + map do |field| + { name: field['handle'], + label: field['name'], type: field['type'] } + end + standard_fields = [ + { name: 'id', type: 'integer', control_type: 'number', + label: 'Deal ID' }, + { name: 'name', label: 'Deal Name' }, + { name: 'amount', type: 'float' }, + { name: 'owner' }, + { name: 'stage' }, + { name: 'pipeline' }, + { name: 'custom', label: 'Custom fields', + type: 'object', properties: custom_fields } + ] + call('format_schema', standard_fields) + end + }, + object_input: { fields: lambda do |_connection, config_fields| case config_fields['object'] @@ -632,8 +826,309 @@ get("https://api.kizen.com/#{input['object']}?page=1&page_size=1") .dig('results', 0) end - } + }, + log_interaction: { # This is new + title: 'Log an interaction', + subtitle: 'Log an interaction', + description: lambda do + "Log an interaction in Kizen" + end, + input_fields: lambda do + [ + { name: 'client_id', Label: 'Contact ID', optional: false }, + { name: 'business_id', Label: 'Business ID', optional: false }, + { name: 'name', Label: 'Interaction Name', optional: false }, + { name: 'property_label1', Label: 'Property Label1', optional: true }, + { name: 'property_label2', Label: 'Property Label2', optional: true }, + { name: 'property_input1', Label: 'Property Input1', optional: true }, + { name: 'property_input2', Label: 'Property Input 2', optional: true } + ] + end, + execute: lambda do |_connection, input| + post('https://app.kizen.com/api/interaction') + .payload( + 'business_id': input['business_id'], + 'client_id': input['client_id'], + 'name': input['name'], + 'properties': { + "#{input['property_label1']}" => input['property_input1'], + "#{input['property_label2']}" => input['property_input2'] + } + ) + end, + output_fields: lambda do + [ + { name: 'id'} + ] + end, + }, + + add_custom_lead_source: { # This is new here + title: 'Add Custom Lead Source to a Contact', + subtitle: 'Add Custom Lead Source to a Contact', + description: lambda do + "Add Custom Lead Source to a Contact" + end, + + input_fields: lambda do + [ + { name: 'client_id', Label: 'Contact ID', optional: false }, + { name: 'source', + Label: 'Custom Lead Source', + control_type: 'select', + pick_list: 'lead_sources', + hint: 'To add Custom Lead Sources, + navigate inside a contact record and add a custom source', + optional: false }, + { name: 'campaign', Label: 'Campaign Name', optional: true }, + { name: 'medium', Label: 'Medium', optional: true }, + { name: 'term', Label: 'Term', optional: true }, + { name: 'content', Label: 'Content', optional: true } + ] + end, + execute: lambda do |_connection, input| + post('https://app.kizen.com/api/lead-source-custom-source') + .payload( + 'client': input['client_id'], + 'source': input['source'], + 'campaign': input['campaign'], + 'medium': input['medium'], + 'term': input['term'], + 'content': input['content'] + ) + end, + + output_fields: lambda do + [ + { name: 'id' }, + { name: 'client', Label: 'Contact ID' } + ] + end }, +log_activity: { # This is new + title: 'Log an Activity', + subtitle: 'Log an Activity', + description: lambda do + "Log an activity in Kizen" + end, + + input_fields: lambda do |object_definitions| + object_definitions['log_activity_input'] + end, + execute: lambda do |_connection, input| + format_input = call('format_input', input) + payload = format_input.map do |key, value| + if key.include?('custom_fields') + custom_fields = value&.map do |k, v| + { k.split('~').last => + { + 'field_id' => k.split('~').first, + 'value' => v + } } + end&.inject(:merge) + { 'custom_fields' => custom_fields } + else + { key => value } + end + end.inject(:merge) + result = post('/api/logged-activity', payload) + formatted_response = + result.map do |key, value| + if key.include?('custom_fields') + custom_fields = value.values&.map do |object| + { object['field_id'] => object['value'] } + end&.inject(:merge) + { 'custom_fields' => custom_fields } + else + { key => value } + end + end&.inject(:merge) + call('format_output', formatted_response.compact) + end, + + output_fields: lambda do + [ + { name: 'id' } + ] + end +}, +find_contact_by_email: { # This is new + title: 'Find contact by email', + subtitle: 'Find a contact in Kizen by email', + description: lambda do + "Find a contact contact in Kizen by email" + end, + + input_fields: lambda do + [ + { + name: 'email', + label: 'Contact Email', + optional: false + } + ] + end, + + execute: lambda do |_connection, input| + results = get("https://app.kizen.com/api/client?email=#{input['email']}") + records = results['results'] + { + events: records + } + end, + + output_fields: lambda do |object_definitions| + { name: 'events', type: 'array', of: 'object', + properties: object_definitions['contact_fields_trigger_output'] } + end +}, +find_contact_by_id: { # This is new + title: 'Find contact by ID', + subtitle: 'Find a contact in Kizen by ID', + description: lambda do + "Find a contact contact in Kizen by ID " + end, + + input_fields: lambda do + [ + { + name: 'id', + label: 'Contact ID', + optional: false + } + ] + end, + + execute: lambda do |_connection, input| + result = get("https://app.kizen.com/api/client/#{input['id']}") + + formatted_response = + result.map do |key, value| + if key.include?('custom_fields') + custom_fields = value.values&.map do |object| + { object['field_id'] => object['value'] } + end&.inject(:merge) + { 'custom_fields' => custom_fields } + else + { key => value } + end + end&.inject(:merge) + call('fformat_output', formatted_response.compact) + end, + + output_fields: lambda do |object_definitions| + object_definitions['contact_fields_output'] + end +}, +find_company_by_name: { # This is new + title: 'Find company by name', + subtitle: 'Find a company in Kizen by name', + description: lambda do + "Find a company contact in Kizen" + end, + + input_fields: lambda do + [ + { + name: 'name', + label: 'Company Name', + optional: false + } + ] + end, + + execute: lambda do |_connection, input| + results = get("https://app.kizen.com/api/company?search=#{input['name']}") + records = results['results'] + { + events: records + } + end, + + output_fields: lambda do |object_definitions| + { name: 'events', type: 'array', of: 'object', + properties: object_definitions['company_fields_trigger_output'] } + end +}, + +find_deal_by_name: { # This is new + title: 'Find deal by name', + subtitle: 'Find a deal in Kizen by name', + description: lambda do + "Find a deal by name" + end, + + input_fields: lambda do + [ + { + name: 'name', + label: 'Deal Name', + optional: false + } + ] + end, + + execute: lambda do |connection, input| + results = get("https://app.kizen.com/api/deal?search=#{input["name"]}") + records = results["results"] + { + events: records + } + end, + + output_fields: lambda do |object_definitions| + { name: 'events', type: 'array', of: 'object', + properties: object_definitions['deal_fields_trigger_output'] } + end +}, + +create_order: { # This is new + title: 'Create order', + + input_fields: lambda do + [ + { name: 'email', optional: false }, + { name: 'order_status', + optional: false, + control_type: 'select', + pick_list: 'order_status' }, + { name: 'order_number', optional: false, hint: 'Must be an integer' }, + { name: 'created', optional: false, hint: '(YYYY-MM-DD)' }, + { name: 'sku', label: 'SKU', optional: false }, + { name: 'name', optional: false, label: 'Product Name' }, + { name: 'price', optional: false }, + { name: 'quantity', + optional: false, + hint: 'Must be a number without decimal places, 1.00 will not work' } + ] + end, + + execute: lambda do |_connection, input| + post('https://app.kizen.com/api/commerce/orders') + .payload( + 'order_status': input['order_status'], + 'order_number': input['order_number'], + 'created': input['created'], + 'client': { 'email': input['email'] }, + 'upload': true, + 'line_items': [ + { 'price': input['price'], + 'sku': input['sku'], + 'name': input['name'], + 'quantity': input['quantity'] } + ] + ) + end, + + output_fields: lambda do + [ + { name: 'id' }, + { name: 'cart' }, + { name: 'client' } + ] + end +} +}, triggers: { new_object: { @@ -744,9 +1239,206 @@ get("https://api.kizen.com/#{input['object']}?page=1&page_size=1") .dig('results', 0) end + }, + new_order: { + title: 'New Order', + subtitle: 'New Order in Kizen', + description: lambda do + "New Order in Kizen" + end, + + poll: lambda do |_connection, _input, page| + page_size = 50 + page ||= 1 + response = get('https://app.kizen.com/api/commerce/orders') + .params(order_by: 'created', + order_type: 'asc', + page: page, + per_page: page_size + ) + records = response&.[]('results') || [] + page = records.size >= page_size ? page + 1 : 1 + { + events: records, + next_page: page, + can_poll_more: records.size >= page_size + } + end, + + dedup: lambda do |contact| + contact['id'] + end, + + output_fields: lambda do + [ + { name: 'id' }, + { name: 'client' } + ] + end + }, + + new_scheduled_activity: { # I'm having trouble parsing the output + title: 'New Scheduled Activity', + subtitle: 'New Scheduled Activity in Kizen', + description: lambda do + "New scheduled activity in Kizen" + end, + + input_fields: lambda do + [ + { name: 'activities', + label: 'Activities', + control_type: 'select', + pick_list: 'activities', + optional: false } + ] + end, + + poll: lambda do |_connection, input, page| + page_size = 50 + activity_id = input['activities'] + page ||= 1 + response = get("https://app.kizen.com/api/scheduled-activity?activity_type=#{activity_id}") + .params(order_by: 'created', + order_type: 'asc', + page: page, + per_page: page_size) + + records = response&.[]('results') || [] + page = records.size >= page_size ? page + 1 : page + { + events: records, + next_page: page, + can_poll_more: records.size >= page_size + } + end, + + dedup: lambda do |deal| + deal['id'] + end, + + output_fields: lambda do + [ + { name: 'id' }, + { name: 'assigned_to' }, + { name: 'client' }, # This is an array that needs to be split up. + { name: 'company' }, # Need workato's help on this one. + { name: 'deal' }, + { name: 'scheduled' } + ] + end + + }, + +updated_contact: {# This is new + + input_fields: ->() { + }, + + poll: ->(connection, input, last_updated_since) { + updated_since = last_updated_since || input['since'] || Time.now + + contacts = get('https://app.kizen.com/api/client-field-revision') + .params( + order_by: 'updated_at', + order_type: 'asc', + per_page: 2, + updated_since: updated_since.to_time.utc.iso8601 + ) + contacts = contacts['results'] + + next_updated_since = contacts.last['updated_at'] unless contacts.blank? + + { + events: contacts, + next_poll: next_updated_since, + can_poll_more: contacts.length >= 2 } }, + dedup: ->(contacts) { + contacts['id'] + }, + + output_fields: lambda do + [ + { + name: 'id' + }, + { + name: 'client' + }, + { + name: 'custom_field_name' + }, + { + name: 'custom_field' + }, + { + name: 'new_value' + } + ] + end +}, + +new_logged_activity: {# I'm having trouble parsing the output on this + title: 'New Logged Activity', # Will need help from Workato + subtitle: 'New Logged Activity in Kizen', + description: lambda do + "New logged activity in Kizen" + end, + + input_fields: lambda do + [ + { + name: 'activities', + label: 'Activities', + control_type: 'select', + pick_list: 'activities', + optional: false + } + ] + end, + # The output is an array that needs to be split up. How can I do this? + # Need workato's help on this one + poll: lambda do |_connection, input, page| + page_size = 50 + activity_id = input['activities'] + page ||= 1 + response = get("https://app.kizen.com/api/logged-activity?activity_type_id=#{activity_id}") + .params( + order_by: 'created', + order_type: 'asc', + page: page, + per_page: page_size + ) + records = response&.[]('results') || [] + page = records.size >= page_size ? page + 1 : page + { + events: records, + next_page: page, + can_poll_more: records.size >= page_size + } + end, + + dedup: lambda do |deal| + deal['id'] + end, + + output_fields: lambda do + [ + { name: 'id' }, + { name: 'activity_type' }, + { name: 'client' }, + { name: 'company' }, + { name: 'deal' }, + { name: 'employee' }, + { name: 'created' } + ] + end +} +}, + pick_lists: { pipelines: lambda do |_connection| get('/api/deal-pipeline')['results']&.map do |res| @@ -783,6 +1475,24 @@ [res['full_name'].presence || 'unknown', res['id']] end end, + + activities: lambda do |_connection| + url = 'https://app.kizen.com/api/activity-type?fields=id,name,created' + get(url).pluck('name', 'id') + end, + + lead_sources: lambda do |_connection| + url = 'https://app.kizen.com/api/lead-source-custom-source-type' + get(url)['results'].pluck('name', 'id') + end, + + + order_status: lambda do |_connection| + [ + # Display name, value + ['paid', 'paid'] + ] + end, kizen_objects: lambda do [