└── custom_connectors
├── basic_auth
├── onprem_security.rb
├── click_time_connector.rb
├── harvest_connector.rb
├── close_io_connector.rb
├── docparser_connector.rb
├── webmerge_connector.rb
├── watson_tone_analyzer_connector.rb
├── unbounce_connector.rb
├── toggl_connector.rb
├── freshdesk_connector.rb
├── salesforceiq_connector.rb
├── splunk_connector.rb
└── clearbit_connector.rb
├── none
├── password_generator.rb
├── statuspage.rb
└── rssfeedreader.rb
├── api_key_auth
├── gender_api_connector.rb
├── ops_genie_connector.rb
├── hipchat_connector.rb
├── codeship_connector.rb
├── rightsignature_connector.rb
├── mandrill_connector.rb
└── aftership_connector.rb
├── custom_auth
├── knack_hq_connector.rb
├── tsheets_connector.rb
├── infobip_connector.rb
├── lo_jack_connector.rb
├── safetyculture_connector.rb
├── convert_api_connector.rb
├── bill_connector.rb
├── blacklinereports.rb
├── neto_connector.rb
└── domo.rb
└── oauth2
├── pushbullet_connector.rb
├── wachete_connector.rb
├── accelo_connector.rb
├── linenotify.rb
├── podio_connector.rb
├── amcards_connector.rb
├── cisco_spark_connector.rb
├── typeform_connector.rb
├── wrike_connector.rb
├── formassembly.rb
└── ephesoft_connector.rb
/custom_connectors/basic_auth/onprem_security.rb:
--------------------------------------------------------------------------------
1 | {
2 | # Works with the custom security extension profile for
3 | # Workato OPA: https://github.com/workato/opa-extensions/blob/master/src/main/java/com/mycompany/onprem/SecurityExtension.java
4 | title: 'On-prem security',
5 | secure_tunnel: true,
6 |
7 | connection: {
8 | fields: [{ name: 'profile', hint: 'On-prem security connection profile' }],
9 | authorization: { type: 'none'}
10 | },
11 |
12 | test: ->(connection) {
13 | post("http://localhost/ext/#{connection['profile']}", { payload: 'test' }).headers('X-Workato-Connector': 'enforce')
14 | },
15 |
16 | actions: {
17 | sha256_digest: {
18 |
19 | title: 'Create SHA-256 digest',
20 | description: 'Create SHA-256 digest',
21 |
22 | input_fields: ->(_) { [{ name: 'payload' }] },
23 | output_fields: ->(_) { [{name: 'signature'}] },
24 |
25 | execute: ->(connection, input) {
26 | post("http://localhost/ext/#{connection['profile']}", input).headers('X-Workato-Connector': 'enforce')
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/custom_connectors/none/password_generator.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Password Generator',
3 |
4 | connection: {
5 | authorization: {},
6 | },
7 | object_definitions: {},
8 |
9 | test: ->(connection) {
10 | true
11 | },
12 | actions: {
13 | generate_password: {
14 | execute: ->() {
15 | letters_list = [
16 | ('!'..'/').to_a + (':'..'@').to_a + ('['..'`').to_a + ('{'..'~').to_a,
17 | ('0'..'9').to_a,
18 | ('A'..'Z').to_a,
19 | ('a'..'z').to_a
20 | ].sort_by { |n| rand(4) }
21 |
22 | password_size = 8
23 | req_chars_size = letters_list.size
24 | other_chars_size = password_size - req_chars_size
25 | index_list =
26 | (0...req_chars_size).to_a.sort_by { rand(req_chars_size) } +
27 | (0...other_chars_size).to_a.map { rand(other_chars_size) }
28 |
29 | password = (0...password_size).to_a.map do |n|
30 | letters = letters_list[index_list[n]]
31 | letters[rand(letters.size)]
32 | end.join
33 | {
34 | password: password
35 | }
36 | },
37 | output_fields: ->() {
38 | [
39 | { name: 'password' }
40 | ]
41 | },
42 | sample_output: ->() {
43 | { password: 'P@s19ser' }
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/click_time_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Click Time',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'username',
8 | optional: true,
9 | hint: 'Your email used for login'
10 | },
11 | {
12 | name: 'password',
13 | control_type: 'password',
14 | }
15 | ],
16 |
17 | authorization: {
18 | type: 'basic_auth',
19 |
20 | credentials: ->(connection) {
21 | user(connection['username'])
22 | password(connection['password'])
23 | }
24 | }
25 | },
26 |
27 | object_definitions: {
28 | session: {
29 | fields: ->() {
30 | [
31 | { name: 'CompanyID' },
32 | { name: 'SecurityLevel' },
33 | { name: 'Token' },
34 | { name: 'UserEmail' },
35 | { name: 'UserID' },
36 | { name: 'UserName' }
37 | ]
38 | }
39 | }
40 | },
41 |
42 | test: ->(connection) {
43 | get("https://app.clicktime.com/api/1.3/session")
44 | },
45 |
46 | actions: {
47 | get_user_and_company_id: {
48 | input_fields: ->() {
49 | },
50 |
51 | execute: -> (connection, input) {
52 | get("https://app.clicktime.com/api/1.3/session")
53 | },
54 |
55 | output_fields: -> (object_definitions) {
56 | object_definitions['session']
57 | }
58 | }
59 | },
60 |
61 | triggers: {}
62 | }
63 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/gender_api_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Gender',
3 |
4 | connection: {
5 |
6 | fields: [
7 | {
8 | name: 'key',
9 | hint: 'Your Gender API Private Server Key',
10 | optional: false
11 | },
12 | ],
13 |
14 | authorization: {
15 | type: 'api_key',
16 |
17 | credentials: ->(connection) {
18 | params(key: connection['key'])
19 | }
20 | }
21 | },
22 |
23 | test: ->(connection) {
24 | get("https://gender-api.com/get?name=matthew")
25 | },
26 |
27 | object_definitions: {
28 |
29 | person: {
30 | fields: ->() {
31 | [
32 | { name: 'name' },
33 | { name: 'gender' },
34 | { name: 'samples', type: :integer },
35 | { name: 'accuracy', type: :integer }
36 | ]
37 | }
38 | }
39 | },
40 |
41 | actions: {
42 |
43 | get_gender: {
44 |
45 | input_fields: ->(object_definitions) {
46 | [
47 | { name: 'name', optional: false},
48 | { name: 'country', hint: '2 Letter country code. Click here for list.' }
49 | ]
50 | },
51 |
52 | execute: ->(connection, input) {
53 | {
54 | person: get("https://gender-api.com/get", input)
55 | }
56 | },
57 |
58 | output_fields: ->(object_definitions) {
59 | [
60 | { name: "person", type: :object,
61 | properties: object_definitions['person']}
62 | ]
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/knack_hq_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Knack HQ',
3 |
4 | connection: {
5 | fields: [
6 | { name: 'app_id', optional: false },
7 | { name: 'api_key', control_type: 'password', optional: false }
8 | ],
9 |
10 | authorization: {
11 | type: 'custom_auth',
12 |
13 | credentials: ->(connection) {
14 | headers('X-Knack-Application-Id': connection['app_id'],
15 | 'X-Knack-REST-API-Key': connection['api_key'])
16 | }
17 | }
18 | },
19 |
20 | test: ->(connection) {
21 | get("https://api.knackhq.com/v1/objects")
22 | },
23 |
24 | object_definitions: {
25 | object_1: {
26 | fields: ->(connection) {
27 | get("https://api.knackhq.com/v1/objects/object_1/fields")['fields'].
28 | map { |f| { name: f['key'], label: f['label'] } }
29 | }
30 | }
31 | },
32 |
33 | actions: {
34 |
35 | get_object_1_by_id: {
36 | input_fields: ->(object_definitions) {
37 | [
38 | { name: 'id', optional: false }
39 | ]
40 | },
41 |
42 | execute: ->(connection,input) {
43 | get("https://api.knackhq.com/v1/objects/object_1/records/#{input['id']}")
44 | },
45 |
46 | output_fields: -> (object_definitions) {
47 | object_definitions['object_1']
48 | }
49 | }
50 | },
51 |
52 | triggers: {
53 | new_object_1_record: {
54 | type: :paging_desc,
55 |
56 | input_fields: -> (object_definitions) {},
57 |
58 | poll: ->(connection,input,page) {
59 | page ||= 1
60 |
61 | response = get("https://api.knackhq.com/v1/objects/object_1/records").
62 | params(sort_field: 'id',
63 | sort_order: 'desc',
64 | page: page)
65 |
66 | next_page = response['total_pages'] == response['current_page'].to_i ? nil : (page + 1)
67 |
68 | {
69 | events: response['records'],
70 | next_page: next_page
71 | }
72 | },
73 |
74 | output_fields: -> (object_definitions) {
75 | object_definitions['object_1']
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/pushbullet_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Pushbullet',
3 |
4 | connection: {
5 | authorization: {
6 | type: 'oauth2',
7 |
8 | authorization_url: ->() {
9 | 'https://www.pushbullet.com/authorize?response_type=code'
10 | },
11 |
12 | token_url: ->() {
13 | 'https://api.pushbullet.com/oauth2/token'
14 | },
15 |
16 | client_id: 'abababababab',
17 |
18 | client_secret: 'cdcdcdcdcdcd',
19 |
20 | credentials: ->(connection, access_token) {
21 | headers('Authorization': "Bearer #{access_token}")
22 | }
23 | }
24 | },
25 |
26 | object_definitions: {
27 | push: {
28 | fields: ->() {
29 | [
30 | { name: 'active', type: :boolean },
31 | { name: 'body' },
32 | { name: 'created' },
33 | { name: 'direction' },
34 | { name: 'dismissed', type: :boolean },
35 | { name: 'iden' },
36 | { name: 'modified' },
37 | { name: 'receiver_email' },
38 | { name: 'receiver_email_normalized' },
39 | { name: 'receiver_iden' },
40 | { name: 'sender_email' },
41 | { name: 'sender_email_normalized' },
42 | { name: 'sender_iden' },
43 | { name: 'sender_name' },
44 | { name: 'title' },
45 | { name: 'type' },
46 | ]
47 | }
48 | }
49 | },
50 |
51 | actions: {
52 | create_a_push: {
53 | input_fields: ->() {
54 | [
55 | { name: 'email', optional: false },
56 | { name: 'type', type: :select, optional: false, pick_list: [
57 | ["Note","note"],
58 | ["Link","link"],
59 | ["File","file"]
60 | ]},
61 | { name: 'title', optional: false },
62 | { name: 'body', optional: false },
63 | { name: 'url', hint: 'Required if type set to Link or File' },
64 | { name: 'file_type', hint: 'Required if type set to File' }
65 | ]
66 | },
67 | execute: ->(connection,input) {
68 | post("https://api.pushbullet.com/v2/pushes", input)
69 | },
70 | output_fields: ->(object_definitions) {
71 | object_definitions['push']
72 | }
73 | }
74 | },
75 |
76 | triggers: {}
77 | }
78 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/harvest_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Harvest',
3 |
4 | # HTTP basic auth example.
5 | connection: {
6 | fields: [
7 | {
8 | name: 'subdomain',
9 | control_type: 'subdomain',
10 | url: '.harvestapp.com',
11 | hint: 'The subdomain found in your Harvest URL'
12 | },
13 | {
14 | name: 'username'
15 | },
16 | {
17 | name: 'password',
18 | control_type: 'password'
19 | }
20 | ],
21 |
22 | authorization: {
23 | type: 'basic_auth',
24 |
25 | # Basic auth credentials are just the username and password; framework handles adding
26 | # them to the HTTP requests.
27 | credentials: ->(connection) {
28 | user(connection['username'])
29 | password(connection['password'])
30 | }
31 | }
32 | },
33 |
34 | object_definitions: {
35 | },
36 |
37 | test: ->(connection) {
38 | get("https://#{connection['subdomain']}.harvestapp.com/account/who_am_i")
39 | },
40 |
41 | actions: {
42 | search_users: {
43 | # not used
44 | input_fields: ->(object_definitions) {
45 | },
46 |
47 | execute: ->(connection, input) {
48 | # harvest returns an array with each user wrapped in a hash [ { user: {} }, ..]
49 | # extract the object
50 | results = get("https://#{connection['subdomain']}.harvestapp.com/people.json", input).map do |row|
51 | row['user']
52 | end
53 |
54 | { results: results }
55 | },
56 | output_fields: ->(object_definitions) {
57 | [
58 | {
59 | name: 'users',
60 | type: 'array',
61 | of: 'object',
62 | properties: [
63 | { name: 'id', type: 'integer' },
64 | { name: 'first_name' },
65 | { name: 'last_name' },
66 | { name: 'email' },
67 | { name: 'telephone' },
68 | { name: 'department' },
69 | { name: 'cost_rate' },
70 | { name: 'is_admin', type: 'boolean' },
71 | { name: 'is_active', type: 'boolean' },
72 | { name: 'is_contractor', type: 'boolean' },
73 | { name: 'has_access_to_all_future_projects', type: 'boolean' },
74 | { name: 'created_at', type: 'date_time' },
75 | { name: 'updated_at', type: 'date_time' },
76 | ]
77 | }
78 | ]
79 | }
80 | }
81 | },
82 | }
83 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/wachete_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "Wachete",
3 |
4 | connection: {
5 | authorization: {
6 | type: "oauth2",
7 |
8 | authorization_url: lambda do
9 | "https: //www.wachete.com/login"
10 | end,
11 |
12 | token_url: lambda do
13 | "https: //api.wachete.com/v1/oauth/token"
14 | end,
15 |
16 | client_id: "WACHETE_CLIENT_ID",
17 |
18 | client_secret: "WACHETE_CLIENT_SECRET",
19 |
20 | credentials: lambda do |_connection, access_token|
21 | headers("Authorization": "bearer #{access_token}")
22 | end
23 | }
24 | },
25 |
26 | object_definitions: {
27 | notification: {
28 | fields: lambda do
29 | [
30 | {
31 | name: "id",
32 | },
33 | {
34 | name: "task",
35 | type: :object,
36 | properties: [
37 | {
38 | name: "definition",
39 | type: :object,
40 | properties: [
41 | {
42 | name: "name",
43 | hint: "Name of wachet you received notification for"
44 | }
45 | ]
46 | }
47 | ]
48 | },
49 | {
50 | name: "timestampUtc",
51 | label: "Timestamp",
52 | type: :timestamp,
53 | hint: "Time when notification happened"
54 | },
55 | {
56 | name: "current",
57 | hint: "Current value of wachet"
58 | },
59 | {
60 | name: "comparand",
61 | hint: "Previous value of wachet"
62 | },
63 | {
64 | name: "type",
65 | hint: "Type of notification"
66 | }
67 | ]
68 | end
69 | }
70 | },
71 |
72 | test: lambda do |_connection|
73 | get("https://api.wachete.com/v1/task/get")
74 | end,
75 |
76 | triggers: {
77 | new_notification: {
78 | poll: lambda do |_connection, _input, _last_updated_since|
79 | notifications = get("https://api.wachete.com/v1/alert/range").
80 | params(from: "2006-01-25T10: 37: 23.574Z",
81 | to: "2030-01-23T10: 37: 23.574Z",
82 | count: 1)
83 | {
84 | events: notifications["data"]
85 | }
86 | end,
87 |
88 | dedup: lambda do |notification|
89 | notification["id"]
90 | end,
91 |
92 | output_fields: lambda do |object_definitions|
93 | object_definitions["notification"]
94 | end
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/ops_genie_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "OpsGenie",
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "key",
8 | hint: "Find your OpsGenie API key " \
9 | "here.",
10 | optional: false
11 | }
12 | ],
13 |
14 | authorization: {
15 | type: "api_key",
16 |
17 | credentials: lambda do |connection|
18 | headers("Authorization": "GenieKey #{connection['key']}")
19 | end
20 | },
21 |
22 | base_uri: lambda do
23 | "https://api.opsgenie.com"
24 | end
25 | },
26 |
27 | test: lambda do
28 | get("/v2/alerts")
29 | end,
30 |
31 | object_definitions: {
32 | alert: {
33 | fields: lambda do |_connection, _config_fields|
34 | [
35 | { name: "message", optional: false },
36 | { name: "alias" },
37 | { name: "description" },
38 | { name: "responders", type: :object, properties: [
39 | { name: "id" },
40 | { name: "name" },
41 | { name: "username" },
42 | { name: "type" }
43 | ] },
44 | { name: "visibleTo", type: :object, properties: [
45 | { name: "id" },
46 | { name: "name" },
47 | { name: "username" },
48 | { name: "type" }
49 | ] },
50 | { name: "entity" },
51 | { name: "priority", control_type: "select", pick_list: "priorities" }
52 | ]
53 | end
54 | }
55 | },
56 |
57 | actions: {
58 | create_alert: {
59 | title: "Create an alert",
60 | description: "Create alert in " \
61 | "OpsGenie",
62 |
63 | input_fields: lambda do |object_definitions|
64 | object_definitions["alert"]
65 | end,
66 |
67 | execute: lambda do |_connection, input|
68 | post("https://api.opsgenie.com/v2/alerts", input)
69 | end,
70 |
71 | output_fields: lambda do |_object_definitions|
72 | [
73 | { name: "result" },
74 | { name: "took", type: "number" },
75 | { name: "requestId" }
76 | ]
77 | end,
78 |
79 | sample_output: lambda do |_object_definitions|
80 | {
81 | "result": "Request will be processed",
82 | "took": 0.302,
83 | "requestId": "43a29c5c-3dbf-4fa4-9c26-f4f71023e120"
84 | }
85 | end
86 | }
87 | },
88 |
89 | pick_lists: {
90 | priorities: lambda do |_connection|
91 | [
92 | %w[P1 P1],
93 | %w[P2 P2],
94 | %w[P3 P3],
95 | %w[P4 P4],
96 | %w[P5 P5]
97 | ]
98 | end
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/hipchat_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Hipchat',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'subdomain',
8 | control_type: 'subdomain',
9 | url: '.hipchat.com',
10 | optional: false,
11 | hint: 'Enter your subdomain'
12 | },
13 | {
14 | name: 'auth_token',
15 | control_type: 'password',
16 | optional: false,
17 | label: "Access token",
18 | hint: 'Go to Account Settings->API Access. Enter password and get token'
19 | },
20 | ],
21 |
22 | authorization: {
23 | type: 'auth_token',
24 | credentials: ->(connection) {
25 | params(auth_token: connection['auth_token'])
26 | }
27 | }
28 | },
29 |
30 | object_definitions: {
31 |
32 | message: {
33 | fields: ->() {
34 | [
35 | { name: 'id', hint: "ID of the message" },
36 | { name: 'timestamp' }
37 | ]
38 | }
39 | }
40 | },
41 |
42 | test: ->(connection) {
43 | get("https://#{connection['subdomain']}.hipchat.com/v2/room")
44 | },
45 |
46 | actions: {
47 | post_message: {
48 |
49 | description: 'Post Message in Hipchat',
50 |
51 | input_fields: ->() {
52 | [
53 | { name: 'message', hint: "Valid length range: 1 - 1000", optional: false, label: "Message" },
54 | { name: 'room', hint: "Give either Room ID or Room name", optional: false, label: "Room" }
55 | ]
56 | },
57 |
58 | execute: ->(connection, input) {
59 | post("https://#{connection['subdomain']}.hipchat.com/v2/room/#{input['room']}/message",input)
60 | },
61 |
62 | output_fields: ->(object_definitions) {
63 | object_definitions['message']
64 | },
65 |
66 | sample_output: ->(connection) {
67 | room_id = get("https://#{connection['subdomain']}.hipchat.com/v2/room")['items'].last['id']
68 | get("https://#{connection['subdomain']}.hipchat.com/v2/room/#{room_id}/history")['items'].first || {}
69 | }
70 | },
71 |
72 | reply_to_message: {
73 |
74 | description: 'Reply to Message in Hipchat',
75 |
76 | input_fields: ->() {
77 | [
78 | { name: 'parentMessageId', hint: "The ID of the message you are replying to", label: "Message ID", optional: false },
79 | { name: 'message', hint: "Valid length range: 1 - 1000", optional: false, label: "Message" },
80 | { name: 'room', hint: "Give either Room ID or Room name", optional: false, label: "Room"}
81 | ]
82 | },
83 |
84 | execute: ->(connection, input) {
85 | post("https://#{connection['subdomain']}.hipchat.com/v2/room/#{input['room']}/reply",input)
86 | },
87 |
88 | output_fields: ->(object_definitions) {
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/codeship_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Codeship',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'api_key',
8 | control_type: 'password',
9 | label: 'API key',
10 | optional: false,
11 | hint: 'Go to My Account->Account settings and get Api key'
12 | }
13 | ],
14 |
15 | authorization: {
16 | type: 'api_key',
17 | credentials: ->(connection) {
18 | params(api_key: connection['api_key'])
19 | }
20 | }
21 | },
22 |
23 | object_definitions: {
24 | build: {
25 | fields: ->() {
26 | [
27 | { name: 'id', hint: "ID of the particular build" },
28 | { name: 'uuid' },
29 | { name: 'status' },
30 | { name: 'project_id', hint: "ID of the particular project"},
31 | { name: 'branch', hint: "Name of the branch" },
32 | { name: 'commit_id', hint: "ID of the commited build" },
33 | { name: 'github_username', hint: "User of the github for particular build" },
34 | { name: 'message', hint: "Message of your build" },
35 | { name: 'started_at' },
36 | { name: 'finished_at' },
37 | ]
38 | }
39 | }
40 | },
41 |
42 | test: ->(connection) {
43 | get("https://codeship.com/api/v1/projects")
44 | },
45 |
46 | actions: {
47 | list_builds: {
48 |
49 | description: 'List Builds in Codeship',
50 |
51 | input_fields: ->() {
52 | [
53 | { name: 'project_id', optional: false }
54 | ]
55 | },
56 |
57 | execute: ->(connection, input) {
58 | get("https://codeship.com/api/v1/projects/#{input['project_id']}")
59 | },
60 |
61 | output_fields: ->(object_definitions) {
62 | [
63 | { name:'id' },
64 | { name:'repository_name' },
65 | { name:'repository_provider' },
66 | { name:'uuid' },
67 | { name: 'builds', type: :array, of: :object, properties: object_definitions['build'] }
68 | ]
69 | },
70 |
71 | sample_output: ->(connection) {
72 | get("https://codeship.com/api/v1/projects")['projects'].first || {}
73 | },
74 | },
75 |
76 | restart_build: {
77 |
78 | description: 'Restart Build in Codeship',
79 |
80 | input_fields: ->() {
81 | [
82 | { name: 'id', optional: false, hint: 'ID of the particular build', label: 'Build ID' }
83 | ]
84 | },
85 |
86 | execute: ->(connection, input) {
87 | post("https://codeship.com/api/v1/builds/#{input['id']}/restart")
88 | },
89 |
90 | output_fields: ->(object_definitions) {
91 | object_definitions['build']
92 | },
93 |
94 | sample_output: ->(connection) {
95 | get("https://codeship.com/api/v1/projects")['projects'][0]['builds'].first || {}
96 | }
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/close_io_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Close.io',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'api_key',
8 | optional: false,
9 | hint: 'Profile (top right) > Settings > Your API Keys'
10 | }
11 | ],
12 |
13 | authorization: {
14 | type: 'basic_auth',
15 |
16 | # close.io uses api key only for authentication. treats apikey as username and password left blank
17 | # curl -u "{your api_key}:" "https://app.close.io/api/v1/me/"
18 | credentials: ->(connection) {
19 | user(connection['api_key'])
20 | password("")
21 | }
22 | }
23 | },
24 |
25 | object_definitions: {
26 | lead: {
27 | fields: ->() {
28 | [
29 | { name: 'name' },
30 | { name: 'display_name' },
31 | { name: 'id' },
32 | { name: 'status_id' },
33 | { name: 'date_updated' },
34 | { name: 'status_label' },
35 | { name: 'description' },
36 | { name: 'html_url' },
37 | { name: 'created_by' },
38 | { name: 'organization_id' },
39 | { name: 'url' },
40 | { name: 'updated_by' },
41 | { name: 'created_by_name' },
42 | { name: 'date_created' },
43 | { name: 'updated_by_name' }
44 | ]
45 | }
46 | }
47 | },
48 |
49 | test: ->(connection) {
50 | get("https://app.close.io/api/v1/me/")
51 | },
52 |
53 | actions: {
54 |
55 | get_lead_by_id: {
56 | input_fields: ->() {
57 | [
58 | { name: "lead_id", optional: false }
59 | ]
60 | },
61 | execute: ->(connection, input) {
62 | get("https://app.close.io/api/v1/lead/#{input['lead_id']}/")
63 | },
64 | output_fields: ->(object_definitions) {
65 | object_definitions['lead']
66 | }
67 | }
68 | },
69 |
70 | triggers: {
71 |
72 | new_or_updated_lead: {
73 |
74 | type: :paging_desc,
75 |
76 | input_fields: ->() {
77 | [
78 | { name: 'since', type: :timestamp,
79 | hint: 'Defaults to leads created after the recipe is first started' }
80 | ]
81 | },
82 |
83 | poll: ->(connection, input, last_updated_since) {
84 | since = last_updated_since || input['since'] || Time.now
85 |
86 | # Close.io currently does not support _order_by parameter for leads, defaults to order by date_update
87 | results = get("https://app.close.io/api/v1/lead/").
88 | params(query: "updated > #{since.to_time.iso8601}",
89 | _limit: 5)
90 |
91 | next_updated_since = results['data'].last['date_updated'] unless results['data'].length == 0
92 |
93 | {
94 | events: results['data'],
95 | next_page: next_updated_since,
96 | }
97 | },
98 |
99 | dedup: ->(lead) {
100 | lead['id']
101 | },
102 |
103 | output_fields: ->(object_definitions) {
104 | object_definitions['lead']
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/accelo_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Accelo',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'deployment',
8 | control_type: 'subdomain',
9 | url: '.accelo.com',
10 | optional: false
11 | }
12 | ],
13 | authorization: {
14 | type: 'oauth2',
15 |
16 | authorization_url: ->(connection) {
17 | "https://#{connection['deployment']}.api.accelo.com/oauth2/v0/authorize?response_type=code"
18 | },
19 |
20 | token_url: ->(connection) {
21 | "https://#{connection['deployment']}.api.accelo.com/oauth2/v0/token"
22 | },
23 |
24 | client_id: 'ababababab',
25 |
26 | client_secret: 'cdcdcdcdcd',
27 |
28 | credentials: ->(connection, access_token) {
29 | headers('Authorization': "Bearer #{access_token}")
30 | }
31 | }
32 | },
33 |
34 | object_definitions: {
35 | company: {
36 | fields: ->() {
37 | [
38 | { name: 'id', type: :integer },
39 | { name: 'name' },
40 | { name: 'website' },
41 | { name: 'standing' },
42 | { name: 'status' },
43 | { name: 'phone' },
44 | { name: 'fax' },
45 | { name: 'date_created', type: :integer },
46 | { name: 'date_modified', type: :integer },
47 | { name: 'comments' }
48 | ]
49 | },
50 | }
51 | },
52 |
53 | actions: {
54 | search_company: {
55 | input_fields: ->(object_definitions) {
56 | [
57 | { name: 'company_name' }
58 | ]
59 | },
60 |
61 | execute: ->(connection, input) {
62 | {
63 | 'companies': get("https://#{connection['deployment']}.api.accelo.com/api/v0/companies.json").
64 | params(_search: input['company_name'])['response']
65 | }
66 | },
67 |
68 | output_fields: ->(object_definitions) {
69 | [
70 | {
71 | name: 'companies',
72 | type: :array, of: :object,
73 | properties: object_definitions['company']
74 | }
75 | ]
76 | }
77 | }
78 | },
79 |
80 | triggers: {
81 | new_company: {
82 |
83 | type: :paging_desc,
84 |
85 | input_fields: ->() {
86 | [
87 | { name: 'created_after', type: :timestamp, optional: false }
88 | ]
89 | },
90 | poll: ->(connection, input, last_created_since) {
91 | created_since = (last_created_since || input['created_after'] || Time.now).to_i
92 |
93 | companies = get("https://#{connection['deployment']}.api.accelo.com/api/v0/companies.json").
94 | params(_filters: "date_created_after(#{created_since})",
95 | _limit: 2,
96 | _fields: 'date_created,website,status,phone,fax')['response']
97 |
98 | next_created_since = companies.last['date_created'] unless companies.blank?
99 |
100 | {
101 | events: companies,
102 | next_page: next_created_since
103 | }
104 | },
105 |
106 | dedup: ->(company) {
107 | company['id']
108 | },
109 |
110 | output_fields: ->(object_definitions) {
111 | object_definitions['company']
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/tsheets_connector.rb:
--------------------------------------------------------------------------------
1 | # Adds operations missing from the standard adapter.
2 | {
3 | title: "TSheets(custom)",
4 |
5 | connection: {
6 | fields: [
7 | {
8 | name: "subdomain",
9 | control_type: "subdomain",
10 | url: ".tsheets.com",
11 | label: "TSheets subdomain",
12 | optional: false,
13 | hint: "Your TSheets sub domain name as found in your TSheets URL"
14 | },
15 | {
16 | name: "api_token",
17 | label: "API token",
18 | control_type: "password",
19 | optional: false,
20 | },
21 | ],
22 |
23 | authorization: {
24 | type: "custom_auth",
25 |
26 | credentials: lambda do |connection|
27 | headers("Authorization": "Bearer #{connection['api_token']}")
28 | end
29 | }
30 | },
31 |
32 | test: lambda do |connection|
33 | get("https://#{connection['subdomain']}.tsheets.com/api/v1/timesheets").
34 | params(per_page: 1)["results"]["timesheets"].values
35 | end,
36 |
37 | actions: {
38 | query_timesheets: {
39 | description: 'Query timesheets in TSheets(custom)',
40 |
41 | input_fields: lambda do
42 | [
43 | { name: "start_date", type: :timestamp, optional: false },
44 | { name: "end_date", type: :timestamp, optional: false }
45 | ]
46 | end,
47 |
48 | execute: lambda do |connection, input|
49 | {
50 | timesheets: get("https://#{connection['subdomain']}.tsheets.com/api/v1/timesheets").
51 | params(
52 | start_date: input["start_date"].to_date.to_s,
53 | end_date: input["end_date"].to_date.to_s,
54 | per_page: 100
55 | )["results"]["timesheets"].values
56 | }
57 | end,
58 |
59 | output_fields: lambda do
60 | [
61 | {
62 | name: "timesheets",
63 | type: "array",
64 | of: "object",
65 | properties: [
66 | { name: "id", type: "integer" },
67 | { name: "user_id", type: "integer" },
68 | { name: "jobcode_id", type: "integer" },
69 | { name: "start", type: "timestamp" },
70 | { name: "end", type: "timestamp" },
71 | { name: "duration", type: "integer" },
72 | { name: "date", type: "timestamp" },
73 | { name: "tz", type: "integer" },
74 | { name: "tz_str", type: "string" },
75 | { name: "type", type: "string" },
76 | { name: "location", type: "string" },
77 | { name: "on_the_clock", type: "boolean" },
78 | { name: "locked", type: "integer" },
79 | { name: "notes", type: "string" },
80 | {
81 | name: "customfields",
82 | type: "object",
83 | properties: [
84 | # Add your custom fields here
85 | # { name: "71138", label: "location" },
86 | ]
87 | }
88 | ]
89 | }
90 | ]
91 | end,
92 |
93 | sample_output: lambda do |connection|
94 | {
95 | timesheets: get("https://#{connection['subdomain']}.tsheets.com/api/v1/timesheets").
96 | params(per_page: 1)["results"]["timesheets"].values
97 | }
98 | end
99 | },
100 | },
101 | }
102 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/infobip_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Infobip',
3 | connection: {
4 | fields: [
5 | {
6 | name: 'api_key',
7 | control_type: 'password',
8 | optional: false
9 | }
10 | ],
11 | authorization: {
12 | type: 'custom_auth',
13 | credentials: ->(connection) {
14 | headers(:Authorization => "App #{connection['api_key']}",
15 | :'User-Agent' => 'Workato')
16 | }
17 | }
18 | },
19 | test: ->(connection) {
20 | get('https://api.infobip.com/sms/1/logs').params(limit: 1)
21 | },
22 | object_definitions: {
23 | send_sms_request: {
24 | fields: ->() {
25 | [
26 | {name: 'from'},
27 | {name: 'to', optional: false, control_type: 'phone'},
28 | {name: 'text'}
29 | ]
30 | }
31 | },
32 | sent_sms_info: {
33 | fields: ->() {
34 | [
35 | {name: 'to'},
36 | {name: 'status', type: :object, properties: [
37 | {name: 'groupId', type: :integer},
38 | {name: 'groupName'},
39 | {name: 'id', type: :integer},
40 | {name: 'name'},
41 | {name: 'description'}
42 | ]},
43 | {name: 'smsCount', type: :integer},
44 | {name: 'messageId'}
45 | ]
46 | }
47 | },
48 | received_sms_info: {
49 | fields: ->() {
50 | [
51 | {name: 'messageId'},
52 | {name: 'from'},
53 | {name: 'to'},
54 | {name: 'text'},
55 | {name: 'cleanText'},
56 | {name: 'keyword'},
57 | {name: 'smsCount', type: :integer},
58 | {name: 'receivedAt'}
59 | ]
60 | }
61 | }
62 | },
63 | actions: {
64 | send_sms: {
65 | input_fields: ->(object_definitions) {
66 | object_definitions['send_sms_request']
67 | },
68 | execute: ->(connection, input) {
69 | post('https://api.infobip.com/sms/1/text/single', input)['send_sms_request']
70 | },
71 | output_fields: ->(object_definitions) {[
72 | { name: 'messages', type: :array, of: :object, properties: object_definitions['sent_sms_info'] }
73 | ]}
74 | }
75 | },
76 | triggers: {
77 | sms_received: {
78 | poll: ->(connection, input, last_received_at) {
79 | date_time_format = '%Y-%m-%dT%H:%M:%S.%L+00:00'
80 | received_since = last_received_at || (Time.now - 5 * 60).utc.strftime(date_time_format)
81 | query_param = received_since.gsub(':', '%3A').gsub('+', '%2B')
82 |
83 | received_messages = get("https://api.infobip.com/sms/1/inbox/logs?receivedSince=#{query_param}")
84 |
85 | received_sms_info = received_messages['results']
86 | last_received_at = received_sms_info.length == 0 ? received_since : received_sms_info[0]['receivedAt']
87 | {
88 | events: received_sms_info.reverse,
89 | can_poll_more: false,
90 | next_poll: last_received_at[0, last_received_at.length-2] + ':' + last_received_at[last_received_at.length-2, 2]
91 | }
92 | },
93 | dedup: ->(received_sms_info) {
94 | received_sms_info['messageId']
95 | },
96 | output_fields: ->(object_definitions) {
97 | object_definitions['received_sms_info']
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/docparser_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "Docparser",
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "api_key",
8 | label: "Docparser Account API Key",
9 | optional: false,
10 | hint: "Enter your secret Docparser API key. You can find your API key inside your Docparser account or in the settings of your Document Parser."
11 | }
12 | ],
13 |
14 | authorization: {
15 | type: "basic_auth",
16 | credentials: lambda do |connection|
17 | user(connection['api_key'])
18 | password("")
19 | end
20 | }
21 | },
22 |
23 | pick_lists: {
24 | parsers: lambda do |connection|
25 | get("https://api.docparser.com/v1/parsers").
26 | map { |parser| [parser["label"], parser["id"]] }
27 | end
28 | },
29 |
30 | object_definitions: {
31 | document: {
32 | fields: lambda do
33 | [
34 | {
35 | name: "id",
36 | label: "Document Id"
37 | }
38 | ]
39 | end
40 | },
41 | parsed_data: {
42 | fields: lambda do |_connection, config_fields|
43 | get("https://api.docparser.com/v1/results/#{config_fields['parser_id']}/schema")
44 | end
45 | }
46 | },
47 |
48 | test: lambda do |_connection|
49 | get("https://api.docparser.com/v1/ping")["msg"].present?
50 | end,
51 |
52 | triggers: {
53 | parsed_data: {
54 | config_fields: [
55 | {
56 | name: "parser_id",
57 | label: "Document Parser",
58 | control_type: :select,
59 | pick_list: "parsers",
60 | optional: false
61 | }
62 | ],
63 | poll: lambda do |_connection, input|
64 | parsed_data = get("https://api.docparser.com/v1/results/#{input['parser_id']}")
65 | {
66 | events: parsed_data
67 | }
68 | end,
69 | webhook_subscribe: lambda do |webhook_url, _connection, input, recipe_id|
70 | post("https://api.docparser.com/v1/webhook/subscribe/#{input['parser_id']}/workato",
71 | target_url: webhook_url,
72 | webhook_token: recipe_id)
73 | end,
74 | webhook_unsubscribe: lambda do |webhook|
75 | post("https://api.docparser.com/v1/webhook/unsubscribe/#{webhook['parser_id']}/workato",
76 | id: webhook['webhook_id'])
77 | end,
78 | webhook_notification: lambda do |_input, payload|
79 | payload
80 | end,
81 | dedup: lambda do |parsed_data|
82 | parsed_data["id"]
83 | end,
84 | output_fields: lambda do |object_definitions|
85 | object_definitions["parsed_data"]
86 | end
87 | }
88 | },
89 |
90 | actions: {
91 | fetch_document_from_url: {
92 | input_fields: lambda do
93 | [
94 | {
95 | name: "url",
96 | label: "Source URL",
97 | hint: "Upload file from this URL",
98 | optional: false
99 | },
100 | {
101 | name: "parser_id",
102 | label: "Document Parser",
103 | hint: "The Document Parser the file gets imported to",
104 | control_type: :select,
105 | pick_list: "parsers",
106 | optional: false
107 | },
108 | {
109 | name: "remote_id",
110 | label: "Your Document ID",
111 | hint: "Use this field to pipe your own document ID through the Docparser process.",
112 | optional: true
113 | }
114 | ]
115 | end,
116 | execute: lambda do |_connection, input|
117 | post("https://api.docparser.com/v1/document/fetch/#{input['parser_id']}?url=#{input['url']}&remote_id=#{input['remote_id']}")
118 | end,
119 | output_fields: lambda do |object_definitions|
120 | object_definitions["document"]
121 | end
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/webmerge_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "WebMerge",
3 |
4 | # HTTP basic auth example.
5 | connection: {
6 | fields: [
7 | {
8 | name: "api_key",
9 | optional: false,
10 | hint: "Your WebMerge API Key"
11 | },
12 | {
13 | name: "api_secret",
14 | control_type: "password",
15 | label: "Your WebMerge API Secret"
16 | }
17 | ],
18 |
19 | authorization: {
20 | type: "basic_auth",
21 |
22 | # Basic auth credentials are just the username and password
23 | credentials: lambda do |connection|
24 | user(connection["api_key"])
25 | password(connection["api_secret"])
26 | end
27 | }
28 | },
29 |
30 | object_definitions: {
31 |
32 | document: {
33 |
34 | fields: lambda do |_connection, config_fields|
35 | # here, you can use the input from the input from the user
36 | return [] if config_fields.blank?
37 | d = config_fields["document_id"].split("|")
38 | fields = get("https://www.webmerge.me/api/documents/#{d.first}/fields").
39 | map { |field| field.slice("name") }
40 | end
41 | },
42 |
43 | route: {
44 |
45 | fields: lambda do |_connection, config_fields|
46 | # here, you can use the input from the input from the user
47 | return [] if config_fields.blank?
48 | r = config_fields["route_id"].split("|")
49 | fields = get("https://www.webmerge.me/api/routes/#{r.first}/fields").
50 | map { |field| field.slice("name") }
51 | end
52 | }
53 | },
54 |
55 | test: lambda do |_connection|
56 | get("https://www.webmerge.me/api/account")
57 | end,
58 |
59 | actions: {
60 | merge_document: {
61 | config_fields: [
62 | # this field shows up first in recipe as a picklist of documents to use
63 | {
64 | name: "document_id",
65 | label: "Document",
66 | control_type: :select,
67 | pick_list: "documents",
68 | optional: false
69 | }
70 | ],
71 |
72 | input_fields: lambda do |object_definition|
73 | object_definition["document"]
74 | end,
75 |
76 | execute: lambda do |_connection, input|
77 | d = input["document_id"].split("|")
78 | post(d.last.to_s, input)
79 | end,
80 |
81 | output_fields: lambda do |_object_definition|
82 | [
83 | {
84 | name: "success"
85 | }
86 | ]
87 | end
88 | },
89 |
90 | merge_route: {
91 | config_fields: [
92 | # this field shows up first in recipe as a picklist of routes to use
93 | {
94 | name: "route_id",
95 | label: "Route",
96 | control_type: :select,
97 | pick_list: "routes",
98 | optional: false
99 | }
100 | ],
101 |
102 | input_fields: lambda do |object_definition|
103 | object_definition["route"]
104 | end,
105 |
106 | execute: lambda do |_connection, input|
107 | r = input["route_id"].split("|")
108 | post(r.last.to_s, input)
109 | end,
110 |
111 | output_fields: lambda do |_object_definition|
112 | [
113 | {
114 | name: "success"
115 | }
116 | ]
117 | end
118 | }
119 | },
120 |
121 | pick_lists: {
122 | documents: lambda do |_connection|
123 | get("https://www.webmerge.me/api/documents").map do |document|
124 | [document["name"], document["id"] + "|" + document["url"]]
125 | end
126 | end,
127 |
128 | routes: lambda do |_connection|
129 | get("https://www.webmerge.me/api/routes").map do |route|
130 | [route["name"], route["id"] + "|" + route["url"]]
131 | end
132 | end
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/rightsignature_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "RightSignature",
3 |
4 | connection: {
5 | fields: [{
6 | name: "api_key",
7 | label: "Secure token",
8 | hint: "You may find the secure token here",
10 | control_type: "password",
11 | optional: false
12 | }],
13 |
14 | authorization: {
15 | type: "api_key",
16 |
17 | apply: ->(connection) { headers(api_token: connection["api_key"]) }
18 | },
19 |
20 | base_uri: ->(_connection) { "https://rightsignature.com" }
21 | },
22 |
23 | object_definitions: {
24 | document: {
25 | fields: lambda {
26 | [
27 | { name: "guid", label: "Document ID" },
28 | { name: "created_at", type: "timestamp" },
29 | { name: "completed_at", type: "timestamp" },
30 | { name: "last_activity_at", type: "timestamp" },
31 | { name: "expires_on", type: "timestamp" },
32 | { name: "is_trashed", control_type: "checkbox", type: "boolean" },
33 | { name: "size", type: "integer" },
34 | { name: "content_type" },
35 | { name: "original_filename" },
36 | { name: "signed_pdf_checksum" },
37 | { name: "subject" },
38 | { name: "message" },
39 | { name: "processing_state" },
40 | { name: "merge_state" },
41 | { name: "state" },
42 | { name: "callback_location" },
43 | { name: "tags" },
44 | {
45 | name: "recipients",
46 | type: "array",
47 | of: "object",
48 | properties: [
49 | { name: "name" },
50 | { name: "email", control_type: "email" },
51 | { name: "must_sign", control_type: "checkbox", type: "boolean" },
52 | { name: "document_role_id" },
53 | { name: "role_id" },
54 | { name: "state" },
55 | { name: "is_sender", control_type: "checkbox", type: "boolean" },
56 | { name: "viewed_at", type: "timestamp" },
57 | { name: "completed_at", type: "timestamp" }
58 | ]
59 | },
60 | {
61 | name: "audit_trails",
62 | type: "array",
63 | of: "object",
64 | properties: [
65 | { name: "timestamp", type: "timestamp" },
66 | { name: "keyword" },
67 | { name: "message" }
68 | ]
69 | },
70 | {
71 | name: "pages",
72 | type: "array",
73 | of: "object",
74 | properties: [
75 | { name: "page_number" },
76 | { name: "original_template_guid" },
77 | { name: "original_template_filename" }
78 | ]
79 | },
80 | { name: "original_url" },
81 | { name: "pdf_url" },
82 | { name: "thumbnail_url" },
83 | { name: "large_url" },
84 | { name: "signed_pdf_url" }
85 | ]
86 | }
87 | }
88 | },
89 |
90 | test: ->(_connection) { get("/api/documents.json") },
91 |
92 | actions: {
93 | get_document_details: {
94 | subtitle: "Get document details by ID",
95 | description: "Get document details " \
96 | "by ID in RightSignature",
97 |
98 | input_fields: lambda { |object_definitions|
99 | object_definitions["document"].only("guid").required("guid")
100 | },
101 |
102 | execute: lambda { |_connection, input|
103 | get("/api/documents/#{input['guid']}.json")["document"] || {}
104 | },
105 |
106 | output_fields: ->(object_definitions) { object_definitions["document"] },
107 |
108 | sample_output: lambda { |_connection|
109 | get("/api/documents.json").dig("page", "documents", 0) || {}
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/watson_tone_analyzer_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Watson Tone Analyzer',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'username', optional: true,
8 | hint: 'Your username; leave empty if using API key below'
9 | },
10 | {
11 | name: 'password', control_type: 'password',
12 | label: 'Password or personal API key'
13 | }
14 | ],
15 |
16 | authorization: {
17 | type: 'basic_auth',
18 |
19 | credentials: ->(connection) {
20 | user(connection['username'])
21 | password(connection['password'])
22 | }
23 | }
24 | },
25 |
26 | test: ->(connection) {
27 | post("https://gateway.watsonplatform.net/tone-analyzer-beta/api/v3/tone?version=2016-02-11").
28 | payload(text: "this is it")
29 | },
30 |
31 | object_definitions: {
32 | tone: {
33 | fields: ->(connection) {
34 | [
35 | { name: 'score', type: :decimal },
36 | { name: 'tone_id' },
37 | { name: 'tone_name' }
38 | ]
39 | }
40 | }
41 | },
42 |
43 | actions: {
44 | analyze_content: {
45 | input_fields: ->(object_definitions) {
46 | [
47 | { name: 'text', optional: false }
48 | ]
49 | },
50 |
51 | execute: ->(connection, input) {
52 | response = post("https://gateway.watsonplatform.net/tone-analyzer-beta/api/v3/tone?version=2016-02-11").
53 | payload(text: input['text'])['document_tone']
54 |
55 | tones = {}
56 | response['tone_categories'].each do |cat|
57 | if ["emotion_tone", "writing_tone", "social_tone"].include?(cat['category_id'])
58 | tones[cat['category_id']] = cat
59 | end
60 | end
61 |
62 | if tones['emotion_tone'].present? && tones['emotion_tone']['tones'].present?
63 | dominant_emotion_tone = tones['emotion_tone']['tones'].
64 | sort { |a,b| b['score'] <=> a['score'] }.
65 | first
66 | end
67 |
68 | if tones['writing_tone'].present? && tones['writing_tone']['tones'].present?
69 | dominant_writing_tone = tones['writing_tone']['tones'].
70 | sort { |a,b| b['score'] <=> a['score'] }.
71 | first
72 | end
73 |
74 | if tones['social_tone'].present? && tones['social_tone']['tones'].present?
75 | dominant_social_tone = tones['social_tone']['tones'].
76 | sort { |a,b| b['score'] <=> a['score'] }.
77 | first
78 | end
79 |
80 | {
81 | 'dominant_emotion_tone': dominant_emotion_tone,
82 | 'emotion_tones': tones['emotion_tone'],
83 | 'dominant_writing_tone': dominant_writing_tone,
84 | 'writing_tones': tones['writing_tone'],
85 | 'dominant_social_tone': dominant_social_tone,
86 | 'social_tones': tones['social_tone'],
87 | }
88 | },
89 |
90 | output_fields: ->(object_definitions) {
91 | [
92 | {
93 | name: 'dominant_emotion_tone', type: :object,
94 | properties: object_definitions['tone']
95 | },
96 | {
97 | name: 'emotion_tones', type: :array,
98 | of: :object, properties: object_definitions['tone']
99 | },
100 | {
101 | name: 'dominant_writing_tone', type: :object,
102 | properties: object_definitions['tone']
103 | },
104 | {
105 | name: 'writing_tones', type: :array,
106 | of: :object, properties: object_definitions['tone']
107 | },
108 | {
109 | name: 'dominant_social_tone', type: :object,
110 | properties: object_definitions['tone'] },
111 | {
112 | name: 'social_tones', type: :array,
113 | of: :object, properties: object_definitions['tone']
114 | }
115 | ]
116 | }
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/linenotify.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Line Notify',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "client_id",
8 | label: "Client ID",
9 | optional: false,
10 | hint: "You can find your client ID " \
11 | "here"
13 | },
14 | {
15 | name: "client_secret",
16 | label: "Client secret",
17 | control_type: "password",
18 | optional: false,
19 | hint: "You can find your client secret " \
20 | "here"
22 | }
23 | ],
24 |
25 | authorization: {
26 | type: "oauth2",
27 |
28 | authorization_url: lambda do |connection|
29 | "https://notify-bot.line.me/oauth/authorize?" \
30 | "client_id=#{connection['client_id']}&response_type=code&scope=notify"
31 | end,
32 |
33 | acquire: lambda do |connection, auth_code|
34 | response = post("https://notify-bot.line.me/oauth/token").
35 | payload(code: auth_code,
36 | client_id: connection["client_id"],
37 | client_secret: connection["client_secret"],
38 | redirect_uri: "https://www.workato.com/oauth/callback",
39 | grant_type: "authorization_code").
40 | request_format_www_form_urlencoded
41 |
42 | [response, nil, nil]
43 | end,
44 |
45 | refresh_on: [403],
46 |
47 | refresh: lambda do |connection, refresh_token|
48 | post("https://notify-bot.line.me/oauth/token").
49 | payload(grant_type: "refresh_token",
50 | client_id: connection["client_id"],
51 | client_secret: connection["client_secret"],
52 | refresh_token: refresh_token,
53 | redirect_uri: "https://www.workato.com/oauth/callback").
54 | request_format_www_form_urlencoded
55 | end,
56 |
57 | apply: lambda do |_connection, access_token|
58 | headers("Authorization": "Bearer #{access_token}")
59 | end
60 | },
61 |
62 | base_uri: lambda do
63 | "https://notify-bot.line.me"
64 | end
65 | },
66 | object_definitions: {
67 | response: {
68 | fields: lambda do
69 | [
70 | { name: "status", type: "Integer" },
71 | { name: "message" }
72 | ]
73 | end
74 | }
75 | },
76 |
77 | actions: {
78 | notify: {
79 | description: "Send notification in " \
80 | "Line Notify",
81 | title_hint: "Sends notifications to users or groups that" \
82 | " are related to an access token.",
83 | input_fields: lambda do
84 | [
85 | { name: "message", label: "Message", optional: false },
86 | { name: "stickerId", label: "Sticker ID", type: "number",
87 | hint: "You can find sticker list " \
88 | "here"
90 | },
91 | { name: "stickerPackageId", label: "Sticker package ID", type: "number",
92 | hint: "You can find sticker package list " \
93 | "here"
95 | }
96 | ]
97 | end,
98 |
99 | execute: lambda do |_connection, input|
100 | post("https://notify-api.line.me/api/notify").
101 | payload(input).
102 | request_format_multipart_form
103 | end,
104 |
105 | output_fields: lambda do |object_definitions|
106 | object_definitions['response']
107 | end,
108 | sample_output: lambda do |_|
109 | { "status": 200, "message": "ok" }
110 | end
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/lo_jack_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'LoJack',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'account',
8 | },
9 | {
10 | name: 'username',
11 | },
12 | {
13 | name: 'password',
14 | control_type: 'password',
15 | }
16 | ],
17 |
18 | authorization: {
19 | type: 'custom_auth',
20 |
21 | credentials: ->(connection) {
22 | params(connection.merge(lang: 'en', outputformat: 'json'))
23 | # LoJack API expects a non-standard Accept header
24 | headers(Accept: "*/*")
25 | }
26 | }
27 | },
28 |
29 | object_definitions: {
30 | },
31 |
32 | test: ->(connection) {
33 | get("https://csv.business.tomtom.com/extern?action=showObjectReportExtern&filterstring=XXXXXXXX")
34 | },
35 |
36 | actions: {
37 | get_object_reports: {
38 | # not used
39 | input_fields: ->() {
40 | [
41 | {
42 | name: "filterstring",
43 | label: "Filter String",
44 | optional: true,
45 | hint: "An arbitrary pattern that is located in the object data."
46 | },
47 |
48 | {
49 | name: "objectgroupname",
50 | label: "Object Group Name",
51 | optional: true,
52 | hint: "A name of an object group."
53 | },
54 |
55 | {
56 | name: "objectno",
57 | label: "Object No",
58 | optional: true,
59 | hint: "Identifying number of an object. Unique within an account, case-sensitive. Can be used alternatively to Object UID"
60 | },
61 |
62 | {
63 | name: "objectuid",
64 | label: "Object UID",
65 | optional: true,
66 | hint: "Identifying number of an object. Unique within an account, case-sensitive. Can be used alternatively to Object No"
67 | },
68 | ]
69 | },
70 |
71 | execute: ->(connection, input) {
72 | reply = get("https://csv.business.tomtom.com/extern?action=showObjectReportExtern", input)
73 | {
74 | reports: (reply[0] ? reply : []) # reply is an array when successful otherwise an object
75 | }
76 | },
77 |
78 | output_fields: ->(object_definitions) {
79 | [
80 | {
81 | name: 'reports',
82 | type: 'array',
83 | of: 'object',
84 | properties: [
85 | { name: "objectno" },
86 | { name: "objectname" },
87 | { name: "objectclassname" },
88 | { name: "objecttype" },
89 | { name: "description" },
90 | { name: "lastmsgid", type: "integer" },
91 | { name: "deleted", type: "boolean" },
92 | { name: "msgtime", type: "date_time" },
93 | { name: "longitude" },
94 | { name: "latitude" },
95 | { name: "postext" },
96 | { name: "postext_short" },
97 | { name: "status" },
98 | { name: "driver" },
99 | { name: "driver_currentworkstate", type: "integer" },
100 | { name: "codriver_currentworkstate", type: "integer" },
101 | { name: "odometer", type: "integer" },
102 | { name: "ignition", type: "integer" },
103 | { name: "dest_distance", type: "integer" },
104 | { name: "tripmode", type: "integer" },
105 | { name: "standstill", type: "integer" },
106 | { name: "pndconn", type: "integer" },
107 | { name: "ignition_time", type: "date_time" },
108 | { name: "drivername" },
109 | { name: "pos_time", type: "date_time" },
110 | { name: "longitude_mdeg", type: "integer" },
111 | { name: "latitude_mdeg", type: "integer" },
112 | { name: "objectuid" },
113 | { name: "driveruid" }
114 | ]
115 | }
116 | ]
117 | }
118 | }
119 | },
120 | }
121 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/unbounce_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Unbounce',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'api_key',
8 | optional: false,
9 | control_type: 'password',
10 | hint: 'Profile (top right) > Manage Account > API Keys'
11 | },
12 | {
13 | name: 'page_id',
14 | optional: false,
15 | hint: "ID of page to connect, found at the end of respective page's URL"
16 | }
17 | ],
18 |
19 | authorization: {
20 | type: 'basic_auth',
21 | # unbounce uses api key only for authentication. treats apikey as username and password left blank
22 | # curl -u "{your api_key}:" "https://api.unbounce.com"
23 | credentials: ->(connection) {
24 | user(connection['api_key'])
25 | password("")
26 | }
27 | }
28 | },
29 |
30 | test: ->(connection) {
31 | get("https://api.unbounce.com/pages/#{connection['page_id']}")
32 | },
33 |
34 | object_definitions: {
35 |
36 | form: {
37 | fields: ->(connection) {
38 | get("https://api.unbounce.com/pages/#{connection['page_id']}/form_fields")['formFields'].
39 | map { |field| { name: field['id'] } }
40 | }
41 | },
42 |
43 | page: {
44 | fields: ->(connection) {
45 | [
46 | { name:'subAccountId', type: :integer },
47 | { name:'integrationsCount', type: :integer },
48 | { name:'integrationsErrorsCount', type: :integer },
49 | { name:'id' },
50 | { name:'createdAt', type: :datetime },
51 | { name:'lastPublishedAt', type: :datetime },
52 | { name:'name' },
53 | { name:'state' },
54 | { name:'url', control_type: 'url' },
55 | { name:'variantsCount', type: :integer },
56 | { name:'domain', control_type: 'url' },
57 | { name:'fullUrl', control_type: 'url' },
58 | { name: 'metaData', type: :object, properties: [
59 | { name: 'documentation', control_type: 'url' },
60 | { name: 'location', control_type: 'url' },
61 | { name: 'related', type: :object, properties: [
62 | { name: 'leads', control_type: 'url' },
63 | { name: 'subAccount', control_type: 'url' }
64 | ]}
65 | ]}
66 | ]
67 | }
68 | }
69 | },
70 |
71 | actions: {
72 |
73 | get_page_details: {
74 | input_fields: ->() {},
75 | execute: ->(connection,input) {
76 | get("https://api.unbounce.com/pages/#{connection['page_id']}")
77 | },
78 | output_fields: ->(object_definitions) {
79 | object_definitions['page']
80 | }
81 | }
82 | },
83 |
84 | triggers: {
85 |
86 | new_submission: {
87 |
88 | type: :paging_desc,
89 |
90 | input_fields: ->() {
91 | [
92 | { name: 'since', type: :timestamp,
93 | hint: 'Defaults to submissions after the recipe is first started' }
94 | ]
95 | },
96 |
97 | poll: ->(connection, input, last_created_since) {
98 | since = last_created_since || input['since'] || Time.now
99 |
100 | leads = get("https://api.unbounce.com/pages/#{connection['page_id']}/leads").
101 | params(from: since.to_time.iso8601,
102 | sort_order: :desc, # API sorts by creation date
103 | limit: 10)['leads']
104 |
105 | leads.map do |lead|
106 | lead['formData'] = lead['formData'].map do |k,v|
107 | { k => v.first }
108 | end.
109 | inject(:merge)
110 | lead
111 | end
112 |
113 | next_updated_since = leads.first['createdAt'] unless leads.length == 0
114 |
115 | {
116 | events: leads,
117 | next_page: next_updated_since
118 | }
119 | },
120 |
121 | output_fields: ->(object_definitions) {
122 | [
123 | { name: 'id', type: :integer },
124 | { name: 'formData', type: :object, properties: object_definitions['form'] }
125 | ]
126 | }
127 | }
128 | },
129 | }
130 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/safetyculture_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'SafetyCulture',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'access_token',
8 | control_type: 'password'
9 | }
10 | ],
11 |
12 | authorization: {
13 | type: 'custom_auth',
14 |
15 | # Safety Culture uses non standard OAuth 2.0 type authentication. Workaround is to use access token generates in the UI
16 | credentials: ->(connection) {
17 | headers('Authorization': "Bearer #{connection['access_token']}")
18 | }
19 | }
20 | },
21 |
22 | test: ->(connection) {
23 | get("https://api.safetyculture.io/audits/search")
24 | },
25 |
26 | object_definitions: {
27 | audit: {
28 | fields: ->() {
29 | [
30 | { name: 'template_id' },
31 | { name: 'audit_id' },
32 | { name: 'created_at', type: :datetime },
33 | { name: 'modified_at', type: :datetime },
34 | { name: 'audit_data', type: :object, properties: [
35 | { name: 'name' },
36 | { name: 'score', type: :integer },
37 | { name: 'total_score', type: :integer },
38 | { name: 'score_percentage', type: :integer },
39 | { name: 'duration', type: :integer },
40 | { name: 'date_completed', type: :datetime },
41 | { name: 'date_modified', type: :datetime },
42 | { name: 'date_started', type: :datetime },
43 | { name: 'authorship', type: :object, properties: [
44 | { name: 'devise_id' },
45 | { name: 'owner' },
46 | { name: 'author' },
47 | ]}
48 | ]},
49 | { name: 'template_data', type: :object, properties: [
50 | { name: 'authorship', type: :object, properties: [
51 | { name: 'devise_id' },
52 | { name: 'owner' },
53 | { name: 'author' },
54 | ]},
55 | { name: 'metadata', type: :object, properties: [
56 | { name: 'description' },
57 | { name: 'name' }
58 | ]}
59 | ]},
60 | { name: 'header_items',type: :array, of: :object, properties: [
61 | { name: 'item_id' },
62 | { name: 'label' },
63 | { name: 'type' }
64 | ]},
65 | { name: 'items',type: :array, of: :object, properties: [
66 | { name: 'item_id' },
67 | { name: 'parent_id' },
68 | { name: 'label' },
69 | { name: 'type' },
70 | { name: 'scoring', type: :object, properties: [
71 | { name: 'combined_score', type: :integer },
72 | { name: 'combined_max_score', type: :integer },
73 | { name: 'combined_score_percentage', type: :integer },
74 | ]}
75 | ]}
76 | ]
77 | }
78 | }
79 | },
80 |
81 | actions: {
82 | get_audit_data: {
83 | input_fields: ->() {
84 | [
85 | { name: 'audit_id' }
86 | ]
87 | },
88 | execute: ->(connection,input) {
89 | get("https://api.safetyculture.io/audits/#{input['audit_id']}")
90 | },
91 | output_fields: ->(object_definitions) {
92 | object_definitions['audit']
93 | }
94 | }
95 | },
96 |
97 | triggers: {
98 |
99 | new_or_updated_audit: {
100 |
101 | type: :paging_desc,
102 |
103 | input_fields: ->() {
104 | [
105 | { name: 'since', type: :timestamp, optional: false,
106 | hint: 'Defaults to audits modified after the recipe is first started' },
107 | { name: 'completed', control_type: 'select', optional: false,
108 | pick_list: [
109 | ["Yes", "true"],
110 | ["No", "false"],
111 | ["Both", "both"]]
112 | }
113 | ]
114 | },
115 |
116 | poll: ->(connection, input, last_updated_since) {
117 | updated_since = last_updated_since || input['since'] || Time.now
118 |
119 | response = get("https://api.safetyculture.io/audits/search").
120 | params(modified_after: updated_since.to_time.utc.iso8601,
121 | order: :desc,
122 | limit: 2,
123 | completed: input['completed'])
124 |
125 | audits = response['audits'].map do |audit|
126 | get("https://api.safetyculture.io/audits/#{audit['audit_id']}")
127 | end
128 |
129 | next_updated_since = response['audits'].last['modified_at'] unless response['count'] == 0
130 |
131 | {
132 | events: audits,
133 | next_page: next_updated_since,
134 | }
135 | },
136 |
137 | dedup: ->(audit) {
138 | audit['audit_id']
139 | },
140 |
141 | output_fields: ->(object_definitions) {
142 | object_definitions['audit']
143 | }
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/convert_api_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "ConvertAPI",
3 |
4 | connection: {
5 | fields: [{
6 | name: "secret",
7 | hint: "Secret can be found in ConvertAPI " \
8 | "Control Panel.",
9 | optional: false
10 | }],
11 |
12 | base_uri: ->(_connection) { "https://v2.convertapi.com" },
13 |
14 | authorization: {
15 | type: "custom_auth",
16 |
17 | acquire: lambda do |connection|
18 | {
19 | token: post("/token/create").
20 | params("Secret" => connection["secret"],
21 | "RequestCount" => 100,
22 | "Lifetime" => 1000).
23 | dig("Tokens", 0, "Id")
24 | }
25 | end,
26 |
27 | refresh_on: [401, /"Code"\s*\:\s*4011/],
28 |
29 | apply: ->(connection) { params("Token" => connection["token"]) }
30 | }
31 | },
32 |
33 | test: ->(connection) { get("/user", "Secret" => connection["secret"]) },
34 |
35 | object_definitions: {
36 | file_input: {
37 | fields: lambda do |_connection, _config_fields|
38 | [
39 | {
40 | name: "File",
41 | label: "File URL",
42 | control_type: "url"
43 | },
44 | { name: "StoreFile", control_type: "checkbox", type: "boolean" },
45 | {
46 | name: "FileName",
47 | hint: "Converted output file name without extension. " \
48 | "The extension will be added automatically."
49 | },
50 | {
51 | name: "Timeout",
52 | hint: "Default: 300. Valid value ranges from 10 to 1200",
53 | type: "integer"
54 | },
55 | {
56 | name: "PdfResolution",
57 | label: "PDF Resolution",
58 | hint: "Default: 300. Valid value ranges from 10 to 2400",
59 | type: "integer"
60 | }
61 | ]
62 | end
63 | },
64 |
65 | file_output: {
66 | fields: lambda do |_connection, _config_fields|
67 | [
68 | { name: "FileName" },
69 | { name: "FileSize" },
70 | { name: "FileData" },
71 | { name: "Url", label: "URL" }
72 | ]
73 | end
74 | }
75 | },
76 |
77 | actions: {
78 | split_pdf_file: {
79 | title: "Split PDF file",
80 | description: "Split PDF file in " \
81 | "ConvertAPI",
82 | help: "Splits each page into a PDF file.",
83 |
84 | execute: lambda do |_connection, input|
85 | post("/pdf/to/split", input).request_format_www_form_urlencoded
86 | end,
87 |
88 | input_fields: lambda do |object_definitions|
89 | object_definitions["file_input"].required("File")
90 | end,
91 |
92 | output_fields: lambda do |object_definitions|
93 | [{
94 | name: "Files",
95 | type: "array",
96 | of: "object",
97 | properties: object_definitions["file_output"]
98 | }]
99 | end,
100 |
101 | sample_output: lambda do |_connection, _input|
102 | {
103 | "Files" => [{
104 | "FileName" => "Workato.pdf",
105 | "FileSize" => 1234,
106 | "Url" => "https://v2.convertapi.com/d/ABCD/Workato.pdf"
107 | }]
108 | }
109 | end
110 | },
111 |
112 | merge_pdf_file: {
113 | title: "Merge PDF file",
114 | description: "Merge PDF files in " \
115 | "ConvertAPI",
116 |
117 | execute: lambda do |_connection, input|
118 | files_list = []
119 | index = 0
120 | input_files = input["Files"]&.pluck("File")
121 | input_files_size = input_files.size
122 | while index < input_files_size
123 | files_list.concat([{ index => input_files[index] }])
124 | index = index + 1
125 | end
126 | input["Files"] = files_list.inject(:merge)
127 |
128 | post("/pdf/to/merge", input).request_format_www_form_urlencoded
129 | end,
130 |
131 | input_fields: lambda do |object_definitions|
132 | [{
133 | name: "Files",
134 | optional: false,
135 | type: "array",
136 | of: "object",
137 | properties: object_definitions["file_input"].
138 | only("File").
139 | required("File")
140 | }] + object_definitions["file_input"].ignored("File")
141 | end,
142 |
143 | output_fields: lambda do |object_definitions|
144 | [{
145 | name: "Files",
146 | type: "array",
147 | of: "object",
148 | properties: object_definitions["file_output"]
149 | }]
150 | end,
151 |
152 | sample_output: lambda do |_connection, _input|
153 | {
154 | "Files" => [{
155 | "FileName" => "Workato.pdf",
156 | "FileSize" => 1234,
157 | "Url" => "https://v2.convertapi.com/d/ABCD/Workato.pdf"
158 | }]
159 | }
160 | end
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/podio_connector.rb:
--------------------------------------------------------------------------------
1 | # Substitute YOUR_PODIO_CLIENT_ID for your OAuth2 client id from Podio
2 | # Substitute YOUR_PODIO_CLIENT_SECRET for your OAuth2 client secret from Podio
3 | {
4 | title: 'Podio',
5 |
6 | connection: {
7 | authorization: {
8 | type: 'oauth2',
9 |
10 | authorization_url: ->() {
11 | 'https://podio.com/oauth/authorize'
12 | },
13 |
14 | token_url: ->() {
15 | 'https://podio.com/oauth/token'
16 | },
17 |
18 | client_id: 'YOUR_PODIO_CLIENT_ID',
19 |
20 | client_secret: 'YOUR_PODIO_CLIENT_SECRET',
21 |
22 | credentials: ->(connection, access_token) {
23 | headers('Authorization': "OAuth2 #{access_token}")
24 | }
25 | }
26 | },
27 |
28 | object_definitions: {
29 | contact: {
30 | fields: ->(connection) {
31 | [
32 | { name: 'profile_id'},
33 | { name: 'name'},
34 | { name: 'organization'},
35 | { name: 'department'},
36 | { name: 'skype'},
37 | { name: 'about'},
38 | { name: 'address'},
39 | { name: 'zip'},
40 | { name: 'city'},
41 | { name: 'state'},
42 | { name: 'country'},
43 | { name: 'mail'},
44 | { name: 'phone'},
45 | { name: 'title'},
46 | { name: 'linkedin'},
47 | { name: 'url'},
48 | { name: 'twitter'}
49 | ]
50 | },
51 | },
52 |
53 | application: {
54 | fields: ->(connection) {
55 | [
56 | { name: 'app_id'},
57 | { name: 'original'},
58 | { name: 'original_revision'},
59 | { name: 'status'},
60 | { name: 'space_id'},
61 | { name: 'owner', type: :object, properties: [{name: 'user_id', type: :integer}, {name: 'avatar'}, {name: 'name'}]},
62 | { name: 'link'},
63 | { name: 'link_add'},
64 | { name: 'config', type: :object,
65 | properties:
66 | [
67 | { name: 'type', control_type: 'select', picklist: [['standard'], ['meeting'], ['contact']]},
68 | { name: 'name'},
69 | { name: 'item_name'},
70 | { name: 'description'},
71 | { name: 'usage'},
72 | { name: 'external_id'},
73 | { name: 'icon'},
74 | { name: 'allow_edit', type: :boolean},
75 | { name: 'default view'},
76 | { name: 'allow_attachments', type: :boolean},
77 | { name: 'allow_comments', type: :boolean},
78 | { name: 'fivestar', type: :boolean},
79 | { name: 'fivestar_label'},
80 | { name: 'approved', type: :boolean},
81 | { name: 'thumbs', type: :boolean},
82 | { name: 'thumbs_label', type: :boolean},
83 | { name: 'rsvp', type: :boolean},
84 | { name: 'yesno', type: :boolean},
85 | { name: 'yesno_label'},
86 | { name: 'tasks'}
87 | ]
88 | }
89 | ]
90 | }
91 | },
92 |
93 | tag: {
94 | fields: ->(connection){
95 | [{ name: 'count'},{ name: 'text'}]
96 | }
97 | }
98 | },
99 |
100 | actions: {
101 |
102 | get_apps: {
103 | input_fields: ->(object_definitions){
104 | [
105 | { name: 'Workspace ID', optional: 'false'}
106 | ]
107 | },
108 |
109 | execute: ->(connection, input) {
110 | { applications: get("https://api.podio.com/app/space/#{input['Workspace ID']}")}
111 | },
112 |
113 | output_fields: ->(object_definitions) {
114 | { name: 'applications', type: 'array', of: 'object', properties: object_definitions['application']}
115 | }
116 | },
117 |
118 | get_app_detail: {
119 | input_fields: ->(object_definitions){
120 | [
121 | { name: 'Application ID', optional: 'false'}
122 | ]
123 | },
124 |
125 | execute: ->(connection, input) {
126 | { app_detail: get("https://api.podio.com/app/#{input['Application ID']}")}
127 | },
128 |
129 | output_fields: ->(object_definitions){
130 | object_definitions['application']
131 | }
132 | },
133 |
134 | get_app_tags: {
135 | input_fields: ->(object_definitions){
136 | [
137 | { name: 'Application ID', optional: 'false'}
138 | ]
139 | },
140 |
141 | execute: ->(connection, input) {
142 | { tags: get("https://api.podio.com/tag/app/#{input['Application ID']}")}
143 | },
144 |
145 | output_fields: ->(object_definitions){
146 | { name: 'tags', type = 'array', of: 'object', properties: object_definitions['tag']}
147 | }
148 | },
149 |
150 | get_contacts: {
151 | input_fields: ->(object_definitions) {[]},
152 |
153 | execute: ->(connection, input) {
154 | { contacts: get("https://api.podio.com/contact/?limit=5")}
155 | },
156 |
157 | output_fields: ->(object_definitions) {
158 | [
159 | { name: 'contacts', type: 'array', of: 'object', properties: object_definitions['contact']}
160 | ]
161 | }
162 | }
163 |
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/toggl_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Toggl',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'api_token',
8 | control_type: 'password',
9 | label: 'Toggl API token',
10 | hint: 'Available in "My Profile" page'
11 | }
12 | ],
13 |
14 | authorization: {
15 | type: 'basic_auth',
16 |
17 | # Toggl API expect the token to be sent as user name and the string 'api_token' as the password
18 | # curl -u "{your api_token}:api_token" "https://www.toggl.com/api/v8/me"
19 | credentials: ->(connection) {
20 | user(connection['api_token'])
21 | password('api_token')
22 | }
23 | }
24 | },
25 |
26 | test: ->(connection) {
27 | get("https://www.toggl.com/api/v8/me")
28 | },
29 |
30 | object_definitions: {
31 | time_entry: {
32 | fields: ->() {
33 | [
34 | { name:'id', type: :integer },
35 | { name:'wid', type: :integer },
36 | { name:'pid' },
37 | { name:'project_name' },
38 | { name:'billable', type: :boolean },
39 | { name:'start', type: :timestamp },
40 | { name:'stop', type: :timestamp },
41 | { name:'duration', type: :integer },
42 | { name:'description' },
43 | { name:'at', type: :timestamp }
44 | ]
45 | }
46 | }
47 | },
48 |
49 | actions: {
50 | get_time_entries: {
51 | input_fields: ->(object_definitions) {
52 | [
53 | { name: 'date', type: :date, optional: false }
54 | ]
55 | },
56 |
57 | execute: ->(connection, input) {
58 | start_time = input['date'].to_time.beginning_of_day.utc.iso8601
59 | end_time = (input['date'].to_time + 1.days).beginning_of_day.utc.iso8601
60 |
61 | entries = get("https://www.toggl.com/api/v8/time_entries").
62 | params(start_date: start_time,
63 | end_date: end_time)
64 |
65 | {
66 | 'entries': entries
67 | }
68 | },
69 |
70 | output_fields: ->(object_definitions) {
71 | [
72 | { name: 'entries', type: :array, of: :object, properties: object_definitions['time_entry'] }
73 | ]
74 | }
75 | },
76 | get_project_name: {
77 | input_fields: ->(object_definitions) {
78 | [
79 | { name: 'id', optional: false }
80 | ]
81 | },
82 |
83 | execute: ->(connection, input) {
84 | project = get("https://www.toggl.com/api/v8/projects/#{input['id']}")['data']
85 | {
86 | 'project_name': project['name'],
87 | 'client_id': project['cid']
88 | }
89 | },
90 |
91 | output_fields: ->(object_definitions) {
92 | [
93 | { name: 'project_name' },
94 | { name: 'client_id' }
95 | ]
96 | }
97 | },
98 | get_client_name: {
99 | input_fields: ->(object_definitions) {
100 | [
101 | { name: 'id', optional: false }
102 | ]
103 | },
104 |
105 | execute: ->(connection, input) {
106 | {
107 | 'name': get("https://www.toggl.com/api/v8/clients/#{input['id']}")['data']['name']
108 | }
109 | },
110 |
111 | output_fields: ->(object_definitions) {
112 | [
113 | { name: 'name' }
114 | ]
115 | }
116 | },
117 | get_daily_report: {
118 | input_fields: ->(object_definitions) {
119 | [
120 | { name: 'date', optional: false },
121 | { name: 'workspace_id', optional: false },
122 | { name: 'user', optional: false, hint: 'Name of agent to generate report for. Input "me" for current user' }
123 | ]
124 | },
125 |
126 | execute: ->(connection, input) {
127 | # Toggl API expects ISO8601 format
128 | start_time = input['date'].to_time.beginning_of_day.utc.iso8601
129 | end_time = (input['date'].to_time + 1.days).beginning_of_day.utc.iso8601
130 |
131 | user = input['user'] == 'me' ? get("https://www.toggl.com/api/v8/me")['data']['fullname'] : input['user']
132 |
133 | report = get("https://toggl.com/reports/api/v2/summary").
134 | params(since: start_time,
135 | until: end_time,
136 | user_agent: user,
137 | workspace_id: input['workspace_id'])['data']
138 |
139 | {
140 | 'report': report
141 | }
142 | },
143 |
144 | output_fields: ->(object_definitions) {
145 | [
146 | { name: 'report', type: :array, of: :object, properties: [
147 | { name: 'id' },
148 | { name: 'title', type: :object, properties: [
149 | { name: 'project' },
150 | { name: 'client' }
151 | ]},
152 | { name: 'time', type: :integer },
153 | { name: 'items', type: :array, of: :object, properties: [
154 | { name: 'title', type: :object, properties: [
155 | { name: 'time_entry' }
156 | ]}
157 | ]}
158 | ]}
159 | ]
160 | }
161 | },
162 | },
163 |
164 | triggers: {}
165 | }
166 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/amcards_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'AMcards.com',
3 | connection: {
4 | authorization: {
5 | type: 'oauth2',
6 |
7 | authorization_url: ->() {
8 | 'https://amcards.com/oauth2/authorize/?response_type=code&scope=read+write'
9 | },
10 |
11 | token_url: ->() {
12 | 'https://amcards.com/oauth2/access_token/'
13 | },
14 |
15 | client_id: 'doesThisNeedToBeInRepo?',
16 |
17 | client_secret: 'doesThisNeedToBeInRepo?',
18 |
19 | credentials: ->(connection, access_token) {
20 | headers('Authorization': "Bearer #{access_token}")
21 | }
22 | }
23 | },
24 |
25 | object_definitions: {
26 | card: {
27 | fields: ->() {
28 | [
29 | {
30 | name: 'template_id',
31 | type: :integer,
32 | hint: "You must own the template or it must be public in order to use it.",
33 | control_type: 'select',
34 | pick_list: 'templates',
35 | optional: false,
36 | },
37 | {
38 | name: 'message',
39 | label: 'Message for inside of card',
40 | control_type: 'text-area',
41 | hint: "Maximum of 700 characters please! Message will be added to the inside right (vertical) or inside bottom (horizontal) panel of the card. It will be added to the card and not replace an existing message!",
42 | },
43 | {
44 | name: 'send_date',
45 | type: :date,
46 | hint: "The card will be scheduled to mail out the next business day if you leave this out.",
47 | },
48 | {
49 | name: 'initiator',
50 | hint: "This is something that will help you to track who or what triggered this card.",
51 | optional: false,
52 | },
53 | {
54 | name: 'first_name',
55 | label: "TO: First Name",
56 | optional: false,
57 | },
58 | {
59 | name: 'last_name',
60 | label: "TO: Last Name",
61 | optional: false,
62 | },
63 | {
64 | name: 'organization',
65 | hint: "Only use this if the mailing address is for this place. This will be included on envelope.",
66 | label: "TO: Organization Name",
67 | },
68 | {
69 | name: 'address_line_1',
70 | label: "TO: Address Line 1",
71 | optional: false,
72 | },
73 | {
74 | name: 'address_line_2',
75 | label: "TO: Address Line 2",
76 | },
77 | {
78 | name: 'city',
79 | label: "TO: City",
80 | optional: false,
81 | },
82 | {
83 | name: 'state',
84 | label: "TO: State",
85 | hint: "Try to use 2 character state codes! ('UT' is better than 'Utah')",
86 | optional: false,
87 | },
88 | {
89 | name: 'postal_code',
90 | label: "TO: Postal/Zip Code",
91 | optional: false,
92 | },
93 | {
94 | name: 'country',
95 | label: "TO: Country",
96 | hint: "Try to use 2 character country codes! ('US' is better than 'United States')",
97 | },
98 | {
99 | name: 'return_first_name',
100 | label: "FROM: First Name",
101 | optional: false,
102 | },
103 | {
104 | name: 'return_last_name',
105 | label: "FROM: Last Name",
106 | optional: false,
107 | },
108 | {
109 | name: 'return_address_line_1',
110 | label: "FROM: Address Line 1",
111 | optional: false,
112 | },
113 | {
114 | name: 'return_address_line_2',
115 | label: "FROM: Address Line 2",
116 | },
117 | {
118 | name: 'return_city',
119 | label: "FROM: City",
120 | optional: false,
121 | },
122 | {
123 | name: 'return_state',
124 | label: "FROM: State",
125 | hint: "Use 2 character state codes! ('UT' is better than 'Utah')",
126 | optional: false,
127 | },
128 | {
129 | name: 'return_postal_code',
130 | label: "FROM: Postal/Zip Code",
131 | optional: false,
132 | },
133 | {
134 | name: 'return_country',
135 | label: "FROM: Country",
136 | default: "US",
137 | hint: "Use 2 character country codes! ('US' is better than 'United States')",
138 | },
139 | ]
140 | },
141 | },
142 | },
143 |
144 | actions: {
145 | create_card: {
146 | input_fields: ->(object_definitions) {
147 | object_definitions['card']
148 | },
149 |
150 | execute: ->(connection, input) {
151 | post("https://amcards.com/cards/open-card-form-oa/", input)
152 | },
153 |
154 | output_fields: ->(object_definitions) {
155 | object_definitions['card']
156 | },
157 | },
158 | },
159 |
160 | triggers: {
161 | # None so far...
162 | },
163 |
164 | pick_lists: {
165 | templates: ->(connection){
166 | get("https://amcards.com/.api/v1/template/")['objects'].
167 | map { |template| [template['name'], template['id']] }
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/bill_connector.rb:
--------------------------------------------------------------------------------
1 | # Adds operations missing from the standard adapter.
2 | {
3 | title: "Bill.com (custom)",
4 |
5 | connection: {
6 | fields: [
7 | {
8 | name: "user_name",
9 | hint: "Bill.com app login username",
10 | optional: false
11 | },
12 | {
13 | name: "password",
14 | hint: "Bill.com app login password",
15 | optional: false,
16 | control_type: "password"
17 | },
18 | {
19 | name: "org_id",
20 | label: "Organisation ID",
21 | hint: "Log in to your Bill.com account, click on gear icon, click " \
22 | "on settings then click on profiles under your company. The " \
23 | "Organization ID is at the end of the URL, after " \
24 | "https://[app/app-stage].bill.com/Organization?Id=",
25 | optional: false
26 | },
27 | {
28 | name: "dev_key",
29 | label: "Developer API key",
30 | hint: "Sign up for the developer program to get API key. " \
31 | "You may find more info here",
33 | optional: false,
34 | control_type: "password"
35 | },
36 | {
37 | name: "environment",
38 | hint: "Find more info here",
41 | control_type: "select",
42 | pick_list: [
43 | %w[Production api],
44 | %w[Sandbox/Stage api-stage]
45 | ],
46 | optional: false
47 | }
48 | ],
49 |
50 | authorization: {
51 | type: "custom_auth",
52 |
53 | acquire: lambda { |connection|
54 | {
55 | session_id: post("https://#{connection['environment']}.bill.com" \
56 | "/api/v2/Login.json").
57 | payload(userName: connection["user_name"],
58 | password: connection["password"],
59 | orgId: connection["org_id"],
60 | devKey: connection["dev_key"]).
61 | request_format_www_form_urlencoded.
62 | dig("response_data", "sessionId")
63 | }
64 | },
65 |
66 | refresh_on: [/"error_message"\s*\:\s*"Session is invalid/],
67 |
68 | detect_on: [/"response_message"\s*\:\s*"Error"/],
69 |
70 | apply: lambda { |connection|
71 | payload(sessionId: connection["session_id"],
72 | devKey: connection["dev_key"])
73 | request_format_www_form_urlencoded
74 | }
75 | },
76 |
77 | base_uri: lambda { |connection|
78 | "https://#{connection['environment']}.bill.com"
79 | }
80 | },
81 |
82 | test: lambda { |_connection|
83 | post("/api/v2/GetSessionInfo.json")
84 | },
85 |
86 | object_definitions: {
87 | vendor: {
88 | fields: lambda { |_connection, _config_fields|
89 | post("/api/v2/GetEntityMetadata.json").
90 | dig("response_data", "Vendor", "fields").
91 | map { |key, _value| { name: key } } || []
92 | }
93 | }
94 | },
95 |
96 | triggers: {
97 | new_or_updated_vendor: {
98 | subtitle: "New or updated vendor",
99 | description: "New or updated vendor in " \
100 | "Bill.com",
101 | type: "paging_desc",
102 |
103 | input_fields: lambda { |_connection|
104 | [
105 | {
106 | name: "since",
107 | label: "From",
108 | type: "timestamp",
109 | optional: true,
110 | sticky: true,
111 | hint: "Get vendors created or updated since given date/time. " \
112 | "Leave empty to get vendors created or updated one hour ago"
113 | }
114 | ]
115 | },
116 |
117 | poll: lambda { |_connection, input, page|
118 | page ||= 0
119 | page_size = 50
120 | query = {
121 | start: page,
122 | max: page_size,
123 | filters: [
124 | {
125 | field: "updatedTime",
126 | op: ">=",
127 | value: (input["since"].presence || 1.hour.ago).
128 | utc.
129 | strftime("%Y-%m-%dT%H:%M:%S.%L%z")
130 | }
131 | ],
132 | sort: [{ field: "updatedTime", asc: 0 }]
133 | }
134 |
135 | vendors = post("/api/v2/List/Vendor.json").
136 | payload(data: query.to_json).
137 | dig("response_data") || []
138 |
139 | {
140 | events: vendors,
141 | next_page: (vendors.size >= page_size ? page + page_size : nil)
142 | }
143 | },
144 |
145 | document_id: lambda { |vendor|
146 | vendor["id"]
147 | },
148 |
149 | sort_by: lambda { |vendor|
150 | vendor["updatedTime"]
151 | },
152 |
153 | output_fields: lambda { |object_definitions|
154 | object_definitions["vendor"]
155 | },
156 |
157 | sample_output: lambda { |_connection|
158 | post("/api/v2/List/Vendor.json").
159 | payload(data: { start: 0,
160 | max: 1,
161 | sort: [{ field: "updatedTime", asc: 0 }] }.to_json).
162 | dig("response_data", 0) || {}
163 | }
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/cisco_spark_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Cisco Spark',
3 |
4 | connection: {
5 | authorization: {
6 | type: 'oauth2',
7 |
8 | authorization_url: ->() {
9 | scope = [ "spark:messages_write",
10 | "spark:rooms_read",
11 | "spark:memberships_read",
12 | "spark:messages_read",
13 | "spark:rooms_write",
14 | "spark:people_read",
15 | "spark:memberships_write"].join(" ")
16 |
17 | "https://api.ciscospark.com/v1/authorize?response_type=code&scope=#{scope}"
18 | },
19 |
20 | token_url: ->() {
21 | "https://api.ciscospark.com/v1/access_token"
22 | },
23 |
24 | client_id: "YOUR_CISCO_SPARK_CLIENT_ID",
25 |
26 | client_secret: "YOUR_CISCO_SPARK_CLIENT_SECRET",
27 |
28 | credentials: ->(connection, access_token) {
29 | headers("Authorization": "Bearer #{access_token}")
30 | }
31 | }
32 | },
33 |
34 | object_definitions: {
35 | message: {
36 | fields: ->() {
37 | [
38 | { name: "id" },
39 | { name: "roomId" },
40 | { name: "personId" },
41 | { name: "personEmail" },
42 | { name: "created", type: :timestamp }
43 | ]
44 | }
45 | },
46 |
47 | message_detail: {
48 | fields: ->() {
49 | [
50 | { name: "id", optional: false },
51 | { name: "personId", hint: "The ID of the recipient when sending a private 1 to 1 message" },
52 | { name: "personEmail", hint: "The email address of the recipient when sendinga private 1:1 message" },
53 | { name: "roomId", control_type: "select", pick_list: "rooms" },
54 | { name: "text" },
55 | { name: "toPersonId" },
56 | { name: "toPersonEmail" },
57 | { name: "created", type: :timestamp }
58 | ]
59 | }
60 | },
61 |
62 | room: {
63 | fields: ->() {
64 | [
65 | { name: "id", control_type: 'select', pick_list: 'rooms', label: 'Room', optional: false },
66 | { name: "title" },
67 | { name: "type" },
68 | { name: "isLocked" },
69 | { name: "lastActivity", type: :timestamp },
70 | { name: "created", type: :timestamp }
71 | ]
72 | }
73 | },
74 |
75 | person: {
76 | fields: ->() {
77 | [
78 | { name: "id", label: "Person ID", optional: false },
79 | { name: "displayName" }
80 | ]
81 | }
82 | }
83 | },
84 |
85 | actions: {
86 | get_message_details: {
87 | input_fields: ->(object_definitions) {
88 | object_definitions['message_detail'].only('id')
89 | },
90 |
91 | execute: ->(connection,input) {
92 | get("https://api.ciscospark.com/v1/messages/" + input['id'])
93 | },
94 |
95 | output_fields: ->(object_definitions) {
96 | object_definitions['message_detail']
97 | }
98 | },
99 |
100 | get_room_details: {
101 | input_fields: ->(object_definitions) {
102 | object_definitions['room'].only('id')
103 | },
104 |
105 | execute: ->(connection,input) {
106 | get("https://api.ciscospark.com/v1/rooms/" + input['id'])
107 | },
108 |
109 | output_fields: ->(object_definitions) {
110 | object_definitions['room']
111 | }
112 | },
113 |
114 | get_person_details: {
115 | input_fields: ->(object_definitions) {
116 | object_definitions['person'].only('id')
117 | },
118 |
119 | execute: ->(connection,input) {
120 | get("https://api.ciscospark.com/v1/people/" + input['id'])
121 | },
122 |
123 | output_fields: ->(object_definitions) {
124 | object_definitions['person']
125 | }
126 | },
127 |
128 | post_message: {
129 | input_fields: ->(object_definitions) {
130 | object_definitions['message_detail'].only('roomId', 'text', 'toPersonEmail', 'toPersonId')
131 | },
132 |
133 | execute: ->(connection,input) {
134 | post("https://api.ciscospark.com/v1/messages", input)
135 | },
136 |
137 | output_fields: ->(object_definitions) {
138 | object_definitions['message_detail']
139 | }
140 | }
141 | },
142 |
143 | triggers: {
144 | new_message: {
145 | type: "paging_desc",
146 |
147 | input_fields: ->(object_definitions) {
148 | object_definitions['room'].only('id')
149 | },
150 |
151 | webhook_subscribe: ->(webhook_url, connection, input, flow_id) {
152 | post('https://api.ciscospark.com/v1/webhooks',
153 | name: "Workato recipe #{flow_id}",
154 | targetUrl: webhook_url,
155 | resource: 'messages',
156 | event: 'created',
157 | filter: "roomId=#{input['id']}")
158 | },
159 |
160 | webhook_notification: ->(input, payload) {
161 | payload['data']
162 | },
163 |
164 | webhook_unsubscribe: ->(webhook) {
165 | delete("https://api.ciscospark.com/v1/webhooks/#{webhook['id']}")
166 | },
167 |
168 | dedup: ->(message) {
169 | message['id']
170 | },
171 |
172 | output_fields: ->(object_definitions) {
173 | object_definitions['message']
174 | }
175 | }
176 | },
177 |
178 | pick_lists: {
179 | rooms: ->(connection) {
180 | get("https://api.ciscospark.com/v1/rooms")['items'].map { |r| [r['title'], r['id']] }
181 | }
182 | },
183 | }
184 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/typeform_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "Typeform",
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "client_id",
8 | label: "Client ID",
9 | hint: "You can find your client ID in the settings page.",
10 | optional: false
11 | },
12 | {
13 | name: "client_secret",
14 | label: "Client Secret",
15 | control_type: "password",
16 | hint: "You can find your client ID in the settings page.",
17 | optional: false
18 | }
19 | ],
20 |
21 | authorization: {
22 | type: "oauth2",
23 |
24 | authorization_url: lambda do |connection|
25 | scopes = ["forms:read", "workspaces:read"].join(" ")
26 |
27 | "https://api.typeform.com/oauth/authorize?client_id=" \
28 | "#{connection['client_id']}&scope=#{scopes}" \
29 | "&redirect_uri=https%3A%2F%2Fwww.workato.com%2Foauth%2Fcallback"
30 | end,
31 |
32 | acquire: lambda do |connection, auth_code, _redirect_uri|
33 | response = post("https://api.typeform.com/oauth/token").
34 | payload(client_id: connection["client_id"],
35 | client_secret: connection["client_secret"],
36 | code: auth_code,
37 | redirect_uri: "https://www.workato.com/oauth/" \
38 | "callback").
39 | request_format_www_form_urlencoded
40 |
41 | [response, nil, nil]
42 | end,
43 |
44 | apply: lambda { |_connection, access_token|
45 | headers("Authorization": "Bearer #{access_token}")
46 | }
47 | },
48 |
49 | base_uri: lambda do
50 | "https://api.typeform.com"
51 | end
52 | },
53 |
54 | object_definitions: {
55 | get_forms: {
56 | fields: lambda do |_object_definitions|
57 | [
58 | {
59 | name: "workspace_id",
60 | label: "Workspace",
61 | hint: "Workspace that form belongs to",
62 | type: "string",
63 | control_type: "select",
64 | pick_list: "workspaces"
65 | },
66 | {
67 | name: "search",
68 | label: "Form Name",
69 | hint: "Whole or partial form name to search for",
70 | type: "string"
71 | }
72 | ]
73 | end
74 | },
75 |
76 | forms: {
77 | fields: lambda do |_object_definitions|
78 | [
79 | { name: "id" },
80 | { name: "title" },
81 | { name: "last_updated_at", type: "timestamp" },
82 | {
83 | name: "self",
84 | type: "object",
85 | properties: [
86 | { name: "href" }
87 | ]
88 | },
89 | {
90 | name: "theme",
91 | type: "object",
92 | properties: [
93 | { name: "href" }
94 | ]
95 | },
96 | {
97 | name: "_links",
98 | type: "object",
99 | properties: [
100 | { name: "display" }
101 | ]
102 | }
103 | ]
104 | end
105 | }
106 | },
107 |
108 | actions: {
109 | search_forms: {
110 | subtitle: "Search forms",
111 | description: "Search forms in " \
112 | "Typeform",
113 | help: "Search will return a list of forms that matches " \
114 | "the search criteria.",
115 |
116 | input_fields: lambda do |object_definitions|
117 | object_definitions["get_forms"]
118 | end,
119 |
120 | execute: lambda do |_connection, input|
121 | {
122 | forms: get("/forms").
123 | params(search: input["search"],
124 | page_size: 200,
125 | workspace_id: input["workspace_id"])["items"]
126 | }
127 | end,
128 |
129 | output_fields: lambda do |object_definitions|
130 | [
131 | {
132 | name: "forms",
133 | type: "array",
134 | of: "object",
135 | properties: object_definitions["forms"]
136 | }
137 | ]
138 | end,
139 |
140 | sample_output: lambda do |_connection, _input|
141 | {
142 | forms: get("/forms").
143 | params(page_size: 1)["items"] || []
144 | }
145 | end
146 | }
147 | },
148 |
149 | triggers: {
150 | new_form: {
151 | # Results are listed in descending order based on the modified date.
152 | type: :paging_desc,
153 |
154 | description: "New Form " \
155 | "in Typeform",
156 | subtitle: "New form in Typeform",
157 |
158 | poll: lambda do |_connection, _input, closure|
159 | closure ||= 1
160 | per_page = 100
161 |
162 | forms = get("/forms").
163 | params(page_size: per_page,
164 | page: closure)
165 |
166 | {
167 | events: forms["items"] || [],
168 | next_page: forms.length >= per_page ? closure + 1 : nil
169 | }
170 | end,
171 |
172 | dedup: lambda do |forms|
173 | forms["id"]
174 | end,
175 |
176 | output_fields: lambda do |object_definitions|
177 | object_definitions["forms"]
178 | end,
179 |
180 | sample_output: lambda do |_connection, _input|
181 | get("/forms").params(page_size: 1).dig("items", 0) || {}
182 | end
183 | }
184 | },
185 |
186 | pick_lists: {
187 | workspaces: lambda do |_connection|
188 | get("/workspaces")["items"].
189 | pluck("name", "id")
190 | end
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/wrike_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Wrike',
3 |
4 | connection: {
5 | authorization: {
6 | type: 'oauth2',
7 |
8 | authorization_url: ->() {
9 | 'https://www.wrike.com/oauth2/authorize?response_type=code'
10 | },
11 |
12 | token_url: ->() {
13 | 'https://www.wrike.com/oauth2/token'
14 | },
15 |
16 | client_id: 'YOUR_WRIKE_CLIENT_ID',
17 |
18 | client_secret: 'YOUR_WRIKE_CLIENT_SECRET',
19 |
20 | credentials: ->(connection, access_token) {
21 | headers('Authorization': "Bearer #{access_token}")
22 | }
23 | }
24 | },
25 |
26 | object_definitions: {
27 |
28 | task: {
29 | fields: ->() {
30 | [
31 | { name: 'id' },
32 | { name: 'accountId' },
33 | { name: 'title', hint: 'Searches for exact match' },
34 | { name: 'description' },
35 | { name: 'briefDescription' },
36 | { name: 'status', hint: 'Accepted values are Active, Completed, Deferred and Cancelled' },
37 | { name: 'importance', hint: 'Accepted values are High, Normal and Low' },
38 | { name: 'createdDate', type: :timestamp },
39 | { name: 'updatedDate', type: :timestamp },
40 | { name: 'dates', type: :object, properties: [
41 | { name: 'type' },
42 | { name: 'duration', type: :integer},
43 | { name: 'start', type: :timestamp },
44 | { name: 'due', type: :timestamp }
45 | ]},
46 | { name: 'scope' },
47 | { name: 'customStatusId' },
48 | { name: 'hasAttachments', type: :boolean },
49 | { name: 'attachmentCount', type: :integer },
50 | { name: 'permalink', control_type: 'url' },
51 | { name: 'priority' },
52 | { name: 'responsibles', control_type: 'select', pick_list: 'user' }
53 | ]
54 | },
55 | }
56 | },
57 |
58 | actions: {
59 |
60 | get_task_by_id: {
61 | input_fields: ->(object_definitions) {
62 | [{ name: 'id', optional: false }]
63 | },
64 |
65 | execute: ->(connection,input) {
66 | get("https://www.wrike.com/api/v3/tasks/#{input['id']}")['data'].first
67 | },
68 |
69 | output_fields: ->(object_definitions) {
70 | object_definitions['task']
71 | }
72 | },
73 |
74 | search_task: {
75 | input_fields: ->(object_definitions) {
76 | [{ name: 'created_after' }].concat(object_definitions['task'].only('title', 'status', 'importance'))
77 | },
78 |
79 | execute: ->(connection,input) {
80 | if input['created_after'].present?
81 | created_date_query = '?createdDate={"start":"' + input['created_after'].to_time.utc.iso8601 + '"}'
82 | input = input.reject { |k,v| k == 'created_after' }
83 | end
84 |
85 | get("https://www.wrike.com/api/v3/tasks" + (created_date_query || ""), input)['data']
86 | },
87 |
88 | output_fields: ->(object_definitions) {
89 | [
90 | { name: 'tasks', type: :array, of: :object, properties: object_definitions['task'] }
91 | ]
92 | }
93 | },
94 |
95 | create_task: {
96 | input_fields: ->(object_definitions) {
97 | [{ name: 'folder_id', control_type: 'select', pick_list: 'folder' }].
98 | concat(object_definitions['task'].
99 | only('title', 'description', 'status', 'importance', 'responsibles')).
100 | required('folder_id', 'title')
101 | },
102 |
103 | execute: ->(connection,input) {
104 | updated_input = input.reject { |k,v| k == 'folder_id' }
105 |
106 | updated_input['responsibles'] = "[" + updated_input['responsibles'] + "]"
107 |
108 | post("https://www.wrike.com/api/v3/folders/#{input['folder_id']}/tasks").params(updated_input)['data'].first
109 | },
110 |
111 | output_fields: ->(object_definitions) {
112 | object_definitions['task']
113 | }
114 | },
115 |
116 | update_task: {
117 | input_fields: ->(object_definitions) {
118 | [{ name: 'id', optional: false }].
119 | concat(object_definitions['task'].
120 | only('title', 'description', 'status', 'importance'))
121 | },
122 |
123 | execute: ->(connection,input) {
124 | updated_input = input.reject { |k,v| k == 'id' }
125 |
126 | put("https://www.wrike.com/api/v3/tasks/#{input['id']}").params(updated_input)['data'].first
127 | },
128 |
129 | output_fields: ->(object_definitions) {
130 | object_definitions['task']
131 | }
132 | }
133 | },
134 |
135 | triggers: {
136 |
137 | new_or_updated_task: {
138 |
139 | type: :paging_desc,
140 |
141 | input_fields: ->(object_definition) {
142 | [{ name: 'since', type: :timestamp, optional: false, hint: 'Select earliest updated date' }]
143 | },
144 |
145 | poll: ->(connection,input,next_page) {
146 | params = {
147 | 'updatedDate' => '{"start":"' + input['since'].to_time.utc.iso8601 + '"}',
148 | 'sortField' => 'UpdatedDate',
149 | 'sortOrder' => 'Desc',
150 | 'pageSize' => '10',
151 | 'nextPageToken' => next_page
152 | }
153 |
154 | response = get("https://www.wrike.com/api/v3/tasks", params)
155 |
156 | {
157 | events: response['data'],
158 | next_page: response['nextPageToken'],
159 | }
160 | },
161 |
162 | output_fields: ->(object_definitions) {
163 | object_definitions['task']
164 | }
165 | }
166 | },
167 |
168 | pick_lists: {
169 | folder: ->(connection) {
170 | get("https://www.wrike.com/api/v3/folders")['data'].
171 | map { |folder| [folder['title'], folder['id']] }
172 | },
173 |
174 | user: ->(connection) {
175 | get("https://www.wrike.com/api/v3/contacts")['data'].
176 | map { |contact| [contact['firstName'] + " " + contact['lastName'], contact['id']] }
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/freshdesk_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Freshdesk',
3 |
4 | # HTTP basic auth example.
5 | connection: {
6 | fields: [
7 | {
8 | name: 'helpdesk',
9 | control_type: 'subdomain',
10 | url: '.freshdesk.com',
11 | hint: 'Your helpdesk name as found in your Freshdesk URL'
12 | },
13 | {
14 | name: 'username',
15 | optional: true,
16 | hint: 'Your username; leave empty if using API key below'
17 | },
18 | {
19 | name: 'password',
20 | control_type: 'password',
21 | label: 'Password or personal API key'
22 | }
23 | ],
24 |
25 | authorization: {
26 | type: 'basic_auth',
27 |
28 | # Basic auth credentials are just the username and password; framework handles adding
29 | # them to the HTTP requests.
30 | credentials: ->(connection) {
31 | # Freshdesk-specific quirk: If only using API key to authenticate, API expects it as username,
32 | # but we prefer to store it in 'password' to keep it obscured (control_type: 'password' above).
33 | if connection['username'].blank?
34 | user(connection['password'])
35 | else
36 | user(connection['username'])
37 | password(connection['password'])
38 | end
39 | }
40 | }
41 | },
42 |
43 | object_definitions: {
44 |
45 | user: {
46 |
47 | # Provide a preview user to display in the recipe data tree.
48 | preview: ->(connection) {
49 | get("https://#{connection['helpdesk']}.freshdesk.com/api/users.json?page_size=1&wf_order=created_at&wf_order_type=desc")['results'].first
50 | },
51 |
52 | fields: ->() {
53 | [
54 | {
55 | name: 'id',
56 | type: :integer
57 | },
58 | {
59 | name: 'name',
60 | },
61 | {
62 | name: 'email'
63 | # type defaults to string
64 | },
65 | {
66 | name: 'created_at',
67 | type: :timestamp
68 | }
69 | ]
70 | },
71 | },
72 |
73 | ticket: {
74 |
75 | fields: ->() {
76 | [
77 | {
78 | name: 'id',
79 | type: :integer
80 | },
81 | {
82 | name: 'email',
83 | control_type: 'email'
84 | },
85 | {
86 | name: 'subject'
87 | },
88 | {
89 | name: 'description'
90 | }
91 | ]
92 | }
93 | }
94 | },
95 |
96 | test: ->(connection) {
97 | get("https://#{connection['helpdesk']}.freshdesk.com/agents.json")
98 | },
99 |
100 | actions: {
101 | create_user: {
102 | input_fields: ->(object_definitions) {
103 | object_definitions['user'].ignored('id', 'created_at').required('email')
104 | },
105 |
106 | execute: ->(connection, input) {
107 | # Freshdesk API uses a 'user' envelope around this endpoint's input,
108 | # and responds in a similar envelope.
109 | post("https://#{connection['helpdesk']}.freshdesk.com/contacts.json", { user: input } )['user']
110 | },
111 |
112 | # Output schema. Same as input above.
113 | output_fields: ->(object_definitions) {
114 | # API endpoint just returns the whole object, so we don't need to adapt the object
115 | # fields definition any further here.
116 | object_definitions['user']
117 | }
118 | },
119 |
120 | search_users: {
121 | input_fields: ->(object_definitions) {
122 | # Assuming here that the API only allows searching by these terms.
123 | object_definitions['user'].only('id', 'email')
124 | },
125 |
126 | execute: ->(connection, input) {
127 | {
128 | 'users': get("https://#{connection['helpdesk']}.freshdesk.com/api/users.json", input)['results']
129 | }
130 | },
131 |
132 | output_fields: ->(object_definitions) {
133 | [
134 | {
135 | name: 'users',
136 | type: :array,
137 | of: :object,
138 | properties: object_definitions['user']
139 | }
140 | ]
141 | }
142 | }
143 | },
144 |
145 | triggers: {
146 |
147 | new_ticket: {
148 |
149 | input_fields: ->() {
150 | [
151 | {
152 | name: 'since',
153 | type: :timestamp,
154 | hint: 'Defaults to tickets created after the recipe is first started'
155 | }
156 | ]
157 | },
158 |
159 | poll: ->(connection, input, last_updated_since) {
160 | updated_since = last_updated_since || input['since'] || Time.now
161 |
162 | tickets = get("https://#{connection['helpdesk']}.freshdesk.com/api/v2/tickets.json").
163 | params(order_by: 'updated_at', # Because we can only query by updated_since in this API.
164 | order_type: 'asc', # We expect events in ascending order.
165 | per_page: 2, # Small page size to help with testing.
166 | updated_since: updated_since.to_time.utc.iso8601)
167 |
168 | next_updated_since = tickets.last['updated_at'] unless tickets.blank?
169 |
170 | # Return three items:
171 | # - The polled objects/events (default: empty/nil if nothing found)
172 | # - Any data needed for the next poll (default: nil, uses one from previous poll if available)
173 | # - Flag on whether more objects/events may be immediately available (default: false)
174 | {
175 | events: tickets,
176 | next_poll: next_updated_since,
177 | # common heuristic when no explicit next_page available in response: full page means maybe more.
178 | can_poll_more: tickets.length >= 2
179 | }
180 | },
181 |
182 | dedup: ->(ticket) {
183 | ticket['id']
184 | },
185 |
186 | output_fields: ->(object_definitions) {
187 | object_definitions['ticket']
188 | }
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/blacklinereports.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'BlackLine Reports',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'environment',
8 | control_type: 'select',
9 | pick_list: [%w[Production us], %w[Sandbox sbus]],
10 | optional: false
11 | },
12 | {
13 | name: 'data_center',
14 | hint: 'Ex: 2, if the app URL is ' \
15 | 'https://subdomain.us2.blackline.com/',
16 | optional: false
17 | },
18 | { name: 'username', optional: false },
19 | {
20 | name: 'api_key',
21 | label: 'API key',
22 | hint: 'Login to app as System Admin and generate an API key by ' \
23 | 'navigating to - System > Users Admin Grid > User > User Information',
24 | control_type: 'password',
25 | optional: false
26 | },
27 | {
28 | name: 'client_id',
29 | hint: 'Ex: subdomain, if the app URL is ' \
30 | 'https://subdomain.us2.blackline.com',
31 | optional: false
32 | },
33 | { name: 'client_secret', control_type: 'password', optional: false },
34 | {
35 | name: 'user_scope',
36 | hint: 'Ex: ReportsAPI instance_ABCD-1234-5AC6-7D89-1C0A2345B6AB',
37 | optional: false
38 | }
39 | ],
40 |
41 | base_uri: lambda do |connection|
42 | "https://#{connection['environment']}#{connection['data_center']}" \
43 | '.api.blackline.com'
44 | end,
45 |
46 | authorization: {
47 | type: 'custom',
48 |
49 | acquire: lambda do |connection|
50 | auth_header =
51 | "#{connection['client_id']}:#{connection['client_secret']}".
52 | encode_base64
53 | response = post('/authorize/connect/token').
54 | headers('Content-Type' =>
55 | 'application/x-www-form-urlencoded',
56 | 'Authorization' => "Basic #{auth_header}").
57 | payload(grant_type: 'password',
58 | password: connection['api_key'],
59 | scope: connection['user_scope'],
60 | username: connection['username']).
61 | request_format_www_form_urlencoded
62 |
63 | { access_token: response['access_token'] }
64 | end,
65 |
66 | refresh_on: [401],
67 |
68 | apply: lambda do |connection|
69 | headers('Authorization' => "Bearer #{connection['access_token']}")
70 | end
71 | }
72 | },
73 |
74 | object_definitions: {
75 | report: {
76 | fields: lambda do |_connection, _config_fields|
77 | [
78 | {
79 | control_type: 'text',
80 | label: 'End time',
81 | render_input: 'date_time_conversion',
82 | parse_output: 'date_time_conversion',
83 | type: 'date_time',
84 | name: 'endTime'
85 | },
86 | {
87 | name: 'exportUrls',
88 | type: 'array',
89 | of: 'object',
90 | label: 'Export URLs',
91 | properties: [{ name: 'type' }, { name: 'url', label: 'URL' }]
92 | },
93 | {
94 | control_type: 'number',
95 | label: 'ID',
96 | parse_output: 'float_conversion',
97 | type: 'number',
98 | name: 'id'
99 | },
100 | { name: 'message' },
101 | { name: 'name' },
102 | { name: 'notes' },
103 | {
104 | control_type: 'text',
105 | label: 'Start time',
106 | render_input: 'date_time_conversion',
107 | parse_output: 'date_time_conversion',
108 | type: 'date_time',
109 | name: 'startTime'
110 | },
111 | { name: 'status' }
112 | ]
113 | end
114 | }
115 | },
116 |
117 | test: ->(_connection) { get('/api/queryruns') },
118 |
119 | actions: {
120 | get_report_content: {
121 | title: 'Get report content in CSV',
122 | description: "Get report content (CSV) " \
123 | "in BlackLine Reports",
124 |
125 | execute: lambda do |_connection, input|
126 | {
127 | content: get("/api/completedqueryrun/#{input['report_id']}/CSV").
128 | response_format_raw.
129 | encode.to_s.gsub(/�/, '')
130 | }
131 | end,
132 |
133 | input_fields: lambda do |_connection|
134 | [{ name: 'report_id',
135 | type: 'integer',
136 | optional: false,
137 | hint: 'Only reports with CSV ExportURLs can be used' }]
138 | end,
139 |
140 | output_fields: ->(_object_definitions) { [{ name: 'content' }] },
141 |
142 | sample_output: lambda do |_connection, _input|
143 | { content: 'EUR 0.99 01/01/2000 M' }
144 | end
145 | },
146 |
147 | list_reports: {
148 | description: "List reports " \
149 | "in BlackLine Reports",
150 |
151 | execute: lambda do |_connection, _input|
152 | {
153 | reports: get('/api/queryruns').
154 | after_error_response(/.*/) do |_code, body, _header, message|
155 | error("#{message}: #{body}")
156 | end
157 | }
158 | end,
159 |
160 | output_fields: lambda do |object_definitions|
161 | [{
162 | name: 'reports',
163 | type: 'array',
164 | of: 'object',
165 | properties: object_definitions['report']
166 | }]
167 | end,
168 |
169 | sample_output: lambda do |_connection, _input|
170 | {
171 | 'endTime' => '2019-01-01T23:16:05.543Z',
172 | 'exportUrls' => [],
173 | 'id' => 123_456,
174 | 'message' => '',
175 | 'name' => 'User Access',
176 | 'notes' => 'User Access - List of users showing their current ' \
177 | 'authorized Roles',
178 | 'startTime' => '2019-01-01T23:16:03.433Z',
179 | 'status' => 'Complete'
180 | }
181 | end
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/salesforceiq_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "SalesforceIQ",
3 |
4 | connection: {
5 | fields: [
6 | { name: "api_key",
7 | label: "API key",
8 | optional: false,
9 | hint: "Get more info from here" },
11 | { name: "api_secret",
12 | label: "API secret",
13 | optional: false,
14 | control_type: "password",
15 | hint: "Get more info from here" }
17 | ],
18 |
19 | authorization: {
20 | type: "basic_auth",
21 |
22 | credentials: lambda do |connection|
23 | user(connection["api_key"])
24 | password(connection["api_secret"])
25 | end
26 | },
27 |
28 | base_uri: lambda do
29 | "https://api.salesforceiq.com"
30 | end
31 | },
32 |
33 | test: lambda do |_connection|
34 | get("/v2/accounts?_limit=1")
35 | end,
36 |
37 | object_definitions: {
38 | account: {
39 | fields: lambda do |_connection|
40 | [
41 | { name: "id" },
42 | { name: "name", optional: false },
43 | { name: "modifiedDate", label: "Modified date", type: :integer,
44 | hint: "Stores a particular Date & Time in UTC milliseconds past" \
45 | " the epoch." }, # milliseconds since epoch
46 | ].concat(
47 | get("/v2/accounts/fields")["fields"].
48 | map do |field|
49 | if field["dataType"] == "List"
50 | pick_list = field["listOptions"].pluck("display", "id")
51 | end
52 |
53 | {
54 | name: field["id"],
55 | label: field["name"],
56 | control_type: field["dataType"] == "List" ? "select" : "text",
57 | pick_list: pick_list
58 | }
59 | end
60 | )
61 | end
62 | },
63 | },
64 |
65 | actions: {
66 | create_account: {
67 | description: "Create Account in " \
68 | "SalesforceIQ",
69 |
70 | input_fields: lambda do |object_definitions|
71 | object_definitions["account"].
72 | ignored("id", "modifiedDate", "address_city", "address_state",
73 | "address_postal_code", "address_country")
74 | end,
75 |
76 | execute: lambda do |_connection, input|
77 | fields = input.reject { |key, _| key == "name" }.
78 | inject({}) do |hash, (key, value)|
79 | hash.merge(key => [{ raw: value }])
80 | end
81 | post("/v2/accounts").
82 | payload(name: input["name"], fieldValues: fields)
83 | end,
84 |
85 | output_fields: lambda do |object_definitions|
86 | object_definitions["account"]
87 | end,
88 |
89 | sample_output: lambda do
90 | get("/v2/accounts").
91 | params(_limit: 1).dig("objects", 0) || {}
92 | end
93 | },
94 |
95 | search_account: {
96 | description: "Search Account in " \
97 | "SalesforceIQ",
98 | help: "Returns accounts matching the IDs. Returns all" \
99 | " accounts, if blank.",
100 |
101 | input_fields: lambda do
102 | [
103 | { name: "_ids", label: "Account identifiers",
104 | hint: "Comma separated list of account identifiers" }
105 | ]
106 | end,
107 |
108 | execute: lambda do |_connection, input|
109 | accounts = get("/v2/accounts",
110 | input)["objects"].each do |account|
111 | (account["fieldValues"] || {}).map do |k, v|
112 | account[k] = v.dig(0, "raw")
113 | end
114 | end
115 |
116 | {
117 | "accounts": accounts
118 | }
119 | end,
120 |
121 | output_fields: lambda do |object_definitions|
122 | [
123 | {
124 | name: "accounts", type: :array, of: :object,
125 | properties: object_definitions["account"]
126 | }
127 | ]
128 | end,
129 |
130 | sample_output: lambda do
131 | get("/v2/accounts").
132 | params(_limit: 1).dig("objects", 0) || {}
133 | end
134 | }
135 | },
136 |
137 | triggers: {
138 | new_or_updated_accounts: {
139 | description: "New/Updated Account in " \
140 | "SalesforceIQ",
141 | help: "Checks for new or updated accounts.",
142 |
143 | input_fields: lambda do
144 | [
145 | {
146 | name: "since", type: :timestamp,
147 | sticky: true, label: "From",
148 | hint: "Fetch trigger events from specified time. If left blank," \
149 | " accounts are processed from recipe start time"
150 | }
151 | ]
152 | end,
153 |
154 | poll: lambda do |_connection, input, _|
155 | limit = 50
156 | modified_date ||= ((input["since"].presence || Time.now.utc).
157 | to_time.to_f * 1000).to_i
158 | # result returns in ascending order
159 | result = get("/v2/accounts").
160 | params(_limit: limit, _start: 0,
161 | modifiedDate: modified_date)["objects"]
162 | accounts = result.each do |account|
163 | (account["fieldValues"] || {}).map do |k, v|
164 | account[k] = v.dig(0, "raw")
165 | end
166 | end
167 | modified_date_since = accounts.dig(-1, "modifiedDate") ||
168 | (Time.now.to_f * 1000).to_i
169 |
170 | {
171 | events: accounts,
172 | next_poll: modified_date_since,
173 | can_poll_more: accounts.size >= limit
174 | }
175 | end,
176 |
177 | dedup: lambda do |account|
178 | [account["id"], account["modifiedDate"]].join("_")
179 | end,
180 |
181 | output_fields: lambda do |object_definitions|
182 | object_definitions["account"]
183 | end,
184 |
185 | sample_output: lambda do
186 | get("/v2/accounts").
187 | params(_limit: 1).dig("objects", 0) || {}
188 | end
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/mandrill_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "Mandrill",
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "api_key",
8 | label: "API key",
9 | control_type: "password",
10 | hint: "You may find the API key here",
12 | optional: false
13 | }
14 | ],
15 |
16 | authorization: {
17 | type: "api_key",
18 |
19 | acquire: ->(_connection) {},
20 |
21 | refresh_on: [/"name"\:\s*"Invalid_Key"/],
22 |
23 | detect_on: [
24 | /"status"\:\s*"error"/,
25 | /"reject_reason"\:"*"/,
26 | /"status"\:\s*"invalid"/
27 | ],
28 |
29 | apply: ->(connection) { payload(key: connection["api_key"]) }
30 | },
31 |
32 | base_uri: ->(_connection) { "https://mandrillapp.com" }
33 | },
34 |
35 | test: ->(_connection) { post("/api/1.0/users/ping.json") },
36 |
37 | object_definitions: {
38 | send_template: {
39 | fields: lambda { |_connection, config_fields|
40 | template_variables = if config_fields.blank?
41 | []
42 | else
43 | post("/api/1.0/templates/info.json").
44 | payload(name: config_fields["template_name"]).
45 | dig("code").
46 | scan(/mc:edit=\"([^\"]*)\"/).
47 | map do |var|
48 | {
49 | name: var.first,
50 | hint: "Include html tags for better " \
51 | "formatting"
52 | }
53 | end
54 | end
55 |
56 | if template_variables.blank?
57 | []
58 | else
59 | [{
60 | name: "template_content",
61 | type: "object",
62 | properties: template_variables
63 | }]
64 | end.concat([
65 | {
66 | name: "message",
67 | optional: false,
68 | type: "object",
69 | properties: [
70 | {
71 | name: "from_email",
72 | hint: "The sender email address",
73 | optional: false
74 | },
75 | {
76 | name: "from_name",
77 | hint: "The sender name"
78 | },
79 | {
80 | name: "to",
81 | hint: "List of email recipients, one per line.",
82 | optional: false
83 | },
84 | {
85 | name: "important",
86 | hint: "Whether or not this message is important, " \
87 | "and should be delivered ahead of non-important " \
88 | "messages.",
89 | control_type: "checkbox",
90 | type: "boolean"
91 | },
92 | {
93 | name: "track_opens",
94 | hint: "Whether or not to turn on open tracking " \
95 | "for the message",
96 | control_type: "checkbox",
97 | type: "boolean"
98 | },
99 | {
100 | name: "track_clicks",
101 | hint: "Whether or not to turn on click tracking " \
102 | "for the message",
103 | control_type: "checkbox",
104 | type: "boolean"
105 | }
106 | ]
107 | },
108 | {
109 | name: "send_at",
110 | hint: "When this message should be sent. If you " \
111 | "specify a time in the past, the message will be " \
112 | "sent immediately.",
113 | type: "timestamp"
114 | }
115 | ])
116 | }
117 | }
118 | },
119 |
120 | actions: {
121 | send_message: {
122 | description: "Send message using " \
123 | "template in Mandrill",
124 |
125 | config_fields: [
126 | {
127 | name: "template_name",
128 | control_type: "select",
129 | pick_list: "templates",
130 | optional: false
131 | }
132 | ],
133 |
134 | input_fields: lambda { |object_definitions|
135 | object_definitions["send_template"]
136 | },
137 |
138 | execute: lambda { |_connection, input|
139 | input["template_content"] = (input["template_content"] || []).
140 | map do |key, val|
141 | { name: key, content: val }
142 | end
143 | input["message"]["to"] = (input["message"]["to"] || "").
144 | split("\n").
145 | map { |to| { email: to.strip } }
146 | if input["send_at"].present?
147 | input["send_at"] = input["send_at"].
148 | to_time.
149 | utc.
150 | strftime("%Y-%m-%d %H:%M:%S.%6N")
151 | end
152 |
153 | post("/api/1.0/messages/send-template.json", input).dig(0) || {}
154 | },
155 |
156 | output_fields: lambda { |_object_definitions|
157 | [{ name: "email" },
158 | { name: "status" },
159 | { name: "_id" }]
160 | },
161 |
162 | sample_output: lambda {
163 | {
164 | email: "mail@workato.com",
165 | status: "send",
166 | _id: "abc123abc123abc123abc123abc123"
167 | }
168 | }
169 | }
170 | },
171 |
172 | pick_lists: {
173 | templates: lambda { |_connection|
174 | post("/api/1.0/templates/list.json").pluck("name", "slug")
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/splunk_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "Splunk",
3 | secure_tunnel: true,
4 |
5 | connection: {
6 | fields: [
7 | {
8 | name: "server_url",
9 | label: "Server URL",
10 | control_type: "text",
11 | hint: "The URL of the Splunk management port " \
12 | "(e.g. https://yourdomain:8089). You MUST install the " \
13 | "" \
14 | "Workato Add-on for Splunk first."
15 | },
16 | {
17 | name: "username",
18 | hint: "The Splunk username (e.g. admin)"
19 | },
20 | {
21 | name: "password",
22 | control_type: "password",
23 | hint: "The password for the Splunk username"
24 | }
25 | ],
26 |
27 | authorization: {
28 | type: "basic_auth",
29 | credentials: lambda do |connection|
30 | user(connection["username"])
31 | password(connection["password"])
32 | end
33 | }
34 | },
35 |
36 | test: lambda do |connection|
37 | get("#{connection['server_url']}/services/workato/version")
38 | end,
39 |
40 | object_definitions: {
41 | generic_alert: {
42 | fields: lambda do |_connection, config_fields|
43 | config_fields["fields"].split(",").map do |name|
44 | {
45 | name: name.strip
46 | }
47 | end
48 | end
49 | },
50 |
51 | service_alert: {
52 | fields: lambda do |_connection, _config_fields|
53 | [
54 | { name: "event_id", type: :string, optional: false },
55 | { name: "severity", type: :string },
56 | { name: "title", type: :string },
57 | { name: "_time", type: :integer, optional: false },
58 | { name: "severity_label", type: :string },
59 | { name: "description", type: :string },
60 | ]
61 | end
62 | },
63 | },
64 |
65 | triggers: {
66 | new_generic_alert: {
67 | input_fields: lambda do |_object_definitions|
68 | [{
69 | name: "search_name",
70 | label: "Splunk alert",
71 | type: :string,
72 | control_type: :select,
73 | pick_list: "saved_searches",
74 | optional: false,
75 | hint: "Select one of the alerts saved in Splunk that " \
76 | "have the Workato alert action assigned.",
77 | }]
78 | end,
79 |
80 | config_fields: [
81 | {
82 | name: "fields",
83 | label: "Alert fields",
84 | type: :string,
85 | optional: false,
86 | hint: "Comma-separated field names to be taken over from the Splunk" \
87 | "data (e.g. host, count)",
88 | }
89 | ],
90 |
91 | webhook_subscribe: lambda do |callback_url, connection, input, _flow_id|
92 | data = post(
93 | "#{connection['server_url']}/services/workato/alerts",
94 | callback_url: callback_url,
95 | search_name: input["search_name"]
96 | )
97 | {
98 | server_url: connection["server_url"],
99 | search_name: data["search_name"],
100 | callback_url: data["callback_url"]
101 | }
102 | end,
103 |
104 | webhook_unsubscribe: lambda do |subscription|
105 | delete(
106 | "#{subscription['server_url']}/services/workato/alerts",
107 | search_name: subscription["search_name"],
108 | callback_url: subscription["callback_url"]
109 | )
110 | end,
111 |
112 | webhook_notification: lambda do |_input, payload|
113 | payload
114 | end,
115 |
116 | dedup: lambda do |_event|
117 | rand()
118 | end,
119 |
120 | output_fields: lambda do |object_definitions|
121 | object_definitions["generic_alert"]
122 | end
123 | },
124 | new_service_alert: {
125 | webhook_subscribe: lambda do |callback_url, connection, _input, _flow_id|
126 | data = post(
127 | "#{connection['server_url']}/services/workato/servicealerts",
128 | callback_url: callback_url
129 | )
130 | {
131 | server_url: connection["server_url"],
132 | search_name: data["search_name"],
133 | callback_url: data["callback_url"]
134 | }
135 | end,
136 |
137 | webhook_unsubscribe: lambda do |subscription|
138 | delete(
139 | "#{subscription['server_url']}/services/workato/servicealerts",
140 | search_name: subscription["search_name"],
141 | callback_url: subscription["callback_url"]
142 | )
143 | end,
144 |
145 | webhook_notification: lambda do |_input, payload|
146 | payload
147 | end,
148 |
149 | dedup: lambda do |event|
150 | event["event_id"]
151 | end,
152 |
153 | output_fields: lambda do |object_definitions|
154 | object_definitions["service_alert"]
155 | end
156 | },
157 | },
158 |
159 | pick_lists: {
160 | saved_searches: lambda do |connection|
161 | get("#{connection['server_url']}/services/workato/alerts").
162 | map { |name| [name,name] }
163 | end
164 | },
165 |
166 | actions: {
167 | send_event_to_splunk: {
168 | input_fields: lambda do
169 | [
170 | {
171 | name: "payload",
172 | optional: false,
173 | },
174 | {
175 | name: "index",
176 | hint: "The name of the repository for Splunk to store the event in."
177 | },
178 | {
179 | name: "source",
180 | hint: "The source value to assign to the event data. For example," \
181 | " if you're sending data from an app you're developing, " \
182 | "you could set this key to the name of the app."
183 | },
184 | {
185 | name: "sourcetype",
186 | hint: "The sourcetype value to assign to the event data. " \
187 | "It identifies the data structure of an event. " \
188 | "A source type determines how Splunk formats the " \
189 | "data during the indexing and also parses the data " \
190 | "during searching process."
191 | },
192 | {
193 | name: "host",
194 | hint: "The host value to assign to the event data. " \
195 | "This is typically the hostname of the " \
196 | "client/server/service from which the data came from."
197 | },
198 | ]
199 | end,
200 |
201 | execute: lambda do |connection, input|
202 | post(
203 | "#{connection['server_url']}/services/workato/events",
204 | payload: input["payload"],
205 | index: input["index"],
206 | source: input["source"],
207 | sourcetype: input["sourcetype"],
208 | host: input["host"]
209 | )
210 | end,
211 |
212 | output_fields: lambda do |_object_definitions|
213 | []
214 | end
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/custom_connectors/basic_auth/clearbit_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Clearbit',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'api_key',
8 | control_type: 'password',
9 | hint: 'Can be found here: https://dashboard.clearbit.com/keys'
10 | }
11 | ],
12 |
13 | authorization: {
14 | type: 'basic_auth',
15 |
16 | # clearbit uses api key only for authentication. treats api key as username and password left blank
17 | # curl -u "{your api_key}:" "https://person.clearbit.com/v1/people/email/eeshansim@gmail.com"
18 | credentials: ->(connection) {
19 | user(connection['api_key'])
20 | password("")
21 | }
22 | }
23 | },
24 |
25 | test: ->(connection) {
26 | get("https://person.clearbit.com/v1/people/email/eeshansim@gmail.com")
27 | },
28 |
29 | object_definitions: {
30 | person: {
31 | fields: ->() {
32 | [
33 | { name: 'id' },
34 | { name: 'name', type: :object, properties: [
35 | { name: 'fullName' },
36 | { name: 'givenName' },
37 | { name: 'familyName' }
38 | ]},
39 | { name: 'email' },
40 | { name: 'gender' },
41 | { name: 'timeZone' },
42 | { name: 'avatar' },
43 | { name: 'geo', type: :object, properties: [
44 | { name: 'city' },
45 | { name: 'stateCode' },
46 | { name: 'countryCode' }
47 | ]},
48 | { name: 'bio' },
49 | { name: 'fuzzy', type: :boolean },
50 | { name: 'site' },
51 | { name: 'employment', type: :object, properties: [
52 | { name: 'domain' },
53 | { name: 'name' },
54 | { name: 'title' },
55 | { name: 'role' },
56 | { name: 'seniority' }
57 | ]},
58 | { name: 'facebook', type: :object, properties: [
59 | { name: 'handle' }
60 | ]},
61 | { name: 'linkedin', type: :object, properties: [
62 | { name: 'handle' }
63 | ]},
64 | { name: 'googleplus', type: :object, properties: [
65 | { name: 'handle' }
66 | ]},
67 | { name: 'twitter', type: :object, properties: [
68 | { name: 'handle' },
69 | { name: 'id' },
70 | { name: 'bio' },
71 | { name: 'followers', type: :integer },
72 | { name: 'following', type: :integer },
73 | { name: 'site' }
74 | ]},
75 | { name: 'github', type: :object, properties: [
76 | { name: 'handle' },
77 | { name: 'company' },
78 | { name: 'blog' },
79 | { name: 'followers', type: :integer },
80 | { name: 'following', type: :integer }
81 | ]},
82 | { name: 'angellist', type: :object, properties: [
83 | { name: 'handle' },
84 | { name: 'bio' },
85 | { name: 'blog' },
86 | { name: 'site' },
87 | { name: 'followers', type: :integer }
88 | ]},
89 | { name: 'aboutme', type: :object, properties: [
90 | { name: 'handle' },
91 | { name: 'bio' }
92 | ]},
93 | { name: 'gravatar', type: :object, properties: [
94 | { name: 'handle' },
95 | { name: 'urls', type: :object, properties: [
96 | { name: 'value', type: :url },
97 | { name: 'title' }
98 | ]}
99 | ]}
100 | ]
101 | }
102 | },
103 | company: {
104 | fields: ->() {
105 | [
106 | { name: 'id' },
107 | { name: 'name' },
108 | { name: 'legalName' },
109 | { name: 'domain' },
110 | { name: 'site', type: :object, properties: [
111 | { name: 'url' },
112 | { name: 'title' },
113 | { name: 'metaDescription' },
114 | { name: 'metaAuthor' },
115 | ]},
116 | { name: 'location' },
117 | { name: 'geo', type: :object, properties: [
118 | { name: 'streetNumber' },
119 | { name: 'streetName' },
120 | { name: 'subPremise' },
121 | { name: 'city' },
122 | { name: 'state' },
123 | { name: 'stateCode' },
124 | { name: 'postalCode' },
125 | { name: 'country' },
126 | { name: 'countryCode' }
127 | ]},
128 | { name: 'timeZone' },
129 | { name: 'description' },
130 | { name: 'foundedDate', type: :date },
131 | { name: 'metrics', type: :object, properties: [
132 | { name: 'raised', type: :integer },
133 | { name: 'employees', type: :integer },
134 | { name: 'googleRank' },
135 | { name: 'annualRevenue', type: :integer }
136 | ]},
137 | { name: 'logo' },
138 | { name: 'facebook', type: :object, properties: [
139 | { name: 'handle' }
140 | ]},
141 | { name: 'linkedin', type: :object, properties: [
142 | { name: 'handle' }
143 | ]},
144 | { name: 'twitter', type: :object, properties: [
145 | { name: 'handle' },
146 | { name: 'id' },
147 | { name: 'bio' },
148 | { name: 'followers', type: :integer },
149 | { name: 'following', type: :integer },
150 | { name: 'site' }
151 | ]},
152 | { name: 'angellist', type: :object, properties: [
153 | { name: 'id' },
154 | { name: 'handle' },
155 | { name: 'description' },
156 | { name: 'blogUrl' },
157 | { name: 'followers', type: :integer },
158 | ]},
159 | { name: 'crunchbase', type: :object, properties: [
160 | { name: 'handle' },
161 | ]},
162 | { name: 'phone' },
163 | { name: 'emailProvider', type: :boolean },
164 | ]
165 | }
166 | }
167 | },
168 |
169 | actions: {
170 |
171 | email_lookup: {
172 | input_fields: ->() {
173 | [
174 | { name: 'email', optional: false }
175 | ]
176 | },
177 | execute: ->(connection, input) {
178 | get("https://person.clearbit.com/v2/combined/find?email=#{input['email']}")
179 | },
180 | output_fields: ->(object_definitions) {
181 | [
182 | { name: 'person', type: :object, properties: object_definitions['person'] },
183 | { name: 'company', type: :object, properties: object_definitions['company'] }
184 | ]
185 | }
186 | },
187 |
188 | company_lookup: {
189 | input_fields: ->() {
190 | [
191 | { name: 'company_name', optional: false }
192 | ]
193 | },
194 | execute: ->(connection, input) {
195 | query = "?page_size=1&limit=1&query=name:#{input['company_name']}"
196 | {
197 | 'companies': get("https://company.clearbit.com/v1/companies/search" + query)['results']
198 | }
199 | },
200 | output_fields: ->(object_definitions) {
201 | [
202 | { name: 'companies', type: :array, of: :object, properties: object_definitions['company'] }
203 | ]
204 | }
205 | }
206 | },
207 |
208 | triggers: {}
209 | }
210 |
--------------------------------------------------------------------------------
/custom_connectors/none/statuspage.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | {
4 | title: 'Statuspage',
5 |
6 | connection: {
7 | fields: [
8 | {
9 | name: 'status_page_url',
10 | label: 'Statuspage URL',
11 | optional: false,
12 | hint: 'For example: https://status.workato.com/'
13 | }
14 | ],
15 |
16 | base_uri: lambda { |connection|
17 | connection['status_page_url']
18 | },
19 |
20 | authorization: {
21 | type: 'no_auth'
22 | }
23 | },
24 |
25 | object_definitions: {
26 | incident_update: {
27 | fields: lambda do |_connection, _config_fields|
28 | [
29 | {
30 | control_type: 'text',
31 | label: 'Status',
32 | type: 'string',
33 | name: 'status'
34 | },
35 | {
36 | control_type: 'text',
37 | label: 'Body',
38 | type: 'string',
39 | name: 'body'
40 | },
41 | {
42 | control_type: 'text',
43 | label: 'Created at',
44 | type: 'date_time',
45 | name: 'created_at'
46 | },
47 | {
48 | control_type: 'text',
49 | label: 'Wants twitter update',
50 | toggle_hint: 'Select from option list',
51 | toggle_field: {
52 | label: 'Wants twitter update',
53 | control_type: 'text',
54 | toggle_hint: 'Use custom value',
55 | type: 'boolean',
56 | name: 'wants_twitter_update'
57 | },
58 | type: 'boolean',
59 | name: 'wants_twitter_update'
60 | },
61 | {
62 | control_type: 'text',
63 | label: 'Twitter updated at',
64 | type: 'date_time',
65 | name: 'twitter_updated_at'
66 | },
67 | {
68 | control_type: 'text',
69 | label: 'Updated at',
70 | type: 'date_time',
71 | name: 'updated_at'
72 | },
73 | {
74 | control_type: 'text',
75 | label: 'Display at',
76 | type: 'date_time',
77 | name: 'display_at'
78 | },
79 | {
80 | control_type: 'text',
81 | label: 'Affected components',
82 | type: 'string',
83 | name: 'affected_components'
84 | },
85 | {
86 | control_type: 'text',
87 | label: 'Custom tweet',
88 | type: 'string',
89 | name: 'custom_tweet'
90 | },
91 | {
92 | control_type: 'text',
93 | label: 'Deliver notifications',
94 | toggle_hint: 'Select from option list',
95 | toggle_field: {
96 | label: 'Deliver notifications',
97 | control_type: 'text',
98 | toggle_hint: 'Use custom value',
99 | type: 'boolean',
100 | name: 'deliver_notifications'
101 | },
102 | type: 'boolean',
103 | name: 'deliver_notifications'
104 | },
105 | {
106 | control_type: 'text',
107 | label: 'Tweet ID',
108 | type: 'string',
109 | name: 'tweet_id'
110 | },
111 | {
112 | control_type: 'text',
113 | label: 'ID',
114 | type: 'string',
115 | name: 'id'
116 | },
117 | {
118 | control_type: 'text',
119 | label: 'Incident ID',
120 | type: 'string',
121 | name: 'incident_id'
122 | }
123 | ]
124 | end
125 | }
126 | },
127 |
128 | test: lambda do |_connection|
129 | get('history.json')
130 | end,
131 |
132 | actions: {
133 | list_incident_updates: {
134 | description: "List incedent updates " \
135 | "in Statuspage",
136 |
137 | execute: lambda do |_connection, _input|
138 | incedents = get('history.json')['months']&.pluck('incidents')
139 | incedent_codes = []
140 | incedents.select { |incedent| incedent&.pluck('code').present? }
141 | .each do |incedent|
142 | incedent_codes.concat(incedent&.pluck('code').presence)
143 | end
144 | incident_updates = []
145 | incedent_codes.each do |incedent|
146 | incident_updates.concat(get("incidents/#{incedent}.json")
147 | .[]('incident_updates'))
148 | end
149 |
150 | { incident_updates: incident_updates }
151 | end,
152 |
153 | output_fields: lambda do |object_definitions|
154 | [{
155 | name: 'incident_updates',
156 | type: 'array',
157 | of: 'object',
158 | properties: object_definitions['incident_update']
159 | }]
160 | end,
161 |
162 | sample_output: lambda do |_connection, _input|
163 | incedent_code = get('history.json')['months']
164 | &.pluck('incidents')
165 | &.select { |incedent| incedent&.pluck('code').present? }
166 | &.[](0)&.pluck('code')&.[](0).presence
167 |
168 | incident_updates = if incedent_code
169 | get("incidents/#{incedent_code}.json")
170 | .[]('incident_updates')
171 | end || []
172 |
173 | { incident_updates: incident_updates }
174 | end
175 | }
176 | },
177 |
178 | triggers: {
179 | new_updated_incident_update: {
180 | title: 'New/updated incident update',
181 | description: "New or updated incident update" \
182 | " in Statuspage",
183 | type: 'paging_desc',
184 |
185 | poll: lambda do |_connection, _input, _last_updated_since|
186 | incedents = get('history.json')['months']&.pluck('incidents')
187 | incedent_codes = []
188 | incedents.select { |incedent| incedent&.pluck('code').present? }
189 | .each do |incedent|
190 | incedent_codes.concat(incedent&.pluck('code').presence)
191 | end
192 | incident_updates = []
193 | incedent_codes.each do |incedent|
194 | incident_updates.concat(get("incidents/#{incedent}.json")
195 | .[]('incident_updates'))
196 | end
197 |
198 | { events: incident_updates, next_page: nil }
199 | end,
200 |
201 | document_id: ->(incident_update) { incident_update['id'] },
202 |
203 | sort_by: ->(incident_update) { incident_update['updated_at'] },
204 |
205 | output_fields: lambda do |object_definitions|
206 | object_definitions['incident_update']
207 | end,
208 |
209 | sample_output: lambda do |_connection, _input|
210 | incedent_code = get('history.json')['months']
211 | &.pluck('incidents')
212 | &.select { |incedent| incedent&.pluck('code').present? }
213 | &.[](0)&.pluck('code')&.[](0).presence
214 |
215 | incident_updates = if incedent_code
216 | get("incidents/#{incedent_code}.json")
217 | .[]('incident_updates')
218 | end || []
219 |
220 | { incident_updates: incident_updates }
221 | end
222 | }
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/formassembly.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "FormAssembly",
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "client_id",
8 | optional: false,
9 | hint: "Get your API key here"
12 | },
13 | {
14 | name: "client_secret",
15 | optional: false,
16 | control_type: :password
17 | },
18 | {
19 | name: "endpoint",
20 | label: "Edition",
21 | control_type: "select",
22 | pick_list: [
23 | %w[FormAssembly\ Developer\ Sandbox https://developer.formassembly.com],
24 | %w[FormAssembly.com https://app.formassembly.com],
25 | %w[FormAssembly\ Enterprise\ Cloud https://base.tfaforms.net],
26 | %w[FormAssembly\ Enterprise\ On-Site https://base/formassembly]
27 | ],
28 | optional: false
29 | },
30 | {
31 | name: "base_url",
32 | ngIf: 'input.endpoint == "https://base/formassembly" ||
33 | input.endpoint == "https://base.tfaforms.net"',
34 | label: "Base URL",
35 | hint: "Use 'workato_formassembly' if that is your instance name or " \
36 | "'workato.formassembly.com' if your server is " \
37 | "'https://workato.formassembly.com/'"
38 | },
39 | ],
40 |
41 | base_uri: lambda do |connection|
42 | connection['endpoint'].gsub("base", connection['base_url'] || '')
43 | end,
44 |
45 | authorization: {
46 | type: 'oauth2',
47 |
48 | authorization_url: ->(connection) {
49 | base_url = connection['endpoint'].gsub("base", connection['base_url'] || '')
50 | "#{base_url}/oauth/login?type=web&client_id=#{connection['client_id']}" +
51 | "&response_type=code"
52 | },
53 |
54 | acquire: lambda do |connection, auth_code, redirect_uri|
55 | base_url = connection['endpoint'].gsub("base", connection['base_url'] || '')
56 | response = post("#{base_url}/oauth/access_token?type=web_server").
57 | payload(
58 | client_id: connection['client_id'] || '',
59 | client_secret: connection['client_secret'] || '',
60 | grant_type: 'authorization_code',
61 | code: auth_code,
62 | redirect_uri: redirect_uri
63 | ).request_format_www_form_urlencoded
64 | [
65 | {
66 | access_token: response['access_token'],
67 | refresh_token: response['refresh_token']
68 | },
69 | nil,
70 | nil
71 | ]
72 | end,
73 |
74 | refresh: lambda do |connection, refresh_token|
75 | base_url = connection['endpoint'].
76 | gsub("base", connection['base_url'] || "")
77 | post("#{base_url}/oauth/access_token?type=web_server").
78 | payload(client_id: connection['client_id'],
79 | client_secret: connection['client_secret'],
80 | grant_type: 'refresh_token',
81 | refresh_token: refresh_token).
82 | request_format_www_form_urlencoded
83 | end,
84 |
85 | refresh_on: [401, 403],
86 |
87 | apply: ->(_connection, access_token) {
88 | params(access_token: access_token)
89 | },
90 | },
91 | },
92 |
93 | object_definitions: {
94 | form: {
95 | fields: lambda do |_connection, _config_fields|
96 | [
97 | { name: "id", type: "integer" },
98 | { name: "version_id", type: "integer" },
99 | { name: "name" },
100 | { name: "category" },
101 | { name: "subcategory" },
102 | { name: "is_template", type: "integer",
103 | hint: "0: Not a template
0: Is a template" },
104 | { name: "display_status", type: "integer",
105 | hint: "0: Archived
2: Active" },
106 | { name: "moderation_status", type: "integer",
107 | hint: "0: Not checked
2: " \
108 | "Reviewed and approved
3: Reviewed and denied" },
109 | { name: "expired" },
110 | { name: "use_ssl" },
111 | { name: "user_id" },
112 | { name: "created", type: "timestamp" },
113 | { name: "modified", type: "timestamp" },
114 | {
115 | name: "Aggregate_metadata",
116 | type: "object",
117 | properties: [
118 | { name: "id", type: "integer" },
119 | { name: "response_count", type: "integer" },
120 | { name: "submitted_count", type: "integer" },
121 | { name: "saved_count", type: "integer" },
122 | { name: "unread_count", type: "integer" },
123 | { name: "dropout_rate" },
124 | { name: "average_completion_time" },
125 | { name: "is_uptodate", type: "boolean" }
126 | ]
127 | }
128 | ]
129 | end
130 | },
131 |
132 | connector: {
133 | fields: lambda do |_connection, _config_fields|
134 | [
135 | { name: "id", type: "integer" },
136 | { name: "form_id", type: "integer" },
137 | { name: "name" },
138 | { name: "status", type: "integer",
139 | hint: "0: Disabled
1: Enabled" },
140 | { name: "event" }
141 | ]
142 | end
143 | }
144 | },
145 |
146 | actions: {
147 | list_forms: {
148 | description: "List forms in " \
149 | " FormAssembly ",
150 |
151 | execute: ->(_connection, _input) {
152 | get("/api_v1/forms/index.json")
153 | },
154 |
155 | output_fields: lambda do |object_definitions|
156 | [
157 | {
158 | name: "Forms",
159 | type: "array",
160 | of: "object",
161 | properties: [
162 | {
163 | name: "Form",
164 | type: "object",
165 | properties: object_definitions['form']
166 | }
167 | ]
168 | }
169 | ]
170 | end,
171 |
172 | sample_output: lambda do |_connection|
173 | get("/api_v1/forms/index.json").
174 | dig("Forms", "Form", 0) || {}
175 | end
176 | },
177 |
178 | list_connectors: {
179 | description: "List connectors in" \
180 | " FormAssembly ",
181 |
182 | config_fields: [
183 | {
184 | name: "form",
185 | control_type: "select",
186 | pick_list: "forms",
187 | optional: false
188 | }
189 | ],
190 |
191 | execute: ->(_connection, input) {
192 | get("/api_v1/connectors/index/#{input['form']}.json")
193 | },
194 |
195 | output_fields: lambda do |object_definitions|
196 | [
197 | {
198 | name: "Connectors",
199 | type: "array",
200 | of: "object",
201 | properties: [
202 | {
203 | name: "Connector",
204 | type: "object",
205 | properties: object_definitions['connector']
206 | }
207 | ]
208 | }
209 | ]
210 | end,
211 |
212 | sample_output: lambda do |_connection, input|
213 | get("/api_v1/connectors/index/#{input['form']}.json").
214 | dig("Connectors", "Connector", 0) || {}
215 | end
216 | },
217 |
218 | get_connector_by_id: {
219 | description: "Get connector details " \
220 | "in FormAssembly ",
221 |
222 | input_fields: lambda do
223 | [
224 | { name: "connector_id", optional: false }
225 | ]
226 | end,
227 |
228 | execute: ->(_connection, input) {
229 | get("/api_v1/connectors/view/#{input['connector_id']}.json")
230 | },
231 |
232 | output_fields: lambda do |object_definitions|
233 | [
234 | {
235 | name: "Form",
236 | type: "object",
237 | properties: [
238 | { name: "id", type: "integer" },
239 | { name: "version_id", type: "integer" },
240 | { name: "name" }
241 | ]
242 | },
243 | {
244 | name: "Connector",
245 | type: "object",
246 | properties: object_definitions['connector']
247 | }
248 | ]
249 | end,
250 |
251 | sample_output: lambda do |_connection, input|
252 | get("/api_v1/connectors/view/#{input['connector_id']}.json").
253 | dig("Connectors", "Connector", 0) || {}
254 | end
255 | }
256 | },
257 |
258 | pick_lists: {
259 | forms: lambda do |_connection|
260 | get("/api_v1/forms/index.json")['Forms'].
261 | map do |form|
262 | form_data = form['Form']
263 | [form_data['name'], form_data['id']]
264 | end
265 | end
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/neto_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Neto',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'domain',
8 | control_type: 'subdomain',
9 | url: '.neto.com.au',
10 | optional: false
11 | },
12 | {
13 | name: 'api_key',
14 | control_type: 'password', optional: false
15 | }
16 | ],
17 |
18 | authorization: {
19 | type: 'custom_auth',
20 |
21 | credentials: ->(connection) {
22 | headers('NETOAPI_KEY': connection['api_key'])
23 | }
24 | }
25 | },
26 |
27 | object_definitions: {
28 |
29 | customer: {
30 |
31 | fields: ->() {
32 | [
33 | { name: 'ID' },
34 | { name: 'EmailAddress', control_type: 'email' },
35 | { name: 'Username' },
36 | { name: 'DateUpdated', type: :date_time },
37 | { name: 'DateAdded', type: :date_time }
38 | ]
39 | }
40 | },
41 |
42 | order: {
43 |
44 | fields: ->() {
45 | [
46 | { name: "OrderID" },
47 | { name: "ShippingOption" },
48 | { name: "DeliveryInstruction" },
49 | { name: "Username" },
50 | { name: "Email", control_type: 'email' },
51 | { name: "ShipAddress" },
52 | { name: "BillAddress" },
53 | { name: "PurchaseOrderNumber" },
54 | { name: "CustomerRef1" },
55 | { name: "CustomerRef2" },
56 | { name: "CustomerRef3" },
57 | { name: "CustomerRef4" },
58 | { name: "SalesChannel" },
59 | { name: "GrandTotal" },
60 | { name: "TaxInclusive" },
61 | { name: "OrderTax" },
62 | { name: "SurchargeTotal" },
63 | { name: "SurchargeTaxable" },
64 | { name: "ProductSubtotal" },
65 | { name: "ShippingTotal" },
66 | { name: "ShippingTax" },
67 | { name: "ClientIPAddress" },
68 | { name: "CouponCode" },
69 | { name: "CouponDiscount" },
70 | { name: "ShippingDiscount" },
71 | { name: "OrderType" },
72 | { name: "OrderStatus" },
73 | { name: "OrderPayment", type: :array, of: :object, parse_output: :item_array_wrap, properties: [
74 | { name: "OrderPaymentId" },
75 | { name: "OrderPaymentAmount" },
76 | { name: "PaymentType" }
77 | ]},
78 | { name: "DateUpdated", type: :date_time },
79 | { name: "DatePlaced", type: :date_time },
80 | { name: "DateRequired", type: :date_time },
81 | { name: "DateInvoiced", type: :date_time },
82 | { name: "DatePaid", type: :date_time },
83 | { name: "DateCompleted", type: :date_time },
84 | { name: "OrderLine", type: :array, of: :object, parse_output: :item_array_wrap, properties: [
85 | { name: "ProductName" },
86 | { name: "ItemNotes" },
87 | { name: "PickQuantity" },
88 | { name: "BackorderQuantity" },
89 | { name: "UnitPrice" },
90 | { name: "Tax" },
91 | { name: "TaxCode" },
92 | { name: "WarehouseID", type: :integer },
93 | { name: "WarehouseName" },
94 | { name: "WarehouseReference" },
95 | { name: "Quantity", type: :integer },
96 | { name: "PercentDiscount" },
97 | { name: "ProductDiscount" },
98 | { name: "CouponDiscount" },
99 | { name: "CostPrice" },
100 | { name: "ShippingMethod" },
101 | { name: "ShippingTracking" },
102 | { name: "Weight" },
103 | { name: "Cubic" },
104 | { name: "Extra" },
105 | { name: "eBay", type: :object, properties: [
106 | { name: "eBayUsername" },
107 | { name: "eBayStoreName" },
108 | { name: "eBayTransactionID" },
109 | { name: "eBayAuctionID" },
110 | { name: "ListingType" },
111 | { name: "DateCreated", type: :date_time },
112 | { name: "DatePaid", type: :date_time },
113 | ]}
114 | ]},
115 | { name: "ShippingSignature" },
116 | { name: "RealtimeConfirmation" },
117 | { name: "InternalOrderNotes" },
118 | { name: "CompleteStatus" },
119 | { name: "UserGroup" },
120 | { name: "StickyNotes", type: :array, of: :object, parse_output: :item_array_wrap, properties: [
121 | { name: "Title" },
122 | { name: "Description" }
123 | ]}
124 | ]
125 | }
126 | }
127 | },
128 |
129 | test: ->(connection) {
130 | post("https://#{connection['domain']}.neto.com.au/do/WS/NetoAPI").headers('NETOAPI_ACTION': 'GetCustomer')
131 | },
132 |
133 | triggers: {
134 |
135 | new_updated_customer: {
136 | description: 'New or Updated customer in Neto',
137 |
138 | input_fields: ->() {
139 | [
140 | {
141 | name: 'since',
142 | type: :timestamp,
143 | hint: 'Defaults to customer updated after the recipe is first started'
144 | }
145 | ]
146 | },
147 |
148 | poll: ->(connection, input, page) {
149 | page ||= 0
150 | limit = 50
151 | updated_since = input['since'] || Time.now
152 |
153 | payload = {
154 | "filter" => {
155 | "DateUpdatedFrom" => (updated_since).utc.strftime("%F %T"),
156 | "Page" => page,
157 | "Limit" => limit,
158 | "OutputSelector" => ["Username", "ID", "EmailAddress", "DateUpdated", "DateAdded"]
159 | },
160 | }
161 |
162 | customers = post("https://#{connection['domain']}.neto.com.au/do/WS/NetoAPI", payload).
163 | headers('NETOAPI_ACTION': 'GetCustomer')['Customer']
164 |
165 | {
166 | events: customers,
167 | next_poll: (page + 1),
168 | can_poll_more: customers.length == limit
169 | }
170 | },
171 |
172 | dedup: ->(customer) {
173 | customer['ID'] + "@" + customer['DateUpdated']
174 | },
175 |
176 | output_fields: ->(object_definitions) {
177 | object_definitions['customer']
178 | }
179 | },
180 |
181 | new_updated_order: {
182 | description: 'New or Updated order in Neto',
183 |
184 | input_fields: ->() {
185 | [
186 | {
187 | name: 'since',
188 | type: :timestamp,
189 | hint: 'Defaults to customer updated after the recipe is first started'
190 | }
191 | ]
192 | },
193 |
194 | poll: ->(connection, input, page) {
195 | page ||= 0
196 | limit = 50
197 | updated_since = input['since'] || Time.now
198 |
199 | payload = {
200 | "filter" => {
201 | "DateUpdatedFrom" => (updated_since).utc.strftime("%F %T"),
202 | "Page" => page,
203 | "Limit" => limit,
204 | "OutputSelector" => [
205 | "ID","ShippingOption","DeliveryInstruction","Username",
206 | "Email","ShipAddress","BillAddress","PurchaseOrderNumber",
207 | "CustomerRef1","CustomerRef2","CustomerRef3","CustomerRef4",
208 | "SalesChannel","GrandTotal","TaxInclusive","OrderTax",
209 | "SurchargeTotal","SurchargeTaxable","ProductSubtotal",
210 | "ShippingTotal","ShippingTax","ClientIPAddress","CouponCode",
211 | "CouponDiscount","ShippingDiscount","OrderType","OrderStatus",
212 | "OrderPayment","OrderPayment.PaymentType","OrderPayment.DatePaid",
213 | "DateUpdated","DatePlaced","DateRequired","DateInvoiced",
214 | "DatePaid","DateCompleted","OrderLine","OrderLine.ProductName",
215 | "OrderLine.ItemNotes","OrderLine.PickQuantity","OrderLine.BackorderQuantity",
216 | "OrderLine.UnitPrice","OrderLine.Tax","OrderLine.TaxCode",
217 | "OrderLine.WarehouseID","OrderLine.WarehouseName",
218 | "OrderLine.WarehouseReference","OrderLine.Quantity","OrderLine.PercentDiscount",
219 | "OrderLine.ProductDiscount","OrderLine.CouponDiscount","OrderLine.CostPrice",
220 | "OrderLine.ShippingMethod","OrderLine.ShippingTracking","OrderLine.Weight",
221 | "OrderLine.Cubic","OrderLine.Extra","ShippingSignature","RealtimeConfirmation",
222 | "InternalOrderNotes","OrderLine.eBay.eBayUsername","OrderLine.eBay.eBayStoreName",
223 | "OrderLine.eBay.eBayTransactionID","OrderLine.eBay.eBayAuctionID",
224 | "OrderLine.eBay.ListingType","OrderLine.eBay.DateCreated","CompleteStatus",
225 | "OrderLine.eBay.DatePaid","UserGroup","StickyNotes"
226 | ]
227 | },
228 | }
229 |
230 | orders = post("https://#{connection['domain']}.neto.com.au/do/WS/NetoAPI", payload).
231 | headers('NETOAPI_ACTION': 'GetOrder')['Order']
232 |
233 | {
234 | events: orders,
235 | next_poll: (page + 1),
236 | can_poll_more: orders.length == limit
237 | }
238 | },
239 |
240 | dedup: ->(order) {
241 | order['ID'] + "@" + order['DateUpdated']
242 | },
243 |
244 | output_fields: ->(object_definitions) {
245 | object_definitions['order']
246 | }
247 | }
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/custom_connectors/custom_auth/domo.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Domo',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'client_id',
8 | optional: false,
9 | hint: 'To create client ID click " \
11 | 'here'
12 | },
13 | {
14 | name: 'client_secret',
15 | control_type: 'password',
16 | optional: false,
17 | hint: 'To create client secret click " \
19 | 'here'
20 | }
21 | ],
22 | authorization: {
23 | type: 'custom_auth',
24 |
25 | acquire: lambda do |connection|
26 | {
27 | access_token: get('https://api.domo.com/oauth/token?' \
28 | 'grant_type=client_credentials&scope=data')
29 | .user(connection['client_id'])
30 | .password(connection['client_secret'])['access_token']
31 | }
32 | end,
33 |
34 | refresh_on: [401],
35 |
36 | apply: lambda do |connection|
37 | headers(Authorization: "bearer #{connection['access_token']}")
38 | end
39 | },
40 |
41 | base_uri: lambda do |_connection|
42 | 'https://api.domo.com'
43 | end
44 | },
45 |
46 | test: lambda do |_connection|
47 | get('/v1/datasets?limit=1')
48 | end,
49 |
50 | object_definitions: {
51 | dataset: {
52 | fields: lambda do |_connection, config_fields|
53 | column_headers =
54 | if config_fields.blank?
55 | []
56 | else
57 | get("/v1/datasets/#{config_fields['dataset_id']}")
58 | .dig('schema', 'columns')
59 | end&.map do |col|
60 | {
61 | name: col['name'],
62 | sticky: true,
63 | type: case col['type']
64 | when 'DATE'
65 | 'date'
66 | when 'DATETIME'
67 | 'date_time'
68 | when 'LONG'
69 | 'integer'
70 | when 'DECIMAL'
71 | 'number'
72 | else
73 | 'string'
74 | end
75 | }
76 | end
77 | {
78 | name: 'data',
79 | type: 'array',
80 | of: 'object',
81 | properties: column_headers,
82 | optional: false,
83 | hint: 'Map the Data source list and Data fields.'
84 | }
85 | end
86 | },
87 |
88 | dataset_definition: {
89 | fields: lambda do |_connection, _config_fields|
90 | [
91 | { name: 'id' },
92 | { name: 'name', optional: false },
93 | { name: 'description', optional: false },
94 | {
95 | name: 'schema',
96 | optional: false,
97 | type: 'object', properties: [
98 | { name: 'columns',
99 | optional: false,
100 | type: 'array', of: 'object',
101 | properties: [
102 | { name: 'name', optional: false },
103 | { name: 'type',
104 | optional: false,
105 | control_type: 'select',
106 | pick_list: [
107 | %w[String STRING],
108 | %w[Decimal DECIMAL],
109 | %w[Long LONG],
110 | %w[Double DOUBLE],
111 | %w[Date DATE],
112 | %w[Date\ time DATETIME]
113 | ],
114 | toggle_hint: 'Select from list',
115 | toggle_field: {
116 | name: 'type', type: 'string',
117 | control_type: 'text',
118 | label: 'Type',
119 | toggle_hint: 'Enter custom value',
120 | hint: 'Allowed values are: STRING, DECIMAL, LONG,' \
121 | 'DOUBLE, DATE, DATETIME'
122 | } }
123 | ] }
124 | ]
125 | },
126 | { name: 'rows', type: 'integer' },
127 | { name: 'columns', type: 'integer' },
128 | { name: 'owner', type: 'object', properties: [
129 | { name: 'id' },
130 | { name: 'name' }
131 | ] },
132 | { name: 'createdAt', type: 'date_time' },
133 | { name: 'updatedAt', type: 'date_time' }
134 | ]
135 | end
136 | }
137 | },
138 |
139 | actions: {
140 | import_data: {
141 | description: 'Import data into ' \
142 | 'dataset in ' \
143 | 'Domo',
144 | help: 'Import data action replaces the data in the dataset',
145 |
146 | config_fields: [
147 | {
148 | name: 'dataset_id',
149 | control_type: 'select',
150 | pick_list: 'datasets',
151 | label: 'Dataset name',
152 | optional: false,
153 | help: 'Select the Dataset to import data.',
154 | toggle_hint: 'Select from list',
155 | toggle_field:
156 | { name: 'dataset_id',
157 | label: 'Dataset ID',
158 | type: :string,
159 | control_type: 'text',
160 | optional: false,
161 | toggle_hint: 'Use custom value' }
162 | }
163 | ],
164 |
165 | input_fields: lambda do |object_definitions|
166 | object_definitions['dataset']
167 | end,
168 |
169 | execute: lambda do |_connection, input|
170 | payload = input['data'].map do |row|
171 | row.map do |_key, val|
172 | val
173 | end.join(',')
174 | end.join("\n")
175 | {
176 | status: put("/v1/datasets/#{input['dataset_id']}/data")
177 | .headers("Content-Type": 'text/csv')
178 | .request_body(payload)
179 | .request_format_www_form_urlencoded
180 | .after_error_response(/40*/) do |code, _body, _header, message|
181 | error("#{code}: #{message}")
182 | end&.presence || 'success'
183 | }
184 | end,
185 |
186 | output_fields: lambda do |_object_definitions|
187 | [{ name: 'status' }]
188 | end,
189 |
190 | sample_output: lambda do |_connection, _input|
191 | { status: 'success' }
192 | end
193 | },
194 |
195 | export_data: {
196 | description: 'Export data from ' \
197 | 'dataset in ' \
198 | 'Domo',
199 | help: 'Known Limitation: Data types will be exported as they are' \
200 | ' currently stored in the dataset. In addition, the only supported' \
201 | ' export type is CSV.',
202 |
203 | config_fields: [
204 | {
205 | name: 'dataset_id',
206 | control_type: 'select',
207 | label: 'Dataset name',
208 | pick_list: 'datasets',
209 | optional: false,
210 | toggle_hint: 'Select from list',
211 | toggle_field:
212 | { name: 'dataset_id',
213 | label: 'Dataset ID',
214 | type: :string,
215 | control_type: 'text',
216 | optional: false,
217 | toggle_hint: 'Use custom value' }
218 | }
219 | ],
220 |
221 | input_fields: lambda do |_object_definitions|
222 | [
223 | {
224 | name: 'includeHeader',
225 | type: 'boolean',
226 | label: 'Include header',
227 | control_type: 'checkbox',
228 | sticky: true,
229 | toggle_hint: 'Select from list',
230 | toggle_field:
231 | { name: 'includeHeader',
232 | label: 'Include header',
233 | type: :string,
234 | control_type: 'text',
235 | optional: true,
236 | toggle_hint: 'Use custom value',
237 | hint: 'Allowed values are: true, false' }
238 | },
239 | {
240 | name: 'fileName',
241 | hint: 'The filename of the exported csv',
242 | sticky: true
243 | }
244 | ]
245 | end,
246 |
247 | execute: lambda do |_connection, input|
248 | {
249 | data: get("/v1/datasets/#{input.delete('dataset_id')}/data", input)
250 | .headers("Content-Type": 'text/csv',
251 | 'Accept': 'text/csv')
252 | .request_format_www_form_urlencoded
253 | .response_format_raw
254 | }
255 | end,
256 |
257 | output_fields: lambda do |_object_definitions|
258 | [{ name: 'data' }]
259 | end,
260 |
261 | sample_output: lambda do |_connection, _input|
262 | { data: 'name,id sam,123 xavier,124' }
263 | end
264 | },
265 |
266 | create_dataset: {
267 | description: 'Create dataset ' \
268 | 'in Domo',
269 | help: "Click " \
271 | 'here for supported data types',
272 |
273 | input_fields: lambda do |object_definitions|
274 | object_definitions['dataset_definition']
275 | .ignored('id', 'rows', 'columns', 'owner', 'createdAt', 'updatedAt')
276 | end,
277 |
278 | execute: lambda do |_connection, input|
279 | post('/v1/datasets/', input)
280 | .after_error_response(/40*/) do |code, _body, _header, message|
281 | error("#{code}: #{message}")
282 | end
283 | end,
284 |
285 | output_fields: lambda do |object_definitions|
286 | object_definitions['dataset_definition']
287 | end,
288 |
289 | sample_output: lambda do |_connection, _input|
290 | dataset_id = get('/v1/datasets?limit=1')&.dig(0, 'id')
291 | dataset_id.present? ? get("/v1/datasets/#{dataset_id}") : {}
292 | end
293 | }
294 | },
295 |
296 | pick_lists: {
297 | datasets: lambda do |_connection|
298 | get('/v1/datasets')&.pluck('name', 'id')
299 | end
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/custom_connectors/oauth2/ephesoft_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'Ephesoft Semantik for Invoices',
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: 'client_id',
8 | optional: false
9 | },
10 | {
11 | name: 'client_secret',
12 | optional: false,
13 | control_type: 'password'
14 | }
15 | ],
16 | authorization: {
17 | type: "oauth2",
18 | authorization_url: lambda do |connection|
19 | params = {
20 | client_id: connection["client_id"],
21 | response_type: "code",
22 | redirect_uri: "https://www.workato.com/oauth/callback",
23 | scope: "admin"
24 | }.to_param
25 |
26 | "https://api.us.ephesoft.io/v1/auth/oauth2/authorize?" + params
27 | end,
28 |
29 | acquire: lambda do |connection, auth_code|
30 | response = post("https://api.us.ephesoft.io/v1/auth/oauth2/token").
31 | payload(
32 | code: auth_code,
33 | grant_type: "authorization_code",
34 | client_id: connection["client_id"],
35 | client_secret: connection["client_secret"],
36 | redirect_uri: "https://www.workato.com/oauth/callback"
37 | ).
38 | request_format_www_form_urlencoded
39 | [
40 | {
41 | access_token: response["access_token"],
42 | refresh_token: response["refresh_token"]
43 | }
44 | ]
45 | end,
46 |
47 | refresh_on: [401, 403],
48 |
49 | refresh: lambda do |connection, refresh_token|
50 | response = post("https://api.us.ephesoft.io/v1/auth/oauth2/refresh").
51 | payload(
52 | grant_type: "refresh_token",
53 | refresh_token: refresh_token,
54 | client_id: connection["client_id"],
55 | client_secret: connection["client_secret"],
56 | redirect_uri: "https://www.workato.com/oauth/callback"
57 | ).
58 | request_format_www_form_urlencoded
59 | [
60 | { # Tokens hash
61 | access_token: response["access_token"],
62 | refresh_token: response["refresh_token"]
63 | }
64 | ]
65 | end,
66 |
67 | apply: lambda do |connection, access_token|
68 | headers("Authorization": "Bearer #{access_token}")
69 | end
70 | }
71 | },
72 | test:
73 | lambda do |connection|
74 | get("https://api.us.ephesoft.io/v1/settings/integrations/configurations")
75 | end,
76 | actions: {
77 | # Future action code here
78 | },
79 | triggers: {
80 | new_message: {
81 | title: 'New complete Semantik invoice',
82 | description: 'Triggers when a Semantik invoice is completed',
83 | webhook_subscribe: lambda do |webhook_url, connection, input, recipe_id|
84 | payload = {
85 | "AmountDue": "$AmountDue",
86 | "DocumentId": "$DocumentId",
87 | "DueDate": "$DueDate",
88 | "FileName": "$FileName",
89 | "InvoiceDate": "$InvoiceDate",
90 | "InvoiceNumber": "$InvoiceNumber",
91 | "OrderDate": "$OrderDate",
92 | "PdfUrl": "$PdfUrl",
93 | "PONumber": "$PONumber",
94 | "ShipDate": "$ShipDate",
95 | "ShipFreight": "$ShipFreight",
96 | "SubTotal": "$SubTotal",
97 | "TableUrl": "$TableUrl",
98 | "TaxAmount": "$TaxAmount",
99 | "TaxId": "$TaxId",
100 | "TaxRate": "$TaxRate",
101 | "TenantId": "$TenantId",
102 | "Terms": "$Terms",
103 | "TotalAmount": "$TotalAmount",
104 | "Vendor": {
105 | "VendorAddress": {
106 | "VendorStreetAddress": "$Vendor:StreetAddress",
107 | "VendorPOBox": "$Vendor:POBox",
108 | "VendorLocality": "$Vendor:Locality",
109 | "VendorRegion": "$Vendor:Region",
110 | "VendorPostalCode": "$Vendor:PostalCode",
111 | "VedorCountry": "$Vendor:Country"
112 | },
113 | "VendorCustom1": "$Vendor:Custom1",
114 | "VendorCustom2": "$Vendor:Custom2",
115 | "VendorCustom3": "$Vendor:Custom3",
116 | "VendorCustom4": "$Vendor:Custom4",
117 | "VendorCustom5": "$Vendor:Custom5",
118 | "VendorCustomerID": "$Vendor:CustomerID",
119 | "VendorIBAN": "$Vendor:IBAN",
120 | "VendorID": "$Vendor:VendorID",
121 | "VendorMatched": "$Vendor:Matched",
122 | "VendorName": "$Vendor:Name",
123 | "VendorStatus": "$Vendor:Status",
124 | "VendorSWIFT": "$Vendor:SWIFT",
125 | "VendorTelephone": "$Vendor:Telephone"
126 | }
127 | }
128 | post("https://api.us.ephesoft.io/v1/settings/integrations/configurations",
129 | integrationName: "Workato Recipe #{recipe_id}",
130 | integrationType: "webhook",
131 | enabled: true,
132 | settings: {
133 | targetUrl: webhook_url,
134 | encoding: "application/json",
135 | payload: payload.to_json.to_s
136 | }
137 | )
138 | end,
139 |
140 | webhook_notification: lambda do |input, payload|
141 | payload
142 | end,
143 |
144 | webhook_unsubscribe: lambda do |webhook|
145 |
146 | # Get the webhook ID to be removed
147 | json_output = webhook['data']
148 | configurationId = (json_output.scan(/configurationId"=>"([\S\s]*)", "integrationId/).dig(0))[0]
149 |
150 | # Delete the webhook
151 | delete("https://api.us.ephesoft.io/v1/settings/integrations/configurations/#{configurationId}")
152 | end,
153 |
154 | output_fields: lambda do |object_definitions|
155 | object_definitions["webhook_output"]
156 | end,
157 | sample_output: lambda do ||
158 | {
159 | AmountDue: '3693.80',
160 | DocumentId: '00000000-0000-0000-0000-000000000000',
161 | DueDate: '2020-04-15',
162 | FileName: 'Kord-Invoice9291873611.pdf',
163 | InvoiceDate: '2020-03-29',
164 | InvoiceNumber: '9291873611',
165 | OrderDate: '2020-03-29',
166 | PdfUrl: 'https://semantik.us.ephesoft.io/assets/samples/webhookTestInvoice.pdf',
167 | PONumber: '8762943181',
168 | ShipDate: '2020-04-10',
169 | ShipFreight: '123.45',
170 | SubTotal: '3358',
171 | TableUrl: 'https://semantik.us.ephesoft.io/assets/samples/webhookTestInvoiceTable.json',
172 | TaxAmount: '335.80',
173 | TaxId: '012-34-56789',
174 | TaxRate: '10',
175 | TenantId: '555e4d7e-0115-4ec4-adac-892367844222',
176 | Terms: 'Net 30 days',
177 | TotalAmount: '3693.8',
178 | Vendor: {
179 | VendorAddress: {
180 | VendorStreetAddress: '2775 S. 900 W.',
181 | VendorPOBox: '123',
182 | VendorLocality: 'Salt Lake City',
183 | VendorRegion: 'UT',
184 | VendorPostalCode: '84128-3227',
185 | VendorCountry: 'US'
186 | },
187 | VendorCustom1: 'Custom1',
188 | VendorCustom2: 'Custom2',
189 | VendorCustom3: 'Custom3',
190 | VendorCustom4: 'Custom4',
191 | VendorCustom5: 'Custom5',
192 | VendorIBAN: 'aa5d5efa-fcaf-4d2b-a118-a093f184a876',
193 | VendorCustomerID: '95bba4ab-1897-4e9d-aff1-f42ae7e5cb86',
194 | VendorID: '1',
195 | VendorMatched: 'true',
196 | VendorName: 'Kord Industries',
197 | VendorStatus: 'active',
198 | VendorSWIFT: '1b0f74e1-ce62-4d1d-9153-f07e88bc0a29',
199 | VendorTelephone: '513-101-4074'
200 | }
201 | }
202 | end,
203 | dedup: lambda do |messages|
204 | Time.now.to_f
205 | end
206 | }
207 | },
208 | object_definitions: {
209 | webhook_output: {
210 | fields: lambda do
211 | [
212 | { name: "AmountDue", type: "string"},
213 | { name: "DocumentId", type: "string"},
214 | { name: "DueDate", type: "string"},
215 | { name: "FileName", type: "string"},
216 | { name: "InvoiceDate", type: "string"},
217 | { name: "InvoiceNumber", type: "string"},
218 | { name: "OrderDate", type: "string"},
219 | { name: "PdfUrl", type: "string"},
220 | { name: "PONumber", type: "string"},
221 | { name: "ShipDate", type: "string"},
222 | { name: "ShipFreight", type: "string"},
223 | { name: "SubTotal", type: "string"},
224 | { name: "TableUrl", type: "string"},
225 | { name: "TaxAmount", type: "string"},
226 | { name: "TaxId", type: "string"},
227 | { name: "TaxRate", type: "string"},
228 | { name: "TenantId", type: "string"},
229 | { name: "Terms", type: "string"},
230 | { name: "TotalAmount", type: "string"},
231 | {
232 | name: "Vendor",
233 | type: :object,
234 | properties: [
235 | {
236 | name: "VendorAddress",
237 | type: :object,
238 | properties: [
239 | { name: "VendorStreetAddress", type: "string"},
240 | { name: "VendorPOBox", type: "string"},
241 | { name: "VendorLocality", type: "string"},
242 | { name: "VendorRegion", type: "string"},
243 | { name: "VendorPostalCode", type: "string"},
244 | { name: "VendorCountry", type: "string"}
245 | ]
246 | },
247 | { name: "VendorCustom1", type: "string"},
248 | { name: "VendorCustom2", type: "string"},
249 | { name: "VendorCustom3", type: "string"},
250 | { name: "VendorCustom4", type: "string"},
251 | { name: "VendorCustom5", type: "string"},
252 | { name: "VendorIBAN", type: "string"},
253 | { name: "VendorCustomerID", type: "string"},
254 | { name: "VendorID", type: "string"},
255 | { name: "VendorMatched", type: "string"},
256 | { name: "VendorName", type: "string"},
257 | { name: "VendorStatus", type: "string"},
258 | { name: "VendorSWIFT", type: "string"},
259 | { name: "VendorTelephone", type: "string"}
260 | ]
261 | }
262 | ]
263 | end
264 | }
265 | },
266 | picklists: {},
267 | methods: {},
268 | }
--------------------------------------------------------------------------------
/custom_connectors/none/rssfeedreader.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: 'RSS Feed Reader 2.0',
3 |
4 | methods: {
5 | parse_xml_to_hash: lambda do |xml_obj|
6 | xml_obj['xml']&.
7 | inject({}) do |hash, (key, value)|
8 | if value.is_a?(Array)
9 | hash.merge(if (array_fields = xml_obj['array_fields'])&.include?(key)
10 | {
11 | key => value.map do |inner_hash|
12 | call('parse_xml_to_hash',
13 | 'xml' => inner_hash,
14 | 'array_fields' => array_fields)
15 | end
16 | }
17 | else
18 | {
19 | key => call('parse_xml_to_hash',
20 | 'xml' => value[0],
21 | 'array_fields' => array_fields)
22 | }
23 | end)
24 | else
25 | value
26 | end
27 | end&.presence
28 | end,
29 |
30 | format_api_output_field_names: lambda do |input|
31 | if input.is_a?(Array)
32 | input.map do |array_value|
33 | call('format_api_output_field_names', array_value)
34 | end
35 | elsif input.is_a?(Hash)
36 | input.map do |key, value|
37 | value = call('format_api_output_field_names', value)
38 | { key.gsub(/[!@#$%^&*(),.?":{}|<>]/, '_') => value }
39 | end.inject(:merge)
40 | else
41 | input
42 | end
43 | end,
44 |
45 | format_schema_field_names: lambda do |input|
46 | input.map do |field|
47 | if field[:properties].present?
48 | field[:properties] = call('format_schema_field_names',
49 | field[:properties])
50 | elsif field['properties'].present?
51 | field['properties'] = call('format_schema_field_names',
52 | field['properties'])
53 | end
54 | if field[:name].present?
55 | field[:name] = field[:name].gsub(/[!@#$%^&*(),.?":{}|<>]/, '_')
56 | elsif field['name'].present?
57 | field['name'] = field['name'].gsub(/[!@#$%^&*(),.?":{}|<>]/, '_')
58 | end
59 | field
60 | end
61 | end
62 | },
63 |
64 | connection: { authorization: { type: 'no_auth' } },
65 |
66 | test: ->(_connection) { true },
67 |
68 | object_definitions: {
69 | item: {
70 | fields: lambda do |_connection, _config_fields|
71 | item_fields = [
72 | { name: 'author' },
73 | { name: 'category' },
74 | { name: 'comments' },
75 | { name: 'description' },
76 | {
77 | type: 'object',
78 | name: 'enclosure',
79 | properties: [
80 | { name: '@length', label: 'Length' },
81 | { name: '@type', label: 'Type' },
82 | { name: '@url', label: 'URL' }
83 | ]
84 | },
85 | { name: 'guid', label: 'GUID' },
86 | { name: 'link' },
87 | {
88 | control_type: 'text',
89 | render_input: 'date_time_conversion',
90 | parse_output: 'date_time_conversion',
91 | type: 'date_time',
92 | name: 'pubDate'
93 | },
94 | { name: 'source' },
95 | { name: 'title' }
96 | ]
97 |
98 | call('format_schema_field_names', item_fields.compact)
99 | end
100 | },
101 |
102 | channel: {
103 | fields: lambda do |_connection, _config_fields|
104 | channel_fields = [
105 | { name: 'title' },
106 | { name: 'link' },
107 | { name: 'description' },
108 | { name: 'language' },
109 | { name: 'copyright' },
110 | { name: 'managingEditor' },
111 | {
112 | control_type: 'text',
113 | render_input: 'date_time_conversion',
114 | parse_output: 'date_time_conversion',
115 | type: 'date_time',
116 | name: 'pubDate'
117 | },
118 | {
119 | control_type: 'text',
120 | render_input: 'date_time_conversion',
121 | parse_output: 'date_time_conversion',
122 | type: 'date_time',
123 | name: 'lastBuildDate'
124 | },
125 | { name: 'category' },
126 | { name: 'generator' },
127 | { name: 'docs' },
128 | {
129 | type: 'object',
130 | name: 'cloud',
131 | properties: [
132 | { name: '@domain', label: 'Domain' },
133 | { name: '@path', label: 'Path' },
134 | { name: '@url', label: 'URL' },
135 | { name: '@port', label: 'Port' },
136 | { name: '@protocol', label: 'Protocol' },
137 | { name: '@registerProcedure', label: 'Register procedure' }
138 | ]
139 | },
140 | {
141 | control_type: 'text',
142 | label: 'Time to live',
143 | type: 'string',
144 | name: 'ttl'
145 | },
146 | {
147 | name: 'image',
148 | type: 'object',
149 | properties: [
150 | { name: 'link' },
151 | { name: 'title' },
152 | { name: 'url' },
153 | { name: 'description' },
154 | { name: 'height' },
155 | { name: 'width' }
156 | ]
157 | },
158 | { name: 'language' },
159 | { name: 'rating' },
160 | {
161 | type: 'object',
162 | name: 'textInput',
163 | properties: [
164 | { name: 'description' },
165 | { name: 'link' },
166 | { name: 'name' },
167 | { name: 'title' }
168 | ]
169 | },
170 | { name: 'webMaster' },
171 | {
172 | name: 'item',
173 | type: 'array',
174 | of: 'object',
175 | properties: [
176 | { name: 'author' },
177 | { name: 'category' },
178 | { name: 'comments' },
179 | { name: 'description' },
180 | {
181 | type: 'object',
182 | name: 'enclosure',
183 | properties: [
184 | { name: '@length', label: 'Length' },
185 | { name: '@type', label: 'Type' },
186 | { name: '@url', label: 'URL' }
187 | ]
188 | },
189 | { name: 'guid', label: 'GUID' },
190 | { name: 'link' },
191 | {
192 | control_type: 'text',
193 | render_input: 'date_time_conversion',
194 | parse_output: 'date_time_conversion',
195 | type: 'date_time',
196 | name: 'pubDate'
197 | },
198 | { name: 'source' },
199 | { name: 'title' }
200 | ]
201 | }
202 | ]
203 |
204 | call('format_schema_field_names', channel_fields.compact)
205 | end
206 | }
207 | },
208 |
209 | actions: {
210 | get_feed: {
211 | description: "Get items from feed in " \
212 | "RSS Feed Reader 2.0",
213 |
214 | input_fields: lambda do |_object_definitions|
215 | [{
216 | name: 'feed_url',
217 | label: 'Feed URL',
218 | type: 'string',
219 | control_type: 'url',
220 | optional: false,
221 | hint: 'E.g. https://status.workato.com/history.rss'
222 | }]
223 | end,
224 |
225 | execute: lambda do |_connection, input|
226 | {
227 | channel: call('format_api_output_field_names',
228 | call('parse_xml_to_hash',
229 | 'xml' => get(input['feed_url'])
230 | .response_format_xml
231 | .dig('rss', 0, 'channel', 0),
232 | 'array_fields' => ['item'])&.compact)
233 | }
234 | end,
235 |
236 | output_fields: lambda do |object_definitions|
237 | [{
238 | name: 'channel',
239 | type: 'object',
240 | properties: object_definitions['channel']
241 | }]
242 | end,
243 |
244 | sample_output: lambda do |_connection, input|
245 | {
246 | channel: [call('format_api_output_field_names',
247 | call('parse_xml_to_hash',
248 | 'xml' => get(input['feed_url'])
249 | .response_format_xml
250 | .dig('rss', 0, 'channel', 0),
251 | 'array_fields' => ['item'])&.compact)] || []
252 | }
253 | end
254 | }
255 | },
256 |
257 | triggers: {
258 | new_item_in_feed: {
259 | description: "New item in" \
260 | "RSS Feed Reader 2.0",
261 | type: 'paging_desc',
262 |
263 | input_fields: lambda do |_object_definitions|
264 | [{
265 | name: 'feed_url',
266 | label: 'Feed URL',
267 | type: 'string',
268 | control_type: 'url',
269 | optional: false,
270 | hint: 'E.g. https://status.workato.com/history.rss'
271 | }]
272 | end,
273 |
274 | poll: lambda do |_connection, input, _page|
275 | items = call('format_api_output_field_names',
276 | call('parse_xml_to_hash',
277 | 'xml' => get(input['feed_url'])
278 | .response_format_xml
279 | .dig('rss', 0, 'channel', 0),
280 | 'array_fields' => ['item'])&.compact)&.[]('item')
281 |
282 | { events: items || [], next_page: nil }
283 | end,
284 |
285 | document_id: lambda do |item|
286 | "#{item['guid']}@#{item['title']}@#{item['description']}"
287 | end,
288 |
289 | sort_by: ->(item) { item['pubDate'] },
290 |
291 | output_fields: ->(object_definitions) { object_definitions['item'] },
292 |
293 | sample_output: lambda do |_connection, input|
294 | call('format_api_output_field_names',
295 | call('parse_xml_to_hash',
296 | 'xml' => get(input['feed_url'])
297 | .response_format_xml
298 | .dig('rss', 0, 'channel', 0),
299 | 'array_fields' => ['item'])&.dig('item', 0)) || {}
300 | end
301 | }
302 | }
303 | }
304 |
--------------------------------------------------------------------------------
/custom_connectors/api_key_auth/aftership_connector.rb:
--------------------------------------------------------------------------------
1 | {
2 | title: "Aftership",
3 |
4 | connection: {
5 | fields: [
6 | {
7 | name: "api_key",
8 | control_type: "password",
9 | optional: false,
10 | label: "API key",
11 | hint: "Get your API key here"
13 | }
14 | ],
15 |
16 | authorization: {
17 | type: "api_key",
18 |
19 | credentials: lambda do |connection|
20 | headers("aftership-api-key": connection["api_key"])
21 | end
22 | },
23 |
24 | base_uri: lambda do
25 | "https://api.aftership.com"
26 | end
27 | },
28 |
29 | object_definitions: {
30 | tracking_input: {
31 | fields: lambda do |_connection|
32 | [
33 | { name: "tracking_number", type: :string, optional: false,
34 | hint: "Duplicate tracking numbers, or tracking number with " \
35 | "invalid tracking number format will not be accepted." },
36 | { name: "slug", type: :string,
37 | hint: "If you do not specify a slug, Aftership will " \
38 | "automatically detect the courier based on the tracking number " \
39 | "format and your selected couriers." },
40 | { name: "tracking_postal_code", type: :string,
41 | hint: "The postal code of receiver's address. " \
42 | "Required by some couriers, such as deutsch-post" },
43 | { name: "tracking_ship_date", type: :string,
44 | hint: "Shipping date in YYYYMMDD format. Required by some " \
45 | "couriers, such as deutsch-post" },
46 | { name: "tracking_account_number", type: :string,
47 | hint: "Account number of the shipper for a specific courier. " \
48 | "Required by some couriers, such as dynamic-logistics" },
49 | { name: "tracking_key", type: :string,
50 | hint: "Key of the shipment for a specific courier. " \
51 | "Required by some couriers, such assic-teliway" },
52 | { name: "tracking_origin_country", type: :string,
53 | hint: "Origin Country of the shipment for a specific courier. " \
54 | "Required by some couriers, such as dhl" },
55 | { name: "tracking_destination_country", type: :string,
56 | hint: "Destination Country of the shipment for a specific courier" \
57 | ". Required by some couriers, such as postnl-3s" },
58 | { name: "tracking_state", type: :string,
59 | hint: "Located state of the shipment for a specific courier. " \
60 | "Required by some couriers, such asstar-track-courier" },
61 | { name: "android", type: :string,
62 | hint: "Google cloud message comma separated registration IDs to " \
63 | "receive the push notifications" },
64 | { name: "ios", type: :string,
65 | hint: "Apple iOS comma separated device IDs to receive the " \
66 | "push notifications" },
67 | { name: "emails", type: :string, label: "E-mails",
68 | hint: "Comma separated email address(es) to receive email " \
69 | "notifications" },
70 | { name: "smses", type: :string, label: "SMSes",
71 | hint: "Comma separated phone number(s) to receive SMS " \
72 | "notifications. Note: Enter + and area code before number." },
73 | { name: "title", type: :string,
74 | hint: "Title of the tracking. Default value astracking_number" },
75 | { name: "customer_name", type: :string },
76 | { name: "origin_country_iso3", type: :string,
77 | label: "Origin Country ISO3",
78 | hint: "Enter ISO Alpha-3 " \
80 | "country code to specify the origin of the shipment" },
81 | { name: "destination_country_iso3", type: :string,
82 | label: "Destination Country ISO3",
83 | hint: "Enter ISO Alpha-3 " \
85 | "country code to specify the destination of the shipment" \
86 | "If you use postal service to send international shipments, " \
87 | "AfterShip will automatically get tracking results at " \
88 | "destination courier as well." },
89 | { name: "order_id", type: :string, label: "Order ID" },
90 | { name: "order_id_path", type: :string, label: "Order ID Path" },
91 | { name: "note", type: :string },
92 | { name: "language", type: :string,
93 | hint: "Enter ISO 639-1 Language Code to specify the " \
96 | "store, customer or order language" }
97 | ]
98 | end
99 | },
100 |
101 | tracking_output: {
102 | fields: lambda do |_connection|
103 | [
104 | { name: "id", type: :string, control_type: :text },
105 | { name: "created_at", type: :date_time, control_type: :date_time },
106 | { name: "updated_at", type: :date_time, control_type: :date_time },
107 | { name: "tracking_number", type: :string, control_type: :text },
108 | { name: "tracking_account_number", type: :string,
109 | control_type: :text },
110 | { name: "tracking_postal_code", type: :string, control_type: :text },
111 | { name: "tracking_ship_date", type: :date_time,
112 | control_type: :date_time },
113 | { name: "tracking_origin_country", type: :string },
114 | { name: "tracking_destination_country", type: :string },
115 | { name: "tracking_state", type: :string },
116 | { name: "tracking_key", type: :string },
117 | { name: "slug", type: :string, control_type: :text },
118 | { name: "active", type: :boolean },
119 | { name: "android", type: :string },
120 | { name: "custom_fields", type: :object },
121 | { name: "customer_name", type: :string, control_type: :text },
122 | { name: "delivery_time", type: :string },
123 | { name: "destination_country_iso3", type: :string,
124 | control_type: :text },
125 | { name: "courier_destination_country_iso3", type: :string,
126 | control_type: :text },
127 | { name: "emails", type: :array, of: :string },
128 | { name: "expected_delivery", type: :date_time,
129 | control_type: :date_time },
130 | { name: "ios", type: :string },
131 | { name: "note", type: :string, control_type: :text },
132 | { name: "order_id", type: :string, control_type: :text },
133 | { name: "order_id_path", type: :string, control_type: :url },
134 | { name: "origin_country_iso3", type: :string, control_type: :text },
135 | { name: "unique_token", type: :string, control_type: :password },
136 | { name: "shipment_package_count", type: :integer,
137 | control_type: :number },
138 | { name: "shipment_type", type: :string, control_type: :text },
139 | { name: "shipment_weight", type: :string, control_type: :text },
140 | { name: "shipment_weight_unit", type: :string, control_type: :text },
141 | { name: "signed_by", type: :string, control_type: :text },
142 | { name: "smses", type: :array, of: :string },
143 | { name: "source", type: :string, control_type: :text },
144 | { name: "tag", type: :string, control_type: :text },
145 | { name: "title", type: :string, control_type: :text },
146 | { name: "tracked_count", type: :integer, control_type: :number },
147 | { name: "last_mile_tracking_supported", type: :boolean,
148 | control_type: :checkbox },
149 | { name: "language", type: :string, control_type: :text },
150 | { name: "return_to_sender", type: :boolean, control_type: :checkbox },
151 | { name: "checkpoints", type: :array, of: :object, properties: [
152 | { name: "slug", type: :string, control_type: :text },
153 | { name: "location", type: :string, control_type: :text },
154 | { name: "city", type: :string, control_type: :text },
155 | { name: "created_at", type: :date_time,
156 | control_type: :date_time },
157 | { name: "country_name", type: :string, control_type: :text },
158 | { name: "message", type: :string, control_type: :text },
159 | { name: "country_iso3", type: :string, control_type: :text },
160 | { name: "tag", type: :string, control_type: :text },
161 | { name: "checkpoint_time", type: :date_time,
162 | control_type: :date_time },
163 | { name: "coordinates", type: :array, of: :integer,
164 | control_type: :number },
165 | { name: "state", type: :string, control_type: :text },
166 | { name: "zip", type: :string, control_type: :text }
167 | ] }
168 | ]
169 | end
170 | }
171 | },
172 |
173 | test: lambda do |_connection|
174 | get("/v4/trackings")
175 | end,
176 |
177 | actions: {
178 | create_tracking: {
179 | description: "Create a tracking in " \
180 | "Aftership",
181 |
182 | input_fields: lambda do |object_definitions|
183 | object_definitions["tracking_input"].required("tracking_number")
184 | end,
185 |
186 | execute: lambda do |_connection, input|
187 | post("/v4/trackings", tracking: input).dig("data", "tracking")
188 | end,
189 |
190 | output_fields: lambda do |object_definitions|
191 | object_definitions["tracking_output"]
192 | end,
193 |
194 | sample_output: lambda do |_connection|
195 | get("/v4/trackings", limit: 1).dig("data", "trackings", 0)
196 | end
197 | },
198 |
199 | search_tracking: {
200 | description: "Search tracking in " \
201 | "Aftership",
202 |
203 | input_fields: lambda do |object_definitions|
204 | object_definitions["tracking_input"].
205 | only("tracking_number").
206 | required("tracking_number")
207 | end,
208 |
209 | execute: lambda do |_connection, input|
210 | {
211 | trackings: get("/v4/trackings", keyword: input["tracking_number"]).
212 | []("data") || []
213 | }
214 | end,
215 |
216 | output_fields: lambda do |object_definitions|
217 | object_definitions["tracking_output"]
218 | end,
219 |
220 | sample_output: lambda do |_connection|
221 | get("/v4/trackings", limit: 1).dig("data", "trackings", 0)
222 | end
223 | }
224 | }
225 | }
226 |
--------------------------------------------------------------------------------