Compare commits

..

9 Commits

Author SHA1 Message Date
Rıdvan Akca
daa38ab846 feat(bigin-by-zoho-crm): add create company action 2024-02-22 14:16:48 +03:00
Rıdvan Akca
00e18cf42d feat(bigin-by-zoho-crm): add create event action 2024-02-21 18:14:22 +03:00
Rıdvan Akca
b3d2a1167c feat(bigin-by-zoho-crm): add create contact action 2024-02-21 15:27:35 +03:00
Rıdvan Akca
43c34fcb7b feat(bigin-by-zoho-crm): add new products trigger 2024-02-20 17:31:30 +03:00
Rıdvan Akca
c98f24338f feat(bigin-by-zoho-crm): add new tasks trigger 2024-02-20 17:26:56 +03:00
Rıdvan Akca
d0748bb7e2 feat(bigin-by-zoho-crm): add new calls trigger 2024-02-20 16:23:51 +03:00
Rıdvan Akca
81e8e4963c feat(bigin-by-zoho-crm): add new companies trigger 2024-02-20 16:22:21 +03:00
Rıdvan Akca
282b2374a2 feat(bigin-by-zoho-crm): add new contacts trigger 2024-02-20 16:19:47 +03:00
Rıdvan Akca
b7e38f9d1c feat(bigin-by-zoho-crm): add bigin by zoho crm integration 2024-02-20 14:21:23 +03:00
63 changed files with 1617 additions and 3555 deletions

View File

@@ -0,0 +1,161 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create company',
key: 'createCompany',
description: 'Creates a new company.',
arguments: [
{
label: 'Company Owner',
key: 'companyOwnerId',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listContactOwners',
},
],
},
},
{
label: 'Company Name',
key: 'companyName',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Phone',
key: 'phone',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Website',
key: 'website',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Tags',
key: 'tags',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Tag',
key: 'tag',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'Description',
key: 'description',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Billing Street',
key: 'billingStreet',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Billing City',
key: 'billingCity',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Billing State',
key: 'billingState',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Billing Country',
key: 'billingCountry',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Billing Code',
key: 'billingCode',
type: 'string',
required: false,
description: '',
variables: true,
},
],
async run($) {
const {
contactOwnerId,
companyName,
phone,
website,
tags,
description,
billingStreet,
billingCity,
billingState,
billingCountry,
billingCode,
} = $.step.parameters;
const allTags = tags.map((tag) => ({
name: tag.tag,
}));
const body = {
data: [
{
Owner: {
id: contactOwnerId,
},
Account_Name: companyName,
Phone: phone,
Website: website,
Tag: allTags,
Description: description,
Billing_Street: billingStreet,
Billing_City: billingCity,
Billing_State: billingState,
Billing_Country: billingCountry,
Billing_Code: billingCode,
},
],
};
const { data } = await $.http.post(`/bigin/v2/Accounts`, body);
$.setActionItem({
raw: data[0],
});
},
});

View File

@@ -0,0 +1,217 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create contact',
key: 'createContact',
description: 'Creates a new contact.',
arguments: [
{
label: 'Contact Owner',
key: 'contactOwnerId',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listContactOwners',
},
],
},
},
{
label: 'First Name',
key: 'firstName',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Last Name',
key: 'lastName',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Title',
key: 'title',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Email',
key: 'email',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Company ID',
key: 'companyId',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listCompanies',
},
],
},
},
{
label: 'Mobile',
key: 'mobile',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Email Opt Out',
key: 'emailOptOut',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'True', value: true },
{ label: 'False', value: false },
],
},
{
label: 'Tags',
key: 'tags',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Tag',
key: 'tag',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'Description',
key: 'description',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Mailing Street',
key: 'mailingStreet',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Mailing City',
key: 'mailingCity',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Mailing State',
key: 'mailingState',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Mailing Country',
key: 'mailingCountry',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Mailing Zip',
key: 'mailingZip',
type: 'string',
required: false,
description: '',
variables: true,
},
],
async run($) {
const {
contactOwnerId,
firstName,
lastName,
title,
email,
companyId,
mobile,
emailOptOut,
tags,
description,
mailingStreet,
mailingCity,
mailingState,
mailingCountry,
mailingZip,
} = $.step.parameters;
const allTags = tags.map((tag) => ({
name: tag.tag,
}));
const body = {
data: [
{
Owner: {
id: contactOwnerId,
},
Account_Name: {
id: companyId,
},
First_Name: firstName,
Last_Name: lastName,
Title: title,
Email: email,
Mobile: mobile,
Email_Opt_Out: emailOptOut,
Tag: allTags,
Description: description,
Mailing_Street: mailingStreet,
Mailing_City: mailingCity,
Mailing_State: mailingState,
Mailing_Country: mailingCountry,
Mailing_Zip: mailingZip,
},
],
};
const { data } = await $.http.post(`/bigin/v2/Contacts`, body);
$.setActionItem({
raw: data[0],
});
},
});

View File

@@ -0,0 +1,293 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create event',
key: 'createEvent',
description: 'Creates a new event.',
arguments: [
{
label: 'Host',
key: 'hostId',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listContactOwners',
},
],
},
},
{
label: 'Title',
key: 'title',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'From',
key: 'from',
type: 'string',
required: true,
description: 'The date format is ISO8601 (yyyy-mm-ddTHH:mm:ssZ).',
variables: true,
},
{
label: 'To',
key: 'to',
type: 'string',
required: true,
description: 'The date format is ISO8601 (yyyy-mm-ddTHH:mm:ssZ).',
variables: true,
},
{
label: 'All Day',
key: 'allDay',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'True', value: true },
{ label: 'False', value: false },
],
},
{
label: 'Frequency (Recurring Activity)',
key: 'frequency',
type: 'dropdown',
required: false,
description:
'Specifies the frequency of event recurrence. The options include DAILY, WEEKLY, MONTHLY, or YEARLY.',
variables: true,
options: [
{ label: 'Daily Events', value: 'DAILY' },
{ label: 'Weekly Events', value: 'WEEKLY' },
{ label: 'Monthly Events', value: 'MONTHLY' },
],
},
{
label: 'Interval (Recurring Activity)',
key: 'interval',
type: 'string',
required: false,
description:
'Specifies the time difference between individual events. The INTERVAL can be anywhere from 1 to 99. For instance, with a WEEKLY event set at an INTERVAL of 2, there will be a two-week gap between each occurrence.',
variables: true,
},
{
label: 'By Month Day (Recurring Activity)',
key: 'byMonthDay',
type: 'string',
required: false,
description:
'This specifies the date within the month when the event recurs. The BYMONTHDAY value can be any number from 1 to 31. This rule applies exclusively to events that repeat monthly or yearly.',
variables: true,
},
{
label: 'By Week (Recurring Activity)',
key: 'byWeek',
type: 'dropdown',
required: false,
description:
'Only relevant for events that occur on a monthly or yearly basis.',
variables: true,
options: [
{ label: 'First week of the month', value: '1' },
{ label: 'Second week of the month', value: '2' },
{ label: 'Third week of the month', value: '3' },
{ label: 'Fourth week of the month', value: '4' },
{ label: 'Last week of the month', value: '-1' },
],
},
{
label: 'By Day (Recurring Activity)',
key: 'byDay',
type: 'string',
required: false,
description:
'This signifies the weekday when the event recurs. The options include SU, MO, TU, WE, TH, FR, or SA. This rule applies to events that repeat daily, weekly, monthly, and yearly (should not be combined with INTERVAL).',
variables: true,
},
{
label: 'Count (Recurring Activity)',
key: 'count',
type: 'string',
required: false,
description:
'Specifies the number of events you wish to generate. The count value range from 1 to 99.',
variables: true,
},
{
label: 'Until (Recurring Activity)',
key: 'until',
type: 'string',
required: false,
description:
'Specifies the concluding date for the event recurrence. Please input the date in the YYYY-MM-DD format.',
variables: true,
},
{
label: 'Reminder',
key: 'reminder',
type: 'dropdown',
required: false,
description:
'Provide the reminder list to notify or prompt participants prior to the event.',
variables: true,
options: [
{ label: '5 min', value: '5 minutes' },
{ label: '10 min', value: '10 minutes' },
{ label: '15 min', value: '15 minutes' },
{ label: '1 hrs', value: '1 hours' },
{ label: '2 hrs', value: '2 hours' },
{ label: '1 days', value: '1 days' },
{ label: '2 days', value: '2 days' },
{ label: '1 weeks', value: '1 weeks' },
],
},
{
label: 'Location',
key: 'location',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Related Module',
key: 'relatedModule',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{ label: 'Companies', value: 'Accounts' },
{ label: 'Contacts', value: 'Contacts' },
{ label: 'Deals', value: 'Deals' },
],
},
{
label: 'Participants',
key: 'participants',
type: 'dynamic',
required: false,
description: 'Email Address of participants.',
fields: [
{
label: 'Participant',
key: 'participant',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'Description',
key: 'description',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Tags',
key: 'tags',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Tag',
key: 'tag',
type: 'string',
required: false,
variables: true,
},
],
},
],
async run($) {
const {
hostId,
title,
from,
to,
allDay,
frequency,
interval,
byMonthDay,
byDay,
byWeek,
count,
until,
reminder,
location,
relatedModule,
participants,
description,
tags,
} = $.step.parameters;
const allTags = tags.map((tag) => ({
name: tag.tag,
}));
const allParticipants = participants.map((participant) => ({
type: 'email',
participant: participant.participant,
}));
const [unit, period] = reminder.split(' ');
let rrule = `FREQ=${frequency};INTERVAL=${interval};`;
if (count) rrule += `COUNT=${count};`;
if (byMonthDay) rrule += `BYMONTHDAY=${byMonthDay};`;
if (byDay) rrule += `BYDAY=${byDay};`;
if (byWeek) rrule += `BYSETPOS=${byWeek};`;
if (until) rrule += `UNTIL=${until};`;
const body = {
data: [
{
Owner: {
id: hostId,
},
Event_Title: title,
Start_DateTime: from,
End_DateTime: to,
All_day: allDay,
$se_module: relatedModule,
Recurring_Activity: {
RRULE: rrule,
},
Remind_At: [
{
unit: Number(unit),
period,
},
],
Venue: location,
Participants: allParticipants,
Description: description,
Tag: allTags,
},
],
};
const { data } = await $.http.post(`/bigin/v2/Events`, body);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -0,0 +1,5 @@
import createCompany from './create-company/index.js';
import createContact from './create-contact/index.js';
import createEvent from './create-event/index.js';
export default [createCompany, createContact, createEvent];

View File

@@ -0,0 +1,32 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" id="b" data-name="Layer 2" width="327.714" height="120" viewBox="0 0 327.714 120">
<defs>
<style>
.d {
fill: #039649;
}
</style>
</defs>
<g id="c" data-name="Layer 1">
<g>
<path class="d" d="m52.39,120c-1.801,0-3.6-.6-5.101-1.5-2.1-1.5-3.6-4.2-3.6-6.9v-24.6L1.09,12.901C-.41,9.9-.41,6.601,1.391,4.2,2.891,1.5,5.89,0,8.89,0h78c2.999,0,5.698,1.5,7.199,4.2,1.801,2.702,1.801,6.3.301,9.002l-5.101,9h10.201c2.999,0,5.698,1.5,7.199,4.2,1.801,2.7,1.801,6.3.301,9l-29.701,51.3v18.599c0,3.899-2.399,6.9-5.999,8.099l-16.2,6.3c-.6.301-1.799.301-2.7.301M8.89,8.4q-.301.301-.301.602l42.301,73.798c1.199,2.1,1.199,3.299,1.199,4.501v23.998s.301.301.6,0l16.2-6.3h.6v-17.999c0-1.199,0-3.299,1.201-4.8l29.4-50.999c0-.301,0-.6-.301-.6l-53.699-.301,14.399,24.901,10.201-17.7c1.199-2.1,3.6-2.7,5.7-1.5,2.1,1.199,2.7,3.6,1.498,5.7l-11.998,20.699c-2.702,4.2-8.701,3.901-11.102.301l-17.4-30.9c-1.199-1.799-1.199-4.2,0-6.3,1.201-2.1,3.301-3.6,5.7-3.6h36.6l7.499-12.899s0-.301-.299-.602H8.89Z"/>
<g>
<path d="m181.725,48.737c0,3.089-.54,5.684-1.618,7.788-1.081,2.104-2.548,3.79-4.407,5.062-1.858,1.27-4.016,2.179-6.476,2.726-2.459.547-5.069.819-7.828.819h-24.591V6.521h23.034c2.676,0,5.198.24,7.561.718,2.364.479,4.427,1.311,6.189,2.5,1.762,1.189,3.149,2.787,4.16,4.795,1.011,2.008,1.517,4.53,1.517,7.562,0,3.17-.786,5.813-2.357,7.93-1.57,2.119-3.913,3.628-7.028,4.53,4.017.819,6.995,2.371,8.935,4.652s2.91,5.458,2.91,9.529Zm-33.813-17.624h10.533c1.612,0,3.033-.136,4.263-.41,1.23-.272,2.268-.738,3.115-1.393.846-.656,1.489-1.55,1.927-2.684.436-1.134.655-2.562.655-4.284,0-1.612-.267-2.923-.799-3.934-.532-1.01-1.25-1.809-2.152-2.398-.902-.587-1.967-.99-3.197-1.209s-2.542-.328-3.934-.328h-10.411v16.64Zm0,26.067h12.09c1.64,0,3.115-.169,4.427-.512,1.311-.342,2.424-.894,3.341-1.66.915-.764,1.612-1.748,2.091-2.951.478-1.202.716-2.663.716-4.385,0-1.802-.294-3.285-.881-4.447-.588-1.161-1.394-2.083-2.419-2.766s-2.227-1.154-3.606-1.414c-1.381-.26-2.863-.39-4.447-.39h-11.312v18.525Z"/>
<path d="m202.257,9.555c0,.847-.151,1.633-.451,2.356-.3.724-.716,1.34-1.25,1.844-.532.507-1.167.902-1.905,1.189s-1.53.431-2.377.431c-.819,0-1.598-.144-2.336-.431s-1.388-.69-1.947-1.209c-.56-.519-.998-1.133-1.311-1.844-.315-.711-.471-1.489-.471-2.336s.156-1.626.471-2.336c.314-.711.744-1.325,1.291-1.845.546-.519,1.187-.922,1.925-1.209s1.53-.431,2.377-.431c.821,0,1.598.144,2.336.431s1.373.69,1.907,1.209c.532.52.955,1.134,1.27,1.845.314.71.471,1.489.471,2.336Zm-.778,12.705v42.871h-10.246V22.261h10.246Z"/>
<path d="m254.186,61.935c0,3.361-.587,6.236-1.762,8.627-1.174,2.391-2.78,4.352-4.815,5.882-2.036,1.529-4.407,2.65-7.111,3.361-2.706.71-5.589,1.065-8.648,1.065-2.023,0-4.037-.157-6.045-.471-2.009-.314-3.908-.861-5.697-1.64-1.79-.778-3.395-1.837-4.816-3.175-1.421-1.34-2.555-3.021-3.402-5.042l8.074-3.525c.519,1.202,1.202,2.193,2.049,2.971.847.779,1.797,1.408,2.848,1.885,1.051.479,2.172.814,3.361,1.005s2.398.287,3.628.287c1.885,0,3.572-.232,5.062-.696,1.489-.466,2.752-1.169,3.79-2.111,1.039-.943,1.838-2.132,2.399-3.566.559-1.434.839-3.107.839-5.02v-6.393c-.71,1.229-1.592,2.336-2.643,3.319-1.053.983-2.207,1.824-3.464,2.52s-2.582,1.237-3.976,1.62c-1.393.383-2.814.574-4.263.574-3.033,0-5.737-.56-8.114-1.681-2.377-1.119-4.379-2.636-6.005-4.55-1.625-1.912-2.862-4.139-3.709-6.68-.847-2.542-1.27-5.233-1.27-8.074,0-2.814.451-5.491,1.353-8.033.901-2.542,2.192-4.775,3.873-6.702,1.68-1.927,3.709-3.464,6.086-4.611,2.376-1.147,5.054-1.721,8.033-1.721,2.923,0,5.621.594,8.094,1.782,2.472,1.189,4.473,3.082,6.004,5.677v-6.557h10.246v39.674Zm-33.198-19.017c0,1.666.252,3.265.758,4.795s1.237,2.876,2.193,4.037c.957,1.162,2.137,2.084,3.545,2.767s3.013,1.025,4.816,1.025c2.021,0,3.784-.355,5.287-1.066,1.502-.711,2.746-1.673,3.729-2.89.985-1.215,1.722-2.643,2.213-4.283.492-1.64.738-3.374.738-5.206,0-1.802-.239-3.49-.716-5.062-.479-1.57-1.203-2.93-2.173-4.077s-2.179-2.056-3.626-2.726c-1.449-.67-3.157-1.005-5.123-1.005-2.049,0-3.812.363-5.287,1.086-1.476.724-2.684,1.709-3.628,2.951-.943,1.243-1.633,2.699-2.069,4.365-.438,1.666-.656,3.429-.656,5.287Z"/>
<path d="m277.096,9.555c0,.847-.151,1.633-.451,2.356-.3.724-.716,1.34-1.25,1.844-.532.507-1.167.902-1.905,1.189s-1.53.431-2.377.431c-.819,0-1.598-.144-2.336-.431s-1.388-.69-1.947-1.209c-.56-.519-.998-1.133-1.311-1.844-.315-.711-.471-1.489-.471-2.336s.156-1.626.471-2.336c.314-.711.744-1.325,1.291-1.845.546-.519,1.187-.922,1.925-1.209s1.53-.431,2.377-.431c.821,0,1.598.144,2.336.431s1.373.69,1.907,1.209c.532.52.955,1.134,1.27,1.845.314.71.471,1.489.471,2.336Zm-.778,12.705v42.871h-10.246V22.261h10.246Z"/>
<path d="m308.451,29.801c-1.585,0-2.999.24-4.243.718-1.243.479-2.288,1.162-3.135,2.049-.847.889-1.496,1.961-1.947,3.217-.451,1.258-.676,2.651-.676,4.181v25.165h-10.246V22.261h10.246v6.803c.683-1.338,1.537-2.492,2.562-3.462,1.025-.97,2.165-1.769,3.422-2.399,1.257-.627,2.59-1.091,3.997-1.393,1.406-.3,2.82-.451,4.241-.451,2.623,0,4.884.431,6.783,1.291s3.464,2.049,4.694,3.565c1.229,1.517,2.131,3.307,2.704,5.37s.861,4.311.861,6.742v26.805h-10.328v-25.822c0-3.005-.711-5.341-2.132-7.008-1.421-1.666-3.688-2.5-6.803-2.5Z"/>
</g>
<g>
<path d="m152.871,102.12c0,1.138-.168,2.221-.507,3.25-.337,1.028-.828,1.935-1.471,2.72s-1.436,1.41-2.379,1.874-2.021.696-3.234.696c-.579,0-1.155-.061-1.723-.183-.569-.121-1.107-.306-1.613-.553-.505-.247-.974-.561-1.407-.941s-.801-.822-1.107-1.328v2.72h-2.625v-24.446h2.625v10.689c.273-.464.632-.882,1.076-1.257.442-.374.93-.696,1.463-.964.531-.27,1.082-.477,1.652-.626.569-.146,1.122-.22,1.66-.22,1.244,0,2.34.227,3.289.679.95.454,1.743,1.068,2.38,1.843s1.117,1.685,1.44,2.728c.321,1.044.482,2.151.482,3.321Zm-13.536.126c0,.917.123,1.756.371,2.515.249.759.614,1.415,1.1,1.968.485.553,1.079.984,1.787,1.289.706.306,1.517.459,2.435.459.991,0,1.813-.178,2.467-.53.653-.354,1.178-.828,1.573-1.424.395-.595.674-1.283.838-2.063.163-.78.245-1.603.245-2.467,0-.801-.104-1.576-.308-2.325-.206-.748-.52-1.415-.941-1.999-.422-.586-.958-1.055-1.605-1.407-.648-.354-1.415-.53-2.3-.53-.981,0-1.827.174-2.538.521-.711.349-1.3.818-1.764,1.409-.464.59-.806,1.28-1.028,2.071s-.332,1.629-.332,2.514Z"/>
<path d="m169.949,93.834l-9.141,22.297h-2.656l3.131-7.464-6.388-14.833h2.814l4.965,11.86,4.586-11.86h2.689Z"/>
<path d="m194.11,108.034v2.34h-16.414v-1.139l13.189-19.228h-12.05v-2.246h15.465v1.139l-12.84,19.134h12.65Z"/>
<path d="m213.229,102.215c0,1.202-.206,2.319-.617,3.352-.411,1.034-.986,1.927-1.723,2.681-.739.753-1.611,1.344-2.618,1.77-1.007.428-2.106.641-3.296.641-1.256,0-2.388-.222-3.4-.665s-1.874-1.053-2.585-1.834-1.257-1.697-1.637-2.752c-.38-1.053-.57-2.192-.57-3.416,0-1.191.201-2.3.601-3.329.4-1.028.964-1.92,1.692-2.68.727-.759,1.594-1.354,2.601-1.787s2.116-.648,3.329-.648c1.254,0,2.391.22,3.408.663s1.881,1.055,2.593,1.835,1.26,1.697,1.644,2.751c.385,1.055.578,2.192.578,3.416Zm-13.726.031c0,.886.117,1.708.349,2.467s.579,1.418,1.043,1.977c.464.558,1.038.995,1.723,1.311.685.317,1.481.476,2.388.476.938,0,1.753-.175,2.443-.522.691-.349,1.263-.816,1.717-1.407.452-.591.79-1.275,1.012-2.056.22-.78.332-1.602.332-2.466,0-.844-.117-1.646-.349-2.404-.232-.759-.579-1.429-1.043-2.008s-1.038-1.038-1.723-1.376c-.685-.337-1.481-.505-2.388-.505-.971,0-1.802.174-2.498.521-.696.349-1.265.82-1.708,1.416-.443.595-.77,1.288-.981,2.078-.21.792-.316,1.624-.316,2.498Z"/>
<path d="m224.423,95.827c-.696,0-1.323.105-1.881.316s-1.034.512-1.423.902c-.391.39-.691.864-.902,1.423s-.316,1.186-.316,1.881v10.026h-2.625v-24.446h2.625v10.531c.253-.516.564-.956.933-1.32s.777-.663,1.226-.902c.447-.237.933-.411,1.454-.521.522-.111,1.057-.166,1.605-.166,1.033,0,1.937.171,2.712.513.775.343,1.423.818,1.945,1.424.522.605.915,1.326,1.178,2.157.263.833.395,1.745.395,2.735v9.994h-2.625v-10.184c0-1.423-.36-2.506-1.083-3.25-.722-.742-1.795-1.114-3.217-1.114Z"/>
<path d="m251.685,102.215c0,1.202-.206,2.319-.617,3.352-.411,1.034-.986,1.927-1.723,2.681-.739.753-1.611,1.344-2.618,1.77-1.007.428-2.106.641-3.296.641-1.256,0-2.388-.222-3.4-.665s-1.874-1.053-2.585-1.834-1.257-1.697-1.637-2.752c-.38-1.053-.57-2.192-.57-3.416,0-1.191.201-2.3.601-3.329.4-1.028.964-1.92,1.692-2.68.727-.759,1.594-1.354,2.601-1.787s2.116-.648,3.329-.648c1.254,0,2.391.22,3.408.663s1.881,1.055,2.593,1.835,1.26,1.697,1.644,2.751c.385,1.055.578,2.192.578,3.416Zm-13.726.031c0,.886.117,1.708.349,2.467s.579,1.418,1.043,1.977c.464.558,1.038.995,1.723,1.311.685.317,1.481.476,2.388.476.938,0,1.753-.175,2.443-.522.691-.349,1.263-.816,1.717-1.407.452-.591.79-1.275,1.012-2.056.22-.78.332-1.602.332-2.466,0-.844-.117-1.646-.349-2.404-.232-.759-.579-1.429-1.043-2.008s-1.038-1.038-1.723-1.376c-.685-.337-1.481-.505-2.388-.505-.971,0-1.802.174-2.498.521-.696.349-1.265.82-1.708,1.416-.443.595-.77,1.288-.981,2.078-.21.792-.316,1.624-.316,2.498Z"/>
<path d="m281.097,103.923c-.38.959-.884,1.85-1.511,2.672-.627.823-1.346,1.534-2.157,2.135-.812.601-1.703,1.073-2.673,1.415-.969.342-1.976.514-3.02.514-1.76,0-3.312-.295-4.656-.886-1.345-.59-2.472-1.407-3.385-2.45-.912-1.044-1.603-2.279-2.072-3.709-.469-1.428-.704-2.98-.704-4.657,0-1.033.114-2.037.341-3.013.227-.974.553-1.889.98-2.743.428-.854.95-1.637,1.565-2.348.617-.711,1.318-1.32,2.104-1.827.785-.505,1.652-.901,2.601-1.186.949-.284,1.961-.426,3.036-.426,1.012,0,2.003.148,2.973.442.971.295,1.866.718,2.689,1.266.822.548,1.55,1.209,2.182,1.984s1.127,1.642,1.486,2.602l-2.246.98c-.295-.768-.673-1.468-1.13-2.095-.459-.627-.989-1.162-1.59-1.604-.601-.443-1.265-.785-1.992-1.029-.728-.242-1.508-.363-2.341-.363-1.359,0-2.532.268-3.518.806s-1.797,1.254-2.435,2.151c-.638.895-1.107,1.919-1.407,3.067-.301,1.149-.451,2.335-.451,3.558,0,1.244.166,2.424.498,3.543.333,1.117.833,2.098,1.503,2.94.669.844,1.507,1.513,2.514,2.008,1.007.496,2.18.744,3.518.744.801,0,1.576-.143,2.325-.428.749-.284,1.44-.671,2.072-1.162.632-.49,1.191-1.064,1.675-1.723.485-.658.864-1.357,1.139-2.095l2.088.917Z"/>
<path d="m287.991,100.539v9.835h-2.751v-22.613h7.431c1.044,0,2.042.111,2.997.332.954.222,1.795.586,2.522,1.092.728.505,1.307,1.168,1.74,1.984.431.818.648,1.822.648,3.013,0,.885-.137,1.673-.411,2.364-.275.691-.66,1.289-1.155,1.795-.496.507-1.086.925-1.771,1.257-.685.333-1.44.583-2.261.752l6.926,10.026h-3.068l-6.736-9.835h-4.112Zm0-2.183h4.871c.727,0,1.393-.075,1.999-.228s1.131-.402,1.574-.744c.442-.342.785-.785,1.028-1.328s.363-1.21.363-2.001c0-.801-.126-1.466-.378-1.992-.254-.527-.601-.943-1.044-1.25-.443-.305-.967-.521-1.573-.648s-1.262-.189-1.968-.189h-4.871v8.38Z"/>
<path d="m308.231,91.335v19.039h-2.529v-22.613h3.826l7.242,17.932,7.148-17.932h3.795v22.613h-2.752v-19.039l-7.653,19.039h-1.17l-7.907-19.039Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,25 @@
import { URLSearchParams } from 'url';
import authScope from '../common/auth-scope.js';
export default async function generateAuthUrl($) {
const oauthRedirectUrlField = $.app.auth.fields.find(
(field) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value;
const searchParams = new URLSearchParams({
scope: authScope.join(','),
client_id: $.auth.data.clientId,
response_type: 'code',
access_type: 'offline',
redirect_uri: redirectUri,
});
const domain =
$.auth.data.region !== 'cn' ? 'account.zoho.com' : 'accounts.zoho.com.cn';
const url = `https://${domain}/oauth/v2/auth?${searchParams.toString()}`;
await $.auth.set({
url,
});
}

View File

@@ -0,0 +1,66 @@
import generateAuthUrl from './generate-auth-url.js';
import verifyCredentials from './verify-credentials.js';
import refreshToken from './refresh-token.js';
import isStillVerified from './is-still-verified.js';
export default {
fields: [
{
key: 'oAuthRedirectUrl',
label: 'OAuth Redirect URL',
type: 'string',
required: true,
readOnly: true,
value: '{WEB_APP_URL}/app/bigin-by-zoho-crm/connections/add',
placeholder: null,
description:
'When asked to input a redirect URL in Bigin By Zoho CRM, enter the URL above.',
clickToCopy: true,
},
{
key: 'region',
label: 'Region',
type: 'dropdown',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: '',
options: [
{ label: 'United States', value: 'us' },
{ label: 'European Union', value: 'eu' },
{ label: 'Australia', value: 'au' },
{ label: 'India', value: 'in' },
{ label: 'China', value: 'cn' },
],
clickToCopy: false,
},
{
key: 'clientId',
label: 'Client ID',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'clientSecret',
label: 'Client Secret',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
],
generateAuthUrl,
verifyCredentials,
isStillVerified,
refreshToken,
};

View File

@@ -0,0 +1,8 @@
import getCurrentOrganization from '../common/get-current-organization.js';
const isStillVerified = async ($) => {
const org = await getCurrentOrganization($);
return !!org.id;
};
export default isStillVerified;

View File

@@ -0,0 +1,34 @@
import { URLSearchParams } from 'node:url';
import authScope from '../common/auth-scope.js';
import { regionUrlMap } from '../common/region-url-map.js';
const refreshToken = async ($) => {
const location = $.auth.data.location;
const params = new URLSearchParams({
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
refresh_token: $.auth.data.refreshToken,
grant_type: 'refresh_token',
});
const { data } = await $.http.post(
`${regionUrlMap[location]}/oauth/v2/token`,
params.toString(),
{
additionalProperties: {
skipAddingBaseUrl: true,
},
}
);
await $.auth.set({
accessToken: data.access_token,
apiDomain: data.api_domain,
scope: authScope.join(','),
tokenType: data.token_type,
expiresIn: data.expires_in,
});
};
export default refreshToken;

View File

@@ -0,0 +1,46 @@
import { URLSearchParams } from 'node:url';
import { regionUrlMap } from '../common/region-url-map.js';
import getCurrentOrganization from '../common/get-current-organization.js';
const verifyCredentials = async ($) => {
const oauthRedirectUrlField = $.app.auth.fields.find(
(field) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value;
const location = $.auth.data.location;
const params = new URLSearchParams({
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
code: $.auth.data.code,
redirect_uri: redirectUri,
grant_type: 'authorization_code',
});
const { data } = await $.http.post(
`${regionUrlMap[location]}/oauth/v2/token`,
params.toString()
);
await $.auth.set({
accessToken: data.access_token,
tokenType: data.token_type,
apiDomain: data.api_domain,
});
const organization = await getCurrentOrganization($);
const screenName = [organization.company_name, organization.primary_email]
.filter(Boolean)
.join(' @ ');
await $.auth.set({
clientId: $.auth.data.clientId,
clientSecret: $.auth.data.clientSecret,
scope: $.auth.data.scope,
expiresIn: data.expires_in,
refreshToken: data.refresh_token,
screenName,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,9 @@
const addAuthHeader = ($, requestConfig) => {
if ($.auth.data?.accessToken) {
requestConfig.headers.Authorization = `Zoho-oauthtoken ${$.auth.data.accessToken}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -0,0 +1,10 @@
const authScope = [
'ZohoBigin.notifications.ALL',
'ZohoBigin.users.ALL',
'ZohoBigin.modules.ALL',
'ZohoBigin.org.READ',
'ZohoBigin.settings.ALL',
'ZohoBigin.modules.ALL',
];
export default authScope;

View File

@@ -0,0 +1,6 @@
const getCurrentOrganization = async ($) => {
const response = await $.http.get('/bigin/v2/org');
return response.data.org[0];
};
export default getCurrentOrganization;

View File

@@ -0,0 +1,8 @@
export const regionUrlMap = {
us: 'https://accounts.zoho.com',
au: 'https://accounts.zoho.com.au',
eu: 'https://accounts.zoho.eu',
in: 'https://accounts.zoho.in',
cn: 'https://accounts.zoho.com.cn',
jp: 'https://accounts.zoho.jp',
};

View File

@@ -0,0 +1,14 @@
const setBaseUrl = ($, requestConfig) => {
if (requestConfig.additionalProperties?.skipAddingBaseUrl)
return requestConfig;
const apiDomain = $.auth.data.apiDomain;
if (apiDomain) {
requestConfig.baseURL = apiDomain;
}
return requestConfig;
};
export default setBaseUrl;

View File

@@ -0,0 +1,5 @@
import listCompanies from './list-companies/index.js';
import listOrganizations from './list-organizations/index.js';
import listContactOwners from './list-contact-owners/index.js';
export default [listCompanies, listOrganizations, listContactOwners];

View File

@@ -0,0 +1,39 @@
export default {
name: 'List companies',
key: 'listCompanies',
async run($) {
const companies = {
data: [],
};
const params = new URLSearchParams({
page: 1,
pageSize: 200,
fields: 'Account_Name',
});
let next = false;
do {
const { data } = await $.http.get('/bigin/v2/Accounts', { params });
if (data.info.more_records) {
params.page = params.page + 1;
next = true;
} else {
next = false;
}
if (data.data) {
for (const account of data.data) {
companies.data.push({
value: account.id,
name: account.Account_Name,
});
}
}
} while (next);
return companies;
},
};

View File

@@ -0,0 +1,39 @@
export default {
name: 'List contact owners',
key: 'listContactOwners',
async run($) {
const contactOwners = {
data: [],
};
const params = {
type: 'AllUsers',
page: 1,
pageSize: 200,
};
let next = false;
do {
const { data } = await $.http.get('/bigin/v2/users', params);
if (data.users.length === params.pageSize) {
next = true;
params.page = params.page + 1;
} else {
next = false;
}
if (data.users) {
for (const user of data.users) {
contactOwners.data.push({
value: user.id,
name: user.full_name,
});
}
}
} while (next);
return contactOwners;
},
};

View File

@@ -0,0 +1,23 @@
export default {
name: 'List organizations',
key: 'listOrganizations',
async run($) {
const organizations = {
data: [],
};
const { data } = await $.http.get('/bigin/v2/org');
if (data.org) {
for (const org of data.org) {
organizations.data.push({
value: org.id,
name: org.company_name,
});
}
}
return organizations;
},
};

View File

@@ -0,0 +1,23 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import setBaseUrl from './common/set-base-url.js';
import triggers from './triggers/index.js';
import dynamicData from './dynamic-data/index.js';
import actions from './actions/index.js';
export default defineApp({
name: 'Bigin By Zoho CRM',
key: 'bigin-by-zoho-crm',
baseUrl: 'https://www.bigin.com',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/bigin-by-zoho-crm/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/bigin-by-zoho-crm/connection',
primaryColor: '039649',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],
auth,
triggers,
dynamicData,
actions,
});

View File

@@ -0,0 +1,7 @@
import newCalls from './new-calls/index.js';
import newCompanies from './new-companies/index.js';
import newContacts from './new-contacts/index.js';
import newProducts from './new-products/index.js';
import newTasks from './new-tasks/index.js';
export default [newCalls, newCompanies, newContacts, newProducts, newTasks];

View File

@@ -0,0 +1,89 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New calls',
key: 'newCalls',
type: 'webhook',
description: 'Triggers when a new call is added.',
arguments: [
{
label: 'Organization',
key: 'organizationId',
type: 'dropdown',
required: true,
description: '',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listOrganizations',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: Crypto.randomUUID(),
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const organizationId = $.step.parameters.organizationId;
const sampleEventData = {
ids: ['111111111111111111'],
token: null,
module: 'Calls',
operation: 'insert',
channel_id: organizationId,
server_time: 1708426963120,
query_params: {},
resource_uri: `${$.auth.data.apiDomain}/bigin/v1/Calls`,
affected_fields: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.channel_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const organizationId = $.step.parameters.organizationId;
const payload = {
watch: [
{
channel_id: organizationId,
notify_url: $.webhookUrl,
events: ['Calls.create'],
},
],
};
await $.http.post('/bigin/v2/actions/watch', payload);
await $.flow.setRemoteWebhookId(organizationId);
},
async unregisterHook($) {
await $.http.delete(
`/bigin/v2/actions/watch?channel_ids=${$.flow.remoteWebhookId}`
);
},
});

View File

@@ -0,0 +1,89 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New companies',
key: 'newCompanies',
type: 'webhook',
description: 'Triggers when a new company is created.',
arguments: [
{
label: 'Organization',
key: 'organizationId',
type: 'dropdown',
required: true,
description: '',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listOrganizations',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: Crypto.randomUUID(),
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const organizationId = $.step.parameters.organizationId;
const sampleEventData = {
ids: ['111111111111111111'],
token: null,
module: 'Accounts',
operation: 'insert',
channel_id: organizationId,
server_time: 1708426963120,
query_params: {},
resource_uri: `${$.auth.data.apiDomain}/bigin/v1/Accounts`,
affected_fields: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.channel_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const organizationId = $.step.parameters.organizationId;
const payload = {
watch: [
{
channel_id: organizationId,
notify_url: $.webhookUrl,
events: ['Accounts.create'],
},
],
};
await $.http.post('/bigin/v2/actions/watch', payload);
await $.flow.setRemoteWebhookId(organizationId);
},
async unregisterHook($) {
await $.http.delete(
`/bigin/v2/actions/watch?channel_ids=${$.flow.remoteWebhookId}`
);
},
});

View File

@@ -0,0 +1,89 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New contacts',
key: 'newContacts',
type: 'webhook',
description: 'Triggers when a new contact is created.',
arguments: [
{
label: 'Organization',
key: 'organizationId',
type: 'dropdown',
required: true,
description: '',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listOrganizations',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: Crypto.randomUUID(),
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const organizationId = $.step.parameters.organizationId;
const sampleEventData = {
ids: ['111111111111111111'],
token: null,
module: 'Contacts',
operation: 'insert',
channel_id: organizationId,
server_time: 1708426963120,
query_params: {},
resource_uri: `${$.auth.data.apiDomain}/bigin/v1/Contacts`,
affected_fields: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.channel_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const organizationId = $.step.parameters.organizationId;
const payload = {
watch: [
{
channel_id: organizationId,
notify_url: $.webhookUrl,
events: ['Contacts.create'],
},
],
};
await $.http.post('/bigin/v2/actions/watch', payload);
await $.flow.setRemoteWebhookId(organizationId);
},
async unregisterHook($) {
await $.http.delete(
`/bigin/v2/actions/watch?channel_ids=${$.flow.remoteWebhookId}`
);
},
});

View File

@@ -0,0 +1,89 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New products',
key: 'newProducts',
type: 'webhook',
description: 'Triggers when a new product is created.',
arguments: [
{
label: 'Organization',
key: 'organizationId',
type: 'dropdown',
required: true,
description: '',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listOrganizations',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: Crypto.randomUUID(),
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const organizationId = $.step.parameters.organizationId;
const sampleEventData = {
ids: ['111111111111111111'],
token: null,
module: 'Products',
operation: 'insert',
channel_id: organizationId,
server_time: 1708426963120,
query_params: {},
resource_uri: `${$.auth.data.apiDomain}/bigin/v1/Products`,
affected_fields: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.channel_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const organizationId = $.step.parameters.organizationId;
const payload = {
watch: [
{
channel_id: organizationId,
notify_url: $.webhookUrl,
events: ['Products.create'],
},
],
};
await $.http.post('/bigin/v2/actions/watch', payload);
await $.flow.setRemoteWebhookId(organizationId);
},
async unregisterHook($) {
await $.http.delete(
`/bigin/v2/actions/watch?channel_ids=${$.flow.remoteWebhookId}`
);
},
});

View File

@@ -0,0 +1,89 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New tasks',
key: 'newTasks',
type: 'webhook',
description: 'Triggers when a new task is created.',
arguments: [
{
label: 'Organization',
key: 'organizationId',
type: 'dropdown',
required: true,
description: '',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listOrganizations',
},
],
},
},
],
async run($) {
const dataItem = {
raw: $.request.body,
meta: {
internalId: Crypto.randomUUID(),
},
};
$.pushTriggerItem(dataItem);
},
async testRun($) {
const organizationId = $.step.parameters.organizationId;
const sampleEventData = {
ids: ['111111111111111111'],
token: null,
module: 'Tasks',
operation: 'insert',
channel_id: organizationId,
server_time: 1708426963120,
query_params: {},
resource_uri: `${$.auth.data.apiDomain}/bigin/v1/Tasks`,
affected_fields: [],
};
const dataItem = {
raw: sampleEventData,
meta: {
internalId: sampleEventData.channel_id,
},
};
$.pushTriggerItem(dataItem);
},
async registerHook($) {
const organizationId = $.step.parameters.organizationId;
const payload = {
watch: [
{
channel_id: organizationId,
notify_url: $.webhookUrl,
events: ['Tasks.create'],
},
],
};
await $.http.post('/bigin/v2/actions/watch', payload);
await $.flow.setRemoteWebhookId(organizationId);
},
async unregisterHook($) {
await $.http.delete(
`/bigin/v2/actions/watch?channel_ids=${$.flow.remoteWebhookId}`
);
},
});

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 112 KiB

View File

@@ -1,21 +0,0 @@
import verifyCredentials from './verify-credentials.js';
import isStillVerified from './is-still-verified.js';
export default {
fields: [
{
key: 'apiKey',
label: 'API Key',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: 'PDFMonkey API secret key of your account.',
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified,
};

View File

@@ -1,8 +0,0 @@
import getCurrentUser from '../common/get-current-user.js';
const isStillVerified = async ($) => {
const currentUser = await getCurrentUser($);
return !!currentUser.id;
};
export default isStillVerified;

View File

@@ -1,15 +0,0 @@
import getCurrentUser from '../common/get-current-user.js';
const verifyCredentials = async ($) => {
const currentUser = await getCurrentUser($);
const screenName = [currentUser.desired_name, currentUser.email]
.filter(Boolean)
.join(' @ ');
await $.auth.set({
screenName,
apiKey: $.auth.data.apiKey,
});
};
export default verifyCredentials;

View File

@@ -1,9 +0,0 @@
const addAuthHeader = ($, requestConfig) => {
if ($.auth.data?.apiKey) {
requestConfig.headers.Authorization = `Bearer ${$.auth.data.apiKey}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -1,8 +0,0 @@
const getCurrentUser = async ($) => {
const response = await $.http.get('/v1/current_user');
const currentUser = response.data.current_user;
return currentUser;
};
export default getCurrentUser;

View File

@@ -1,4 +0,0 @@
import listTemplates from './list-templates/index.js';
import listWorkspaces from './list-workspaces/index.js';
export default [listTemplates, listWorkspaces];

View File

@@ -1,39 +0,0 @@
export default {
name: 'List templates',
key: 'listTemplates',
async run($) {
const templates = {
data: [],
};
const workspaceId = $.step.parameters.workspaceId;
let next = false;
const params = {
page: 'all',
'q[workspace_id]': workspaceId,
};
if (!workspaceId) {
return templates;
}
do {
const { data } = await $.http.get('/v1/document_template_cards', params);
next = data.meta.next_page;
if (!data?.document_template_cards?.length) {
return;
}
for (const template of data.document_template_cards) {
templates.data.push({
value: template.id,
name: template.identifier,
});
}
} while (next);
return templates;
},
};

View File

@@ -1,29 +0,0 @@
export default {
name: 'List workspaces',
key: 'listWorkspaces',
async run($) {
const workspaces = {
data: [],
};
let next = false;
do {
const { data } = await $.http.get('/v1/workspace_cards');
next = data.meta.next_page;
if (!data?.workspace_cards?.length) {
return;
}
for (const workspace of data.workspace_cards) {
workspaces.data.push({
value: workspace.id,
name: workspace.identifier,
});
}
} while (next);
return workspaces;
},
};

View File

@@ -1,20 +0,0 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import triggers from './triggers/index.js';
import dynamicData from './dynamic-data/index.js';
export default defineApp({
name: 'PDFMonkey',
key: 'pdf-monkey',
iconUrl: '{BASE_URL}/apps/pdf-monkey/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/pdf-monkey/connection',
supportsConnections: true,
baseUrl: 'https://pdfmonkey.io',
apiBaseUrl: 'https://api.pdfmonkey.io/api',
primaryColor: '376794',
beforeRequest: [addAuthHeader],
auth,
triggers,
dynamicData,
});

View File

@@ -1,99 +0,0 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'Documents Generated',
key: 'documentsGenerated',
pollInterval: 15,
description:
'Triggers upon the successful completion of document generation.',
arguments: [
{
label: 'Workspace',
key: 'workspaceId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listWorkspaces',
},
],
},
},
{
label: 'Templates',
key: 'templateIds',
type: 'dynamic',
required: false,
description: 'Apply this trigger exclusively for particular templates.',
fields: [
{
label: 'Template',
key: 'templateId',
type: 'dropdown',
required: false,
depensOn: ['parameters.workspaceId'],
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listTemplates',
},
{
name: 'parameters.workspaceId',
value: '{parameters.workspaceId}',
},
],
},
},
],
},
],
async run($) {
const workspaceId = $.step.parameters.workspaceId;
const templateIds = $.step.parameters.templateIds;
const allTemplates = templateIds
.map((templateId) => templateId.templateId)
.join(',');
const params = {
'page[size]': 100,
'q[workspace_id]': workspaceId,
'q[status]': 'success',
};
if (!templateIds.length) {
params['q[document_template_id]'] = allTemplates;
}
let next = false;
do {
const { data } = await $.http.get('/v1/document_cards', { params });
if (!data?.document_cards?.length) {
return;
}
next = data.meta.next_page;
for (const document of data.document_cards) {
$.pushTriggerItem({
raw: document,
meta: {
internalId: document.id,
},
});
}
} while (next);
},
});

View File

@@ -1,3 +0,0 @@
import documentsGenerated from './documents-generated/index.js';
export default [documentsGenerated];

View File

@@ -1,10 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import SamlAuthProvider from '../../../../../models/saml-auth-provider.ee.js';
export default async (request, response) => {
const samlAuthProvider = await SamlAuthProvider.query()
.findById(request.params.samlAuthProviderId)
.throwIfNotFound();
renderObject(response, samlAuthProvider);
};

View File

@@ -1,34 +0,0 @@
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../../app.js';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
import { createRole } from '../../../../../../test/factories/role.js';
import { createUser } from '../../../../../../test/factories/user.js';
import { createSamlAuthProvider } from '../../../../../../test/factories/saml-auth-provider.ee.js';
import getSamlAuthProviderMock from '../../../../../../test/mocks/rest/api/v1/saml-auth-providers/get-saml-auth-provider.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/saml-auth-provider/:samlAuthProviderId', () => {
let samlAuthProvider, currentUser, token;
beforeEach(async () => {
const role = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: role.id });
samlAuthProvider = await createSamlAuthProvider();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return saml auth provider with specified id', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get(`/api/v1/admin/saml-auth-providers/${samlAuthProvider.id}`)
.set('Authorization', token)
.expect(200);
const expectedPayload = await getSamlAuthProviderMock(samlAuthProvider);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,11 +0,0 @@
import { renderObject } from '../../../../../helpers/renderer.js';
import SamlAuthProvider from '../../../../../models/saml-auth-provider.ee.js';
export default async (request, response) => {
const samlAuthProviders = await SamlAuthProvider.query().orderBy(
'created_at',
'desc'
);
renderObject(response, samlAuthProviders);
};

View File

@@ -1,39 +0,0 @@
import { vi, describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../../app.js';
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
import { createRole } from '../../../../../../test/factories/role.js';
import { createUser } from '../../../../../../test/factories/user.js';
import { createSamlAuthProvider } from '../../../../../../test/factories/saml-auth-provider.ee.js';
import getSamlAuthProvidersMock from '../../../../../../test/mocks/rest/api/v1/saml-auth-providers/get-saml-auth-providers.ee.js';
import * as license from '../../../../../helpers/license.ee.js';
describe('GET /api/v1/admin/saml-auth-providers', () => {
let samlAuthProviderOne, samlAuthProviderTwo, currentUser, token;
beforeEach(async () => {
const role = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: role.id });
samlAuthProviderOne = await createSamlAuthProvider();
samlAuthProviderTwo = await createSamlAuthProvider();
token = createAuthTokenByUserId(currentUser.id);
});
it('should return saml auth providers', async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
const response = await request(app)
.get('/api/v1/admin/saml-auth-providers')
.set('Authorization', token)
.expect(200);
const expectedPayload = await getSamlAuthProvidersMock([
samlAuthProviderTwo,
samlAuthProviderOne,
]);
expect(response.body).toEqual(expectedPayload);
});
});

View File

@@ -1,17 +1,16 @@
const authorizationList = {
'GET /api/v1/users/:userId': {
'/api/v1/users/:userId': {
action: 'read',
subject: 'User',
},
'GET /api/v1/users/': {
'/api/v1/users/': {
action: 'read',
subject: 'User',
},
};
export const authorizeUser = async (request, response, next) => {
const currentRoute =
request.method + ' ' + request.baseUrl + request.route.path;
const currentRoute = request.baseUrl + request.route.path;
const currentRouteRule = authorizationList[currentRoute];
try {
@@ -21,13 +20,3 @@ export const authorizeUser = async (request, response, next) => {
return response.status(403).end();
}
};
export const authorizeAdmin = async (request, response, next) => {
const role = await request.currentUser.$relatedQuery('role');
if (role?.isAdmin) {
next();
} else {
return response.status(403).end();
}
};

View File

@@ -1,9 +0,0 @@
import { hasValidLicense } from './license.ee.js';
export const checkIsEnterprise = async (request, response, next) => {
if (await hasValidLicense()) {
next();
} else {
return response.status(404).end();
}
};

View File

@@ -4,8 +4,8 @@ import appConfig from '../config/app.js';
const levels = {
error: 0,
warn: 1,
http: 2,
info: 3,
info: 2,
http: 3,
debug: 4,
};

View File

@@ -15,8 +15,6 @@ const renderObject = (response, object) => {
let data = isPaginated(object) ? object.records : object;
const type = isPaginated(object)
? object.records[0].constructor.name
: Array.isArray(object)
? object[0].constructor.name
: object.constructor.name;
const serializer = serializers[type];

View File

@@ -1,26 +0,0 @@
import { Router } from 'express';
import { authenticateUser } from '../../../helpers/authentication.js';
import { authorizeAdmin } from '../../../helpers/authorization.js';
import { checkIsEnterprise } from '../../../helpers/check-is-enterprise.js';
import getSamlAuthProvidersAction from '../../../controllers/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.js';
import getSamlAuthProviderAction from '../../../controllers/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.js';
const router = Router();
router.get(
'/',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
getSamlAuthProvidersAction
);
router.get(
'/:samlAuthProviderId',
authenticateUser,
authorizeAdmin,
checkIsEnterprise,
getSamlAuthProviderAction
);
export default router;

View File

@@ -5,7 +5,6 @@ import paddleRouter from './paddle.ee.js';
import healthcheckRouter from './healthcheck.js';
import automatischRouter from './api/v1/automatisch.js';
import usersRouter from './api/v1/users.js';
import samlAuthProvidersRouter from './api/v1/saml-auth-providers.ee.js';
const router = Router();
@@ -15,6 +14,5 @@ router.use('/paddle', paddleRouter);
router.use('/healthcheck', healthcheckRouter);
router.use('/api/v1/automatisch', automatischRouter);
router.use('/api/v1/users', usersRouter);
router.use('/api/v1/admin/saml-auth-providers', samlAuthProvidersRouter);
export default router;

View File

@@ -1,13 +1,11 @@
import userSerializer from './user.js';
import roleSerializer from './role.js';
import permissionSerializer from './permission.js';
import samlAuthProviderSerializer from './saml-auth-provider.ee.js';
const serializers = {
User: userSerializer,
Role: roleSerializer,
Permission: permissionSerializer,
SamlAuthProvider: samlAuthProviderSerializer,
};
export default serializers;

View File

@@ -1,18 +0,0 @@
const samlAuthProviderSerializer = (samlAuthProvider) => {
return {
id: samlAuthProvider.id,
name: samlAuthProvider.name,
certificate: samlAuthProvider.certificate,
signatureAlgorithm: samlAuthProvider.signatureAlgorithm,
issuer: samlAuthProvider.issuer,
entryPoint: samlAuthProvider.entryPoint,
firstnameAttributeName: samlAuthProvider.firstnameAttributeName,
surnameAttributeName: samlAuthProvider.surnameAttributeName,
emailAttributeName: samlAuthProvider.emailAttributeName,
roleAttributeName: samlAuthProvider.roleAttributeName,
active: samlAuthProvider.active,
defaultRoleId: samlAuthProvider.defaultRoleId,
};
};
export default samlAuthProviderSerializer;

View File

@@ -1,32 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { createSamlAuthProvider } from '../../test/factories/saml-auth-provider.ee.js';
import samlAuthProviderSerializer from './saml-auth-provider.ee.js';
describe('samlAuthProviderSerializer', () => {
let samlAuthProvider;
beforeEach(async () => {
samlAuthProvider = await createSamlAuthProvider();
});
it('should return saml auth provider data', async () => {
const expectedPayload = {
id: samlAuthProvider.id,
name: samlAuthProvider.name,
certificate: samlAuthProvider.certificate,
signatureAlgorithm: samlAuthProvider.signatureAlgorithm,
issuer: samlAuthProvider.issuer,
entryPoint: samlAuthProvider.entryPoint,
firstnameAttributeName: samlAuthProvider.firstnameAttributeName,
surnameAttributeName: samlAuthProvider.surnameAttributeName,
emailAttributeName: samlAuthProvider.emailAttributeName,
roleAttributeName: samlAuthProvider.roleAttributeName,
active: samlAuthProvider.active,
defaultRoleId: samlAuthProvider.defaultRoleId,
};
expect(samlAuthProviderSerializer(samlAuthProvider)).toEqual(
expectedPayload
);
});
});

View File

@@ -1,33 +0,0 @@
import { createRole } from './role';
import SamlAuthProvider from '../../src/models/saml-auth-provider.ee.js';
export const createSamlAuthProvider = async (params = {}) => {
params.name = params?.name || 'Keycloak SAML';
params.certificate = params?.certificate || 'certificate';
params.signatureAlgorithm = params?.signatureAlgorithm || 'sha512';
params.entryPoint =
params?.entryPoint ||
'https://example.com/auth/realms/automatisch/protocol/saml';
params.issuer = params?.issuer || 'automatisch-client';
params.firstnameAttributeName =
params?.firstnameAttributeName || 'urn:oid:2.1.1.42';
params.surnameAttributeName =
params?.surnameAttributeName || 'urn:oid:2.1.1.4';
params.emailAttributeName =
params?.emailAttributeName || 'urn:oid:1.1.2342.19200300.100.1.1';
params.roleAttributeName = params?.roleAttributeName || 'Role';
params.defaultRoleId = params?.defaultRoleId || (await createRole()).id;
params.active = params?.active || true;
const samlAuthProvider = await SamlAuthProvider.query()
.insert(params)
.returning('*');
return samlAuthProvider;
};

View File

@@ -1,29 +0,0 @@
const getSamlAuthProvidersMock = async (samlAuthProvider) => {
const data = {
active: samlAuthProvider.active,
certificate: samlAuthProvider.certificate,
defaultRoleId: samlAuthProvider.defaultRoleId,
emailAttributeName: samlAuthProvider.emailAttributeName,
entryPoint: samlAuthProvider.entryPoint,
firstnameAttributeName: samlAuthProvider.firstnameAttributeName,
id: samlAuthProvider.id,
issuer: samlAuthProvider.issuer,
name: samlAuthProvider.name,
roleAttributeName: samlAuthProvider.roleAttributeName,
signatureAlgorithm: samlAuthProvider.signatureAlgorithm,
surnameAttributeName: samlAuthProvider.surnameAttributeName,
};
return {
data: data,
meta: {
count: 1,
currentPage: null,
isArray: false,
totalPages: null,
type: 'SamlAuthProvider',
},
};
};
export default getSamlAuthProvidersMock;

View File

@@ -1,31 +0,0 @@
const getSamlAuthProvidersMock = async (samlAuthProviders) => {
const data = samlAuthProviders.map((samlAuthProvider) => {
return {
active: samlAuthProvider.active,
certificate: samlAuthProvider.certificate,
defaultRoleId: samlAuthProvider.defaultRoleId,
emailAttributeName: samlAuthProvider.emailAttributeName,
entryPoint: samlAuthProvider.entryPoint,
firstnameAttributeName: samlAuthProvider.firstnameAttributeName,
id: samlAuthProvider.id,
issuer: samlAuthProvider.issuer,
name: samlAuthProvider.name,
roleAttributeName: samlAuthProvider.roleAttributeName,
signatureAlgorithm: samlAuthProvider.signatureAlgorithm,
surnameAttributeName: samlAuthProvider.surnameAttributeName,
};
});
return {
data: data,
meta: {
count: data.length,
currentPage: null,
isArray: true,
totalPages: null,
type: 'SamlAuthProvider',
},
};
};
export default getSamlAuthProvidersMock;

View File

@@ -32,6 +32,16 @@ export default defineConfig({
],
sidebar: {
'/apps/': [
{
text: 'Bigin By Zoho CRM',
collapsible: true,
collapsed: true,
items: [
{ text: 'Triggers', link: '/apps/bigin-by-zoho-crm/triggers' },
{ text: 'Actions', link: '/apps/bigin-by-zoho-crm/actions' },
{ text: 'Connection', link: '/apps/bigin-by-zoho-crm/connection' },
],
},
{
text: 'Carbone',
collapsible: true,
@@ -252,15 +262,6 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/openai/connection' },
],
},
{
text: 'PDFMonkey',
collapsible: true,
collapsed: true,
items: [
{ text: 'Triggers', link: '/apps/pdf-monkey/triggers' },
{ text: 'Connection', link: '/apps/pdf-monkey/connection' },
],
},
{
text: 'Pipedrive',
collapsible: true,

View File

@@ -0,0 +1,16 @@
---
favicon: /favicons/bigin-by-zoho-crm.svg
items:
- name: Create company
desc: Creates a new company.
- name: Create contact
desc: Creates a new contact.
- name: Create event
desc: Creates a new event.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -0,0 +1,18 @@
# Bigin By Zoho CRM
:::info
This page explains the steps you need to follow to set up the Bigin By Zoho CRM
connection in Automatisch. If any of the steps are outdated, please let us know!
:::
1. Go to the [Zoho API Console](https://api-console.zoho.com) to register an application.
2. Login to your account.
3. Click on the **GET STARTED** button.
4. Choose the **Server-based Applications** client type.
5. Fill the **Create New Client** form.
6. Copy **OAuth Redirect URL** from Automatisch to **Authorized redirect URIs** field, and click on the **Create** button.
7. Copy the **Client ID** value to the `Client ID` field on Automatisch.
8. Copy the **Client Secret** value to the `Client Secret` field on Automatisch.
9. Select the region appropriate for your account.
10. Click **Submit** button on Automatisch.
11. Congrats! Start using your new Bigin By Zoho CRM connection within the flows.

View File

@@ -0,0 +1,20 @@
---
favicon: /favicons/bigin-by-zoho-crm.svg
items:
- name: New calls
desc: Triggers when a new call is added.
- name: New companies
desc: Triggers when a new company is created.
- name: New contacts
desc: Triggers when a new contact is created.
- name: New products
desc: Triggers when a new product is created.
- name: New tasks
desc: Triggers when a new task is created.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -1,11 +0,0 @@
# PDFMonkey
:::info
This page explains the steps you need to follow to set up the PDFMonkey
connection in Automatisch. If any of the steps are outdated, please let us know!
:::
1. Login to your PDFMonkey account: [https://dashboard.pdfmonkey.io/login](https://dashboard.pdfmonkey.io/login).
2. Go to **My Account** section from your profile.
3. Copy `API SECRET KEY` from the page to the `API Key` field on Automatisch.
4. Now, you can start using the PDFMonkey connection with Automatisch.

View File

@@ -1,12 +0,0 @@
---
favicon: /favicons/pdf-monkey.svg
items:
- name: Documents Generated
desc: Triggers upon the successful completion of document generation.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -2,6 +2,7 @@
The following integrations are currently supported by Automatisch.
- [Bigin By Zoho CRM](/apps/bigin-by-zoho-crm/triggers)
- [Carbone](/apps/carbone/actions)
- [DeepL](/apps/deepl/actions)
- [Delay](/apps/delay/actions)

View File

@@ -0,0 +1,32 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" id="b" data-name="Layer 2" width="327.714" height="120" viewBox="0 0 327.714 120">
<defs>
<style>
.d {
fill: #039649;
}
</style>
</defs>
<g id="c" data-name="Layer 1">
<g>
<path class="d" d="m52.39,120c-1.801,0-3.6-.6-5.101-1.5-2.1-1.5-3.6-4.2-3.6-6.9v-24.6L1.09,12.901C-.41,9.9-.41,6.601,1.391,4.2,2.891,1.5,5.89,0,8.89,0h78c2.999,0,5.698,1.5,7.199,4.2,1.801,2.702,1.801,6.3.301,9.002l-5.101,9h10.201c2.999,0,5.698,1.5,7.199,4.2,1.801,2.7,1.801,6.3.301,9l-29.701,51.3v18.599c0,3.899-2.399,6.9-5.999,8.099l-16.2,6.3c-.6.301-1.799.301-2.7.301M8.89,8.4q-.301.301-.301.602l42.301,73.798c1.199,2.1,1.199,3.299,1.199,4.501v23.998s.301.301.6,0l16.2-6.3h.6v-17.999c0-1.199,0-3.299,1.201-4.8l29.4-50.999c0-.301,0-.6-.301-.6l-53.699-.301,14.399,24.901,10.201-17.7c1.199-2.1,3.6-2.7,5.7-1.5,2.1,1.199,2.7,3.6,1.498,5.7l-11.998,20.699c-2.702,4.2-8.701,3.901-11.102.301l-17.4-30.9c-1.199-1.799-1.199-4.2,0-6.3,1.201-2.1,3.301-3.6,5.7-3.6h36.6l7.499-12.899s0-.301-.299-.602H8.89Z"/>
<g>
<path d="m181.725,48.737c0,3.089-.54,5.684-1.618,7.788-1.081,2.104-2.548,3.79-4.407,5.062-1.858,1.27-4.016,2.179-6.476,2.726-2.459.547-5.069.819-7.828.819h-24.591V6.521h23.034c2.676,0,5.198.24,7.561.718,2.364.479,4.427,1.311,6.189,2.5,1.762,1.189,3.149,2.787,4.16,4.795,1.011,2.008,1.517,4.53,1.517,7.562,0,3.17-.786,5.813-2.357,7.93-1.57,2.119-3.913,3.628-7.028,4.53,4.017.819,6.995,2.371,8.935,4.652s2.91,5.458,2.91,9.529Zm-33.813-17.624h10.533c1.612,0,3.033-.136,4.263-.41,1.23-.272,2.268-.738,3.115-1.393.846-.656,1.489-1.55,1.927-2.684.436-1.134.655-2.562.655-4.284,0-1.612-.267-2.923-.799-3.934-.532-1.01-1.25-1.809-2.152-2.398-.902-.587-1.967-.99-3.197-1.209s-2.542-.328-3.934-.328h-10.411v16.64Zm0,26.067h12.09c1.64,0,3.115-.169,4.427-.512,1.311-.342,2.424-.894,3.341-1.66.915-.764,1.612-1.748,2.091-2.951.478-1.202.716-2.663.716-4.385,0-1.802-.294-3.285-.881-4.447-.588-1.161-1.394-2.083-2.419-2.766s-2.227-1.154-3.606-1.414c-1.381-.26-2.863-.39-4.447-.39h-11.312v18.525Z"/>
<path d="m202.257,9.555c0,.847-.151,1.633-.451,2.356-.3.724-.716,1.34-1.25,1.844-.532.507-1.167.902-1.905,1.189s-1.53.431-2.377.431c-.819,0-1.598-.144-2.336-.431s-1.388-.69-1.947-1.209c-.56-.519-.998-1.133-1.311-1.844-.315-.711-.471-1.489-.471-2.336s.156-1.626.471-2.336c.314-.711.744-1.325,1.291-1.845.546-.519,1.187-.922,1.925-1.209s1.53-.431,2.377-.431c.821,0,1.598.144,2.336.431s1.373.69,1.907,1.209c.532.52.955,1.134,1.27,1.845.314.71.471,1.489.471,2.336Zm-.778,12.705v42.871h-10.246V22.261h10.246Z"/>
<path d="m254.186,61.935c0,3.361-.587,6.236-1.762,8.627-1.174,2.391-2.78,4.352-4.815,5.882-2.036,1.529-4.407,2.65-7.111,3.361-2.706.71-5.589,1.065-8.648,1.065-2.023,0-4.037-.157-6.045-.471-2.009-.314-3.908-.861-5.697-1.64-1.79-.778-3.395-1.837-4.816-3.175-1.421-1.34-2.555-3.021-3.402-5.042l8.074-3.525c.519,1.202,1.202,2.193,2.049,2.971.847.779,1.797,1.408,2.848,1.885,1.051.479,2.172.814,3.361,1.005s2.398.287,3.628.287c1.885,0,3.572-.232,5.062-.696,1.489-.466,2.752-1.169,3.79-2.111,1.039-.943,1.838-2.132,2.399-3.566.559-1.434.839-3.107.839-5.02v-6.393c-.71,1.229-1.592,2.336-2.643,3.319-1.053.983-2.207,1.824-3.464,2.52s-2.582,1.237-3.976,1.62c-1.393.383-2.814.574-4.263.574-3.033,0-5.737-.56-8.114-1.681-2.377-1.119-4.379-2.636-6.005-4.55-1.625-1.912-2.862-4.139-3.709-6.68-.847-2.542-1.27-5.233-1.27-8.074,0-2.814.451-5.491,1.353-8.033.901-2.542,2.192-4.775,3.873-6.702,1.68-1.927,3.709-3.464,6.086-4.611,2.376-1.147,5.054-1.721,8.033-1.721,2.923,0,5.621.594,8.094,1.782,2.472,1.189,4.473,3.082,6.004,5.677v-6.557h10.246v39.674Zm-33.198-19.017c0,1.666.252,3.265.758,4.795s1.237,2.876,2.193,4.037c.957,1.162,2.137,2.084,3.545,2.767s3.013,1.025,4.816,1.025c2.021,0,3.784-.355,5.287-1.066,1.502-.711,2.746-1.673,3.729-2.89.985-1.215,1.722-2.643,2.213-4.283.492-1.64.738-3.374.738-5.206,0-1.802-.239-3.49-.716-5.062-.479-1.57-1.203-2.93-2.173-4.077s-2.179-2.056-3.626-2.726c-1.449-.67-3.157-1.005-5.123-1.005-2.049,0-3.812.363-5.287,1.086-1.476.724-2.684,1.709-3.628,2.951-.943,1.243-1.633,2.699-2.069,4.365-.438,1.666-.656,3.429-.656,5.287Z"/>
<path d="m277.096,9.555c0,.847-.151,1.633-.451,2.356-.3.724-.716,1.34-1.25,1.844-.532.507-1.167.902-1.905,1.189s-1.53.431-2.377.431c-.819,0-1.598-.144-2.336-.431s-1.388-.69-1.947-1.209c-.56-.519-.998-1.133-1.311-1.844-.315-.711-.471-1.489-.471-2.336s.156-1.626.471-2.336c.314-.711.744-1.325,1.291-1.845.546-.519,1.187-.922,1.925-1.209s1.53-.431,2.377-.431c.821,0,1.598.144,2.336.431s1.373.69,1.907,1.209c.532.52.955,1.134,1.27,1.845.314.71.471,1.489.471,2.336Zm-.778,12.705v42.871h-10.246V22.261h10.246Z"/>
<path d="m308.451,29.801c-1.585,0-2.999.24-4.243.718-1.243.479-2.288,1.162-3.135,2.049-.847.889-1.496,1.961-1.947,3.217-.451,1.258-.676,2.651-.676,4.181v25.165h-10.246V22.261h10.246v6.803c.683-1.338,1.537-2.492,2.562-3.462,1.025-.97,2.165-1.769,3.422-2.399,1.257-.627,2.59-1.091,3.997-1.393,1.406-.3,2.82-.451,4.241-.451,2.623,0,4.884.431,6.783,1.291s3.464,2.049,4.694,3.565c1.229,1.517,2.131,3.307,2.704,5.37s.861,4.311.861,6.742v26.805h-10.328v-25.822c0-3.005-.711-5.341-2.132-7.008-1.421-1.666-3.688-2.5-6.803-2.5Z"/>
</g>
<g>
<path d="m152.871,102.12c0,1.138-.168,2.221-.507,3.25-.337,1.028-.828,1.935-1.471,2.72s-1.436,1.41-2.379,1.874-2.021.696-3.234.696c-.579,0-1.155-.061-1.723-.183-.569-.121-1.107-.306-1.613-.553-.505-.247-.974-.561-1.407-.941s-.801-.822-1.107-1.328v2.72h-2.625v-24.446h2.625v10.689c.273-.464.632-.882,1.076-1.257.442-.374.93-.696,1.463-.964.531-.27,1.082-.477,1.652-.626.569-.146,1.122-.22,1.66-.22,1.244,0,2.34.227,3.289.679.95.454,1.743,1.068,2.38,1.843s1.117,1.685,1.44,2.728c.321,1.044.482,2.151.482,3.321Zm-13.536.126c0,.917.123,1.756.371,2.515.249.759.614,1.415,1.1,1.968.485.553,1.079.984,1.787,1.289.706.306,1.517.459,2.435.459.991,0,1.813-.178,2.467-.53.653-.354,1.178-.828,1.573-1.424.395-.595.674-1.283.838-2.063.163-.78.245-1.603.245-2.467,0-.801-.104-1.576-.308-2.325-.206-.748-.52-1.415-.941-1.999-.422-.586-.958-1.055-1.605-1.407-.648-.354-1.415-.53-2.3-.53-.981,0-1.827.174-2.538.521-.711.349-1.3.818-1.764,1.409-.464.59-.806,1.28-1.028,2.071s-.332,1.629-.332,2.514Z"/>
<path d="m169.949,93.834l-9.141,22.297h-2.656l3.131-7.464-6.388-14.833h2.814l4.965,11.86,4.586-11.86h2.689Z"/>
<path d="m194.11,108.034v2.34h-16.414v-1.139l13.189-19.228h-12.05v-2.246h15.465v1.139l-12.84,19.134h12.65Z"/>
<path d="m213.229,102.215c0,1.202-.206,2.319-.617,3.352-.411,1.034-.986,1.927-1.723,2.681-.739.753-1.611,1.344-2.618,1.77-1.007.428-2.106.641-3.296.641-1.256,0-2.388-.222-3.4-.665s-1.874-1.053-2.585-1.834-1.257-1.697-1.637-2.752c-.38-1.053-.57-2.192-.57-3.416,0-1.191.201-2.3.601-3.329.4-1.028.964-1.92,1.692-2.68.727-.759,1.594-1.354,2.601-1.787s2.116-.648,3.329-.648c1.254,0,2.391.22,3.408.663s1.881,1.055,2.593,1.835,1.26,1.697,1.644,2.751c.385,1.055.578,2.192.578,3.416Zm-13.726.031c0,.886.117,1.708.349,2.467s.579,1.418,1.043,1.977c.464.558,1.038.995,1.723,1.311.685.317,1.481.476,2.388.476.938,0,1.753-.175,2.443-.522.691-.349,1.263-.816,1.717-1.407.452-.591.79-1.275,1.012-2.056.22-.78.332-1.602.332-2.466,0-.844-.117-1.646-.349-2.404-.232-.759-.579-1.429-1.043-2.008s-1.038-1.038-1.723-1.376c-.685-.337-1.481-.505-2.388-.505-.971,0-1.802.174-2.498.521-.696.349-1.265.82-1.708,1.416-.443.595-.77,1.288-.981,2.078-.21.792-.316,1.624-.316,2.498Z"/>
<path d="m224.423,95.827c-.696,0-1.323.105-1.881.316s-1.034.512-1.423.902c-.391.39-.691.864-.902,1.423s-.316,1.186-.316,1.881v10.026h-2.625v-24.446h2.625v10.531c.253-.516.564-.956.933-1.32s.777-.663,1.226-.902c.447-.237.933-.411,1.454-.521.522-.111,1.057-.166,1.605-.166,1.033,0,1.937.171,2.712.513.775.343,1.423.818,1.945,1.424.522.605.915,1.326,1.178,2.157.263.833.395,1.745.395,2.735v9.994h-2.625v-10.184c0-1.423-.36-2.506-1.083-3.25-.722-.742-1.795-1.114-3.217-1.114Z"/>
<path d="m251.685,102.215c0,1.202-.206,2.319-.617,3.352-.411,1.034-.986,1.927-1.723,2.681-.739.753-1.611,1.344-2.618,1.77-1.007.428-2.106.641-3.296.641-1.256,0-2.388-.222-3.4-.665s-1.874-1.053-2.585-1.834-1.257-1.697-1.637-2.752c-.38-1.053-.57-2.192-.57-3.416,0-1.191.201-2.3.601-3.329.4-1.028.964-1.92,1.692-2.68.727-.759,1.594-1.354,2.601-1.787s2.116-.648,3.329-.648c1.254,0,2.391.22,3.408.663s1.881,1.055,2.593,1.835,1.26,1.697,1.644,2.751c.385,1.055.578,2.192.578,3.416Zm-13.726.031c0,.886.117,1.708.349,2.467s.579,1.418,1.043,1.977c.464.558,1.038.995,1.723,1.311.685.317,1.481.476,2.388.476.938,0,1.753-.175,2.443-.522.691-.349,1.263-.816,1.717-1.407.452-.591.79-1.275,1.012-2.056.22-.78.332-1.602.332-2.466,0-.844-.117-1.646-.349-2.404-.232-.759-.579-1.429-1.043-2.008s-1.038-1.038-1.723-1.376c-.685-.337-1.481-.505-2.388-.505-.971,0-1.802.174-2.498.521-.696.349-1.265.82-1.708,1.416-.443.595-.77,1.288-.981,2.078-.21.792-.316,1.624-.316,2.498Z"/>
<path d="m281.097,103.923c-.38.959-.884,1.85-1.511,2.672-.627.823-1.346,1.534-2.157,2.135-.812.601-1.703,1.073-2.673,1.415-.969.342-1.976.514-3.02.514-1.76,0-3.312-.295-4.656-.886-1.345-.59-2.472-1.407-3.385-2.45-.912-1.044-1.603-2.279-2.072-3.709-.469-1.428-.704-2.98-.704-4.657,0-1.033.114-2.037.341-3.013.227-.974.553-1.889.98-2.743.428-.854.95-1.637,1.565-2.348.617-.711,1.318-1.32,2.104-1.827.785-.505,1.652-.901,2.601-1.186.949-.284,1.961-.426,3.036-.426,1.012,0,2.003.148,2.973.442.971.295,1.866.718,2.689,1.266.822.548,1.55,1.209,2.182,1.984s1.127,1.642,1.486,2.602l-2.246.98c-.295-.768-.673-1.468-1.13-2.095-.459-.627-.989-1.162-1.59-1.604-.601-.443-1.265-.785-1.992-1.029-.728-.242-1.508-.363-2.341-.363-1.359,0-2.532.268-3.518.806s-1.797,1.254-2.435,2.151c-.638.895-1.107,1.919-1.407,3.067-.301,1.149-.451,2.335-.451,3.558,0,1.244.166,2.424.498,3.543.333,1.117.833,2.098,1.503,2.94.669.844,1.507,1.513,2.514,2.008,1.007.496,2.18.744,3.518.744.801,0,1.576-.143,2.325-.428.749-.284,1.44-.671,2.072-1.162.632-.49,1.191-1.064,1.675-1.723.485-.658.864-1.357,1.139-2.095l2.088.917Z"/>
<path d="m287.991,100.539v9.835h-2.751v-22.613h7.431c1.044,0,2.042.111,2.997.332.954.222,1.795.586,2.522,1.092.728.505,1.307,1.168,1.74,1.984.431.818.648,1.822.648,3.013,0,.885-.137,1.673-.411,2.364-.275.691-.66,1.289-1.155,1.795-.496.507-1.086.925-1.771,1.257-.685.333-1.44.583-2.261.752l6.926,10.026h-3.068l-6.736-9.835h-4.112Zm0-2.183h4.871c.727,0,1.393-.075,1.999-.228s1.131-.402,1.574-.744c.442-.342.785-.785,1.028-1.328s.363-1.21.363-2.001c0-.801-.126-1.466-.378-1.992-.254-.527-.601-.943-1.044-1.25-.443-.305-.967-.521-1.573-.648s-1.262-.189-1.968-.189h-4.871v8.38Z"/>
<path d="m308.231,91.335v19.039h-2.529v-22.613h3.826l7.242,17.932,7.148-17.932h3.795v22.613h-2.752v-19.039l-7.653,19.039h-1.17l-7.907-19.039Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 112 KiB