Compare commits

...

218 Commits

Author SHA1 Message Date
Faruk AYDIN
fedbd66f8e Release v.0.5.0 2023-02-08 12:42:38 +01:00
Faruk AYDIN
2be8e14f66 feat(http-request): cover file downloads 2023-02-07 21:48:52 +01:00
Faruk AYDIN
9cfaa9e603 feat(salesforce): Implement create attachment integration 2023-02-07 21:15:44 +01:00
Ali BARIN
48653c7590 feat(slack/list-channels): add private and exclude archived channels 2023-02-06 00:47:41 +01:00
Ömer Faruk Aydın
72450b6305 Merge pull request #872 from automatisch/primitive-custom-http-request
feat(http-request): introduce custom request action
2023-02-06 00:21:37 +01:00
dependabot[bot]
7d22a1c105 chore(deps): bump http-cache-semantics from 4.1.0 to 4.1.1
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-04 12:58:23 +01:00
Ali BARIN
08ac3fb984 docs(http-request): add custom request action 2023-02-02 22:34:42 +00:00
Ali BARIN
2f64a074c6 feat(http-request): introduce custom request action 2023-02-02 22:30:07 +00:00
Donghoon Song
f98c797311 fix: readme git clone commannd
Current command needs public key so access is denied.
2023-02-01 22:12:45 +01:00
Ömer Faruk Aydın
d81fb14b04 Merge pull request #870 from automatisch/slack-search-user-by-email
feat(slack): add find user by email action
2023-01-31 15:15:37 +01:00
Ali BARIN
01bb1259eb feat(slack): add find user by email action 2023-01-30 23:39:00 +00:00
Ali BARIN
1118d025bf chore: add hostRequirements in devcontainer 2023-01-31 00:23:50 +01:00
Ali BARIN
146f0604c3 docs(salesforce): add find record action 2023-01-31 00:19:51 +01:00
Ali BARIN
f90afe8b37 feat(salesforce): add find record action 2023-01-31 00:19:51 +01:00
Ali BARIN
fff5306fa6 chore: introduce .devcontainer 2023-01-30 13:47:30 +01:00
Ali BARIN
078ea24cd2 feat: request increase body size limit to 1mb 2023-01-29 13:53:32 +01:00
Ali BARIN
85a3558074 docs(ntfy): use actions page for app listing 2023-01-25 11:58:52 +01:00
Ali BARIN
73a9ae1c9c docs(twitter): remove duplicate items 2023-01-25 11:26:19 +01:00
dependabot[bot]
2222ede420 chore(deps): bump knex from 0.95.15 to 2.4.0
Bumps [knex](https://github.com/knex/knex) from 0.95.15 to 2.4.0.
- [Release notes](https://github.com/knex/knex/releases)
- [Changelog](https://github.com/knex/knex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/knex/knex/commits/2.4.0)

---
updated-dependencies:
- dependency-name: knex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-20 18:01:10 +01:00
Ömer Faruk Aydın
c6d80a9b0e Merge pull request #856 from automatisch/search-user-in-twitter
feat(twitter): add search user action
2023-01-20 15:38:26 +03:00
Ömer Faruk Aydın
23c4414398 Merge pull request #852 from automatisch/openai-send-prompt
feat(openai): add send prompt action
2023-01-20 15:14:05 +03:00
Ömer Faruk Aydın
8b9320bbf9 Merge pull request #851 from automatisch/openai-check-moderation
feat(openai): add moderation action
2023-01-20 15:07:45 +03:00
Katriel Tsepelevish
a8ac288f17 fix(todoist): Add missing OAuth redirect URL field 2023-01-19 18:42:44 +01:00
Ali BARIN
ffe7de6774 docs(twitter): add search user action 2023-01-19 17:56:58 +01:00
Ali BARIN
d87a826493 feat(twitter): sign querystring in requests 2023-01-19 17:56:39 +01:00
Ali BARIN
645fe29060 feat(twitter): add search user action 2023-01-19 17:55:59 +01:00
Ali BARIN
4db738a7f6 docs(openai): add send prompt action 2023-01-18 22:41:53 +01:00
Ali BARIN
253c2c4317 feat(openai): add send prompt action 2023-01-18 22:41:53 +01:00
Ali BARIN
49755303f7 feat(openai): add list models dynamic data 2023-01-18 22:41:53 +01:00
Ali BARIN
1e137f0bd8 docs(openai): describe auth and check moderation action 2023-01-18 22:41:35 +01:00
Ali BARIN
c2579b1850 feat(openai): add moderation action 2023-01-18 22:41:34 +01:00
Ali BARIN
577d5215cd feat(openai): add app with auth 2023-01-18 22:41:34 +01:00
Ali BARIN
0870fa7e8f fix(typeform): add HTTP 403 to refresh token 2023-01-18 22:41:10 +01:00
Katriel Tsepelevish
ddb3795985 chore(backend): Provide HTTP url on server launch up 2023-01-15 17:24:22 +01:00
Ali BARIN
45e98cd5b7 fix(Editor): fetch webhookUrl upon updating step 2023-01-14 19:15:55 +01:00
Faruk AYDIN
4a99b7a3f2 chore: Update version in Dockerfiles with 0.4.0 2023-01-13 17:09:49 +01:00
Faruk AYDIN
985132da78 Release v0.4.0 2023-01-13 17:09:49 +01:00
Ali BARIN
315edea5ca docs(twitter): add missing space after comma 2023-01-11 22:05:39 +01:00
Ali BARIN
27e0ef4e38 docs(todoist): describe auth with oauth 2.0 2023-01-11 22:05:39 +01:00
Ali BARIN
8090d8be5a feat(todoist): enhance auth with oauth 2.0 2023-01-11 22:05:39 +01:00
Ali BARIN
8c8fd98bd5 feat(rss): cover atom feeds 2023-01-11 20:04:02 +01:00
dependabot[bot]
6f724b5bec chore(deps): bump luxon from 2.5.0 to 2.5.2
Bumps [luxon](https://github.com/moment/luxon) from 2.5.0 to 2.5.2.
- [Release notes](https://github.com/moment/luxon/releases)
- [Changelog](https://github.com/moment/luxon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moment/luxon/compare/2.5.0...2.5.2)

---
updated-dependencies:
- dependency-name: luxon
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 15:47:28 +01:00
Ali BARIN
909cbd1f0c fix(google-forms): platform name in OAuth field description 2023-01-09 14:09:33 +01:00
Ali BARIN
094de0ca21 fix(google-forms): remove unused and wrong docUrl in auth 2023-01-09 14:09:33 +01:00
dependabot[bot]
af8ca4af9e chore(deps): bump json5 from 1.0.1 to 1.0.2
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-07 16:23:57 +01:00
Ali BARIN
709e788f5f docs(todoist): restructure trigger and add in nav 2023-01-07 16:12:47 +01:00
Ian Levesque
1a4a1f7f8b feat(todoist): add app, authentication, docs (#826) 2023-01-07 15:09:39 +01:00
Ömer Faruk Aydın
ff0bde059a Merge pull request #825 from automatisch/google-forms-integration
Add google forms
2023-01-05 19:50:33 +03:00
Ali BARIN
ac671110a3 fix: wrap lines when showing error details 2023-01-03 21:24:29 +01:00
Ali BARIN
30c95da90e feat(google-forms): add new form responses trigger 2023-01-03 21:24:27 +01:00
Ali BARIN
0b52a1bd01 feat(google-forms): add list forms dynamic data 2023-01-03 21:23:35 +01:00
Ali BARIN
3fc7fce9ca feat(google-forms): add authentication 2023-01-03 19:06:04 +01:00
Ali BARIN
f8df7987b8 feat(google-forms): add primitive app 2023-01-03 19:02:56 +01:00
Ali BARIN
697594b63e Merge pull request #815 from automatisch/dependabot/npm_and_yarn/jsonwebtoken-9.0.0
chore(deps): bump jsonwebtoken from 8.5.1 to 9.0.0
2022-12-28 11:52:51 +01:00
dependabot[bot]
7be3923224 chore(deps): bump jsonwebtoken from 8.5.1 to 9.0.0
Bumps [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) from 8.5.1 to 9.0.0.
- [Release notes](https://github.com/auth0/node-jsonwebtoken/releases)
- [Changelog](https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/node-jsonwebtoken/compare/v8.5.1...v9.0.0)

---
updated-dependencies:
- dependency-name: jsonwebtoken
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-28 10:35:59 +00:00
Ömer Faruk Aydın
5b913aa30a Merge pull request #818 from automatisch/handle-different-content-types-in-webhook
feat(webhooks): handle form-data and text/plain reqs
2022-12-28 13:35:02 +03:00
Ali BARIN
da9cb7d6eb feat(webhooks): handle form-data and text/plain reqs 2022-12-25 16:28:58 +01:00
Ali BARIN
aca19f7f73 Merge pull request #814 from automatisch/docs/create-flow
docs: Add the guide for how to create flows
2022-12-22 23:21:07 +01:00
Faruk AYDIN
faf151cd62 docs: Add the guide for how to create flows 2022-12-23 01:02:35 +03:00
Ömer Faruk Aydın
675cd4de2a Merge pull request #813 from automatisch/docs/ngrok-usage
docs: Add usage of ngrok for webhook-based trigger development
2022-12-21 23:10:03 +03:00
Faruk AYDIN
74ebe492c5 docs: Add usage of ngrok for webhook-based trigger development 2022-12-21 23:07:40 +03:00
Ali BARIN
254fcecf33 Merge pull request #811 from automatisch/chore/dockerfile
chore: Cover different architectures in Dockerfile
2022-12-17 18:45:51 +01:00
Faruk AYDIN
a334864980 chore: Cover different architectures in Dockerfile 2022-12-17 20:40:44 +03:00
Ömer Faruk Aydın
b6b377c209 Merge pull request #809 from automatisch/docs/change-advantages-copy
docs: Update advantages section of Automatisch
2022-12-17 16:46:56 +03:00
Faruk AYDIN
5f76aa02dd docs: Adjust advantages text of Automatisch 2022-12-17 16:29:41 +03:00
Ömer Faruk Aydın
0ba0c998e9 Merge pull request #810 from automatisch/readme/installation
chore: Update readme to refer installation guide
2022-12-17 03:12:36 +03:00
Faruk AYDIN
2e54216469 chore: Update readme to refer installation guide 2022-12-17 02:05:09 +03:00
Faruk AYDIN
56dbe62cad docs: Update advantages section of Automatisch 2022-12-17 01:37:59 +03:00
Ömer Faruk Aydın
048db60a10 Merge pull request #808 from automatisch/docs/delay-app
docs: Add connection and actions pages for delay app
2022-12-17 01:09:35 +03:00
Faruk AYDIN
f3b1b2254f docs: Add connection and actions pages for delay app 2022-12-17 01:04:50 +03:00
Ali BARIN
e705aaa2f6 Merge pull request #807 from automatisch/docs/configuration
docs: Add WEB_APP_URL and WEBHOOK_URL to configuration
2022-12-16 23:02:17 +01:00
Faruk AYDIN
1f80f843ba docs: Add WEB_APP_URL and WEBHOOK_URL to configuration 2022-12-17 00:54:49 +03:00
Ömer Faruk Aydın
02a76418fc Merge pull request #806 from automatisch/add-flowers-software
Add flowers software
2022-12-17 00:33:06 +03:00
Ömer Faruk Aydın
d1245705de Merge pull request #805 from automatisch/revise-web-app-url
feat: prioritize WEB_APP_URL
2022-12-16 23:12:09 +03:00
Ali BARIN
6d74f7c64d feat(flowers-software): add new activity trigger 2022-12-16 21:06:54 +01:00
Ali BARIN
bf1076b7d2 fix(AddAppConnection): don't render empty error details 2022-12-16 21:06:53 +01:00
Ali BARIN
7175d92eaf feat(flowers-software): add app with authentication 2022-12-16 21:06:53 +01:00
Ali BARIN
f30ac46672 feat($): add flow.setRemoteWebhookId 2022-12-16 21:06:52 +01:00
Ali BARIN
0970db3295 feat: add remoteWebhookId in Flow 2022-12-16 21:06:52 +01:00
Ali BARIN
5d24216124 feat: prioritize WEB_APP_URL 2022-12-16 21:06:40 +01:00
Ali BARIN
9a55333ce8 Merge pull request #804 from automatisch/delay-until-action
feat: Add delay until action for delay app
2022-12-16 20:16:10 +01:00
Faruk AYDIN
cb58ab5fb7 feat: Add delay until action for delay app 2022-12-16 20:13:39 +01:00
Ali BARIN
5d9ed13003 Merge pull request #801 from automatisch/delay-app
feat: Add delay application along with delay for action
2022-12-16 20:12:06 +01:00
Ali BARIN
5b51cb30f5 refactor: use step.appKey to recognize delay 2022-12-16 19:54:55 +01:00
Ali BARIN
d8c5850eaa Merge pull request #793 from automatisch/issue-788
feat: take search bar out of scroll in add app connection
2022-12-16 16:36:26 +01:00
Rıdvan Akca
4839b100cb feat: take search bar out of scroll in add app connection 2022-12-16 16:33:46 +01:00
Faruk AYDIN
469050914b feat: Add delay application along with delay for action 2022-12-16 02:32:57 +03:00
Ali BARIN
8036d20bf9 Merge pull request #794 from automatisch/fix-broken-flow-editor
fix: make type optional for webhook check
2022-12-12 15:57:30 +01:00
Ali BARIN
f04597335f fix: make type optional for webhook check 2022-12-12 15:54:36 +01:00
Ali BARIN
3d26ca6cc2 Merge pull request #792 from automatisch/available-apps
docs: Add webhooks to available apps
2022-12-12 14:15:05 +01:00
Faruk AYDIN
ec3454291b docs: Add webhooks to available apps 2022-12-12 16:08:04 +03:00
Ali BARIN
21e2f394a9 Merge pull request #791 from automatisch/docs/render-deployment
docs: render deployment
2022-12-12 12:00:41 +01:00
Faruk AYDIN
dd9f69e4cd docs: Add installation type for render 2022-12-12 13:43:04 +03:00
Faruk AYDIN
f7e8cb24ee feat: Add render.yaml for easy deployment to Render 2022-12-12 12:29:36 +03:00
Ömer Faruk Aydın
3b5a77ec22 Merge pull request #790 from automatisch/docs/github-stars
docs: Add cta for github stars
2022-12-12 11:56:43 +03:00
Ali BARIN
16715129d1 docs: fix mobile nav for GH stars announcement 2022-12-11 18:14:21 +01:00
Faruk AYDIN
3aafaabda6 docs: Add cta for github stars 2022-12-11 15:55:16 +03:00
Ali BARIN
279abfedfd Merge pull request #789 from automatisch/issue-760
feat: show "instant" chip for webhook triggers
2022-12-10 16:46:55 +01:00
Ali BARIN
e77580dd35 feat: show "instant" chip for webhook triggers 2022-12-10 16:39:25 +01:00
Ali BARIN
9cde662092 feat(grapql-schema): add type property in Trigger 2022-12-10 16:39:24 +01:00
Ali BARIN
862734c572 Merge pull request #784 from automatisch/dependabot/npm_and_yarn/express-4.17.3
chore(deps): bump express from 4.16.4 to 4.17.3
2022-12-08 23:09:25 +01:00
Ali BARIN
61dc611588 Merge pull request #787 from automatisch/fix-generic-webhook-internal-id-for-get-reqs
fix(webhook): correct internal ID for GET requests
2022-12-08 23:09:06 +01:00
Ali BARIN
03368e2cca fix(webhook): correct internal ID for GET requests 2022-12-08 22:19:45 +01:00
Ali BARIN
6382325280 feat(TestSubstep): put some space between info and test output 2022-12-08 22:19:00 +01:00
dependabot[bot]
a5b0910b60 chore(deps): bump express from 4.16.4 to 4.17.3
Bumps [express](https://github.com/expressjs/express) from 4.16.4 to 4.17.3.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.16.4...4.17.3)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-08 19:19:13 +00:00
Ali BARIN
ba1e1ef20c Merge pull request #786 from automatisch/release/0.3.0
Release v0.3.0
2022-12-08 20:18:27 +01:00
Ali BARIN
dd8bab299d chore: update cli version in dockerfiles 2022-12-08 20:15:06 +01:00
Ali BARIN
1125f31810 Release v0.3.0 2022-12-08 20:12:28 +01:00
Ali BARIN
ef3c93a907 Merge pull request #785 from automatisch/docs/webhooks
Docs: webhooks app
2022-12-08 20:02:53 +01:00
Faruk AYDIN
89bcaa96ed docs: Add trigger and connection pages of webhooks app 2022-12-08 22:00:17 +03:00
Ali BARIN
ce1eecf82e Merge pull request #782 from automatisch/docs/docker-installation
docs: Docker installation
2022-12-08 19:45:52 +01:00
Ali BARIN
3164663b4f Merge pull request #783 from automatisch/ntfy-field-descs
feat(ntfy): describe user & psswd in auth dialog
2022-12-08 19:45:11 +01:00
Ali BARIN
4f99bc36d0 Merge pull request #781 from automatisch/dependabot/npm_and_yarn/decode-uri-component-0.2.2
chore(deps): bump decode-uri-component from 0.2.0 to 0.2.2
2022-12-08 19:45:00 +01:00
Ali BARIN
179c0a39d4 feat(ntfy): describe user & psswd in auth dialog 2022-12-08 19:36:41 +01:00
Faruk AYDIN
0fefa4e43a chore: Make telegram and ntfy apps collapsed for docs sidebar 2022-12-08 21:31:23 +03:00
Ömer Faruk Aydın
d4e8eb276d Merge pull request #780 from automatisch/generic-webhook
Add webhook integration
2022-12-08 19:20:52 +01:00
Ömer Faruk Aydın
fd3c26ad73 Merge pull request #777 from automatisch/feature/ntfy
Add ntfy support with sending message
2022-12-08 19:13:57 +01:00
Ali BARIN
d9f9056515 refactor(webhook): remove auth placeholder 2022-12-08 11:57:36 +01:00
Faruk AYDIN
d326b5a36a chore: Add migration for webhook secret key 2022-12-08 13:27:08 +03:00
Faruk AYDIN
8c4970b550 chore: Use webhook secret key for new entry trigger 2022-12-08 13:00:17 +03:00
Ali BARIN
51ccdf3577 feat(webhook): do not process actions in test run 2022-12-08 10:42:35 +01:00
Ali BARIN
f79245d24a fix(webhook): remove registrations logic 2022-12-08 10:26:07 +01:00
Ali BARIN
e8d8a5e89d feat(webhook): mark test run in executions 2022-12-08 10:22:39 +01:00
Faruk AYDIN
b1dddcb511 docs: Add installation types info box 2022-12-08 10:33:15 +03:00
Faruk AYDIN
af45b8a1e4 docs: Adjust docker setup to use one .env file 2022-12-08 10:33:15 +03:00
Faruk AYDIN
2c8b60ab9b chore: Remove project flag from docker compose command 2022-12-08 10:33:15 +03:00
Faruk AYDIN
75196cbf84 feat: Introduce webhook secret key to verify webhook requests 2022-12-08 10:33:15 +03:00
Faruk AYDIN
5d80fd523c docs: Remind to change password after installation 2022-12-08 10:33:15 +03:00
Faruk AYDIN
22dc61f39b docs: Add docker installation section 2022-12-08 10:33:15 +03:00
dependabot[bot]
f4611d88cd chore(deps): bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-08 01:56:18 +00:00
Ali BARIN
346a706e41 feat(Editor): show webhook info in test substep 2022-12-08 00:34:28 +01:00
Ali BARIN
3c62f182ab feat(webhook): add webhook application 2022-12-08 00:34:26 +01:00
Ömer Faruk Aydın
67964192de Merge pull request #778 from automatisch/worker-readiness-log
feat(worker): log when workers are ready
2022-12-06 18:37:51 +01:00
Ömer Faruk Aydın
c6f62fd078 Merge pull request #779 from automatisch/barinali-patch-1
docs(available-apps): fix telegram link
2022-12-06 18:17:50 +01:00
Ali BARIN
8ea547c1d7 docs(available-apps): fix telegram link 2022-12-06 18:14:21 +01:00
Ali BARIN
c5fedda195 feat(worker): log when workers are ready 2022-12-05 23:53:57 +01:00
Ali BARIN
8300a4b6df docs: add ntfy in available apps 2022-12-05 09:57:42 +01:00
Ali BARIN
32e77de8bb docs(ntfy): describe actions and auth 2022-12-05 00:52:13 +01:00
Ali BARIN
e1c080f237 feat(ntfy): add send message action 2022-12-05 00:45:30 +01:00
Ali BARIN
6995323a45 feat(ntfy): add auth support 2022-12-05 00:45:02 +01:00
Ali BARIN
46bfc597ec feat(ntfy): add application 2022-12-05 00:44:25 +01:00
Ömer Faruk Aydın
0abc614a78 Merge pull request #775 from automatisch/fix-autocomplete-search
fix(ControlledAutocomplete): use option value as option key
2022-12-04 22:51:56 +01:00
Ömer Faruk Aydın
7518456fe8 Merge pull request #776 from automatisch/add-option-value-in-autocomplete
feat(FlowSubstep): show autocomplete option value
2022-12-04 22:46:25 +01:00
Ali BARIN
4ab76e7507 feat(FlowSubstep): show autocomplete option value 2022-12-04 22:33:28 +01:00
Ömer Faruk Aydın
1cf5a88582 Merge pull request #770 from automatisch/feature/telegram-send-message
Add telegram bot support with sending message
2022-12-04 22:28:37 +01:00
Ali BARIN
14a8551e82 docs: add typeform and telegram in available apps 2022-12-04 21:26:11 +01:00
Ali BARIN
4b0916a214 fix(AppRow): use app key for links instead of name 2022-12-04 21:24:19 +01:00
Ali BARIN
e451dd2262 fix(ControlledAutocomplete): use option value as option key 2022-12-04 21:16:16 +01:00
Ali BARIN
2e4ecfab16 docs(telegram-bot): describe actions and auth 2022-12-04 17:27:59 +01:00
Ali BARIN
8c343abac5 feat(telegram-bot): add send message action 2022-12-04 17:27:59 +01:00
Ali BARIN
39ac3ff4c2 feat(telegram-bot): add authentication support 2022-12-04 17:27:58 +01:00
Ali BARIN
677880c633 feat(telegram-bot): add application 2022-12-04 17:27:58 +01:00
Ali BARIN
bd2f2cbf64 Merge pull request #761 from automatisch/docs/typeform-app
docs(typeform): Add connection and trigger pages
2022-12-01 18:22:45 +01:00
Ömer Faruk Aydın
4129264d1d Merge pull request #762 from automatisch/docs/webhook-examples
docs: Add the webhook-based trigger to integration examples
2022-12-01 18:00:49 +01:00
Faruk AYDIN
f9133a6e96 docs: Add the webhook-based trigger to integration examples 2022-12-01 17:57:38 +01:00
Faruk AYDIN
57a23946cc docs(typeform): Add connection and trigger pages 2022-12-01 17:57:07 +01:00
Ömer Faruk Aydın
6faa45ac16 Merge pull request #759 from automatisch/feature/typeform-integration
Add new entry trigger for typeform with webhook support
2022-11-30 22:06:07 +01:00
Ali BARIN
bf62ebd20a chore(typeform): add empty type definition file 2022-11-30 19:38:57 +01:00
Ali BARIN
687c6a09bc feat(webhook): register in mutation calls 2022-11-30 19:33:57 +01:00
Ali BARIN
77a7df1cff feat(webhook): process trigger in controller 2022-11-30 19:33:30 +01:00
Ali BARIN
05ce3edb80 fix(webhook): respond with 404 for non-webhook flows 2022-11-30 19:32:58 +01:00
Ali BARIN
2564d7d976 fix(typeform/new-entry): early exit when no response 2022-11-30 19:31:38 +01:00
Ali BARIN
2f06cda82b fix: remove circular serialization in GQL errors 2022-11-30 16:57:35 +01:00
Ali BARIN
945b777c3c fix(typeform): correct app color 2022-11-30 02:13:00 +01:00
Ali BARIN
d2a6c45fd6 refactor: simplify computed webhook event 2022-11-30 02:13:00 +01:00
Ali BARIN
b5436fe7fa chore: add comments in update flow status 2022-11-30 02:13:00 +01:00
Ali BARIN
82e3b40e7c refactor: remove redundant function signature 2022-11-30 02:12:59 +01:00
Ali BARIN
0f4f36c654 refactor: name webhook controller handler 2022-11-30 02:12:59 +01:00
Faruk AYDIN
d83e8dabf8 feat: Implement webhook logic along with new entry typeform trigger 2022-11-30 02:12:56 +01:00
Faruk AYDIN
397926f994 feat: Add listForms dynamic data to Typeform app 2022-11-30 02:12:26 +01:00
Faruk AYDIN
8d8a9f7c78 feat: Implement Typeform authentication 2022-11-30 02:12:25 +01:00
Ömer Faruk Aydın
40b8860e7c Merge pull request #751 from automatisch/fix/stripe-types
chore: Add type file for the stripe app
2022-11-29 22:23:08 +01:00
Faruk AYDIN
9978241329 chore: Add type file for the stripe app 2022-11-29 22:10:25 +01:00
Ömer Faruk Aydın
666a1ab81e Merge pull request #749 from PierreSchwang/feat/stripe
Feature: Stripe integration (triggers)
2022-11-29 22:06:58 +01:00
Pierre Maurice Schwang
1d6ed8d9d0 chore: align trigger key with trigger name 2022-11-29 21:32:20 +01:00
Pierre Maurice Schwang
34e2c77934 chore: address review comments 2022-11-29 20:06:17 +01:00
Pierre Maurice Schwang
f47d912074 Merge branch 'main' into feat/stripe 2022-11-28 19:28:33 +01:00
Pierre Maurice Schwang
f25b67c81c docs: add documentation for stripe connection / triggers 2022-11-28 19:24:51 +01:00
Ali BARIN
08e60e6961 Merge pull request #747 from automatisch/issue-728
feat(queue): auto clean up complete and fail jobs
2022-11-28 17:55:25 +01:00
Ali BARIN
c393a80185 Merge branch 'main' into issue-728 2022-11-28 17:06:44 +01:00
Ali BARIN
8e28ec491c Merge pull request #748 from automatisch/issue-745
feat: accept username, password, tls for redis configuration
2022-11-28 17:06:20 +01:00
Ali BARIN
2e391cc651 feat(queue): auto clean up complete and fail jobs 2022-11-28 02:01:12 +01:00
Ali BARIN
2e0b2191c0 feat: accept username, password, tls for redis configuration 2022-11-28 01:57:43 +01:00
Ömer Faruk Aydın
4240849a2a Merge pull request #746 from automatisch/separate-dockerfile-for-release
Separate dockerfile for release
2022-11-27 23:08:38 +01:00
Ali BARIN
a0f0db1dd4 refactor(docker-compose): incorporate standalone build 2022-11-27 01:39:08 +01:00
Ali BARIN
e455497596 refactor(docker): rework for release 2022-11-27 01:39:08 +01:00
Ali BARIN
bb99dd82ba chore: remove unused wait for postgres scripts 2022-11-27 01:39:07 +01:00
Ömer Faruk Aydın
48ccddb555 Merge pull request #744 from automatisch/extend-http-error
feat(http-error): add response
2022-11-25 20:01:25 +01:00
Ali BARIN
23f56e4deb feat(http-error): add response 2022-11-25 00:49:40 +01:00
Pierre Maurice Schwang
ef27c9348b feat: stripe triggers (payout + transaction) 2022-11-24 23:23:22 +01:00
Ali BARIN
cb664b563d Merge pull request #739 from ksurl/docker-alpine
chore: switch to alpine based image
2022-11-23 00:14:20 +01:00
ksurl
53f38c583a add openssl package 2022-11-22 14:31:21 -08:00
ksurl
12622e2045 add dos2unix prestage 2022-11-22 10:56:04 -08:00
ksurl
36dfedbaab Merge remote-tracking branch 'upstream/main' into docker-alpine 2022-11-22 10:48:28 -08:00
Ali BARIN
d3a059d759 fix(docker-compose): add dos2unix 2022-11-22 17:36:55 +01:00
ksurl
9ba1351a3b refactor: use healthcheck for db, remove psql client from image (#737)
* refactor: use healthcheck for db, remove postgresql client from main image

* fix: redis dependency condition

* cleanup entrypoint.sh

* fix healthcheck command
2022-11-22 01:18:05 +01:00
ksurl
399f8ed1db switch to alpine based image 2022-11-21 16:14:06 -08:00
ksurl
d36b5e8091 fix(docker-compose): add compose image tag (#734)
* fix: update compose image tag

* fix: update image org name
2022-11-22 00:01:46 +01:00
Ömer Faruk Aydın
fc616e818a Merge pull request #736 from automatisch/docs/refresh-token
docs: Add OAuth with refresh token to example integrations
2022-11-21 23:23:35 +01:00
Faruk AYDIN
edd438c37f docs: Add OAuth with refresh token to example integrations 2022-11-21 23:15:49 +01:00
ksurl
92e5ae0ebd refactor(docker-compose): combine dockerfiles with entrypoint (#727)
* combine worker and main image, support encryption key, app secret key env, and postgres pw

* Update docker/entrypoint.sh

fix env file path

Co-authored-by: Ali BARIN <ali.barin53@gmail.com>

* add build tag, move compose to root

* add volumes

* style: remove trailing indent

* refactor(docker-compose): empty encryption env. vars

* docs(docker-compose): update compose folder

* refactor(docker-compose): remove host network

* fix(docker-compose): add environment variable keys

Co-authored-by: Ali BARIN <ali.barin53@gmail.com>
2022-11-21 20:26:44 +01:00
Faruk AYDIN
d3e13c30a6 chore: Make isRefreshTokenRequested optional for IAuth 2022-11-21 09:43:04 +01:00
Faruk AYDIN
6bf0e799a1 feat: Add isRefreshTokenRequested condition to auth in global variable 2022-11-21 09:43:04 +01:00
Ali BARIN
166dda4a4b feat(salesforce): implement refresh token logic 2022-11-21 09:43:04 +01:00
Ali BARIN
901605fd9c feat: add refresh token capability 2022-11-21 09:43:04 +01:00
dependabot[bot]
e3e8f570f8 chore(deps): bump loader-utils from 1.4.1 to 1.4.2
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-19 15:59:50 +01:00
Ali BARIN
6fdfdefe5c fix: use actual DB name in wait for postgres script 2022-11-19 13:37:36 +01:00
Faruk AYDIN
5cc1afa6de docs: Add explanation of automatic error handling for http client 2022-11-19 13:37:23 +01:00
Ali BARIN
4398570583 feat: show doc info in auth dialog in editor 2022-11-14 18:23:59 +01:00
Ömer Faruk Aydın
2e5b354f49 Merge pull request #716 from automatisch/plausible-docs
feat(docs): add plausible
2022-11-13 22:55:50 +01:00
Ali BARIN
11f96e8039 feat(docs): add plausible 2022-11-13 22:15:19 +01:00
Ömer Faruk Aydın
7ae1a079ea Merge pull request #715 from automatisch/chore/docker-compose-project-name
chore: Pass project name option to docker compose
2022-11-13 21:00:02 +01:00
Faruk AYDIN
b6d2624c4a chore: Pass project name option to docker compose 2022-11-13 20:54:31 +01:00
Ömer Faruk Aydın
51d6362863 Merge pull request #714 from automatisch/docker-compose-project-name
chore: add project name in docker compose
2022-11-13 16:30:13 +01:00
Ali BARIN
e30bfe67ed chore: add project name in docker compose 2022-11-13 16:19:11 +01:00
Faruk AYDIN
c5bcebad9a docs: Explain postgres user for db creation 2022-11-13 00:50:08 +01:00
Ömer Faruk Aydın
5deead7f94 Merge pull request #712 from automatisch/release/0.2.0
Release v0.2.0
2022-11-12 16:34:22 +01:00
Faruk AYDIN
2cff284122 chore: Update cli version in dockerfiles 2022-11-12 16:26:54 +01:00
251 changed files with 5185 additions and 623 deletions

1
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1 @@
FROM mcr.microsoft.com/vscode/devcontainers/base:ubuntu-22.04

48
.devcontainer/boot.sh Normal file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
CURRENT_DIR="$(pwd)"
BACKEND_PORT=3000
WEB_PORT=3001
echo "Configuring backend environment variables..."
cd packages/backend
rm -rf .env
echo "
HOST=localhost
PROTOCOL=http
PORT=$BACKEND_PORT
WEB_APP_URL=https://$CODESPACE_NAME-$WEB_PORT.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
APP_ENV=development
POSTGRES_DATABASE=automatisch
POSTGRES_PORT=5432
POSTGRES_HOST=postgres
POSTGRES_USERNAME=automatisch_user
POSTGRES_PASSWORD=automatisch_password
ENCRYPTION_KEY=sample_encryption_key
WEBHOOK_SECRET_KEY=sample_webhook_secret_key
APP_SECRET_KEY=sample_app_secret_key
REDIS_HOST=redis
SERVE_WEB_APP_SEPARATELY=true" >> .env
cd $CURRENT_DIR
echo "Configuring web environment variables..."
cd packages/web
rm -rf .env
echo "
PORT=$WEB_PORT
REACT_APP_GRAPHQL_URL=https://$CODESPACE_NAME-$BACKEND_PORT.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN/graphql
REACT_APP_BASE_URL=https://$CODESPACE_NAME-$WEB_PORT.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
REACT_APP_NOTIFICATIONS_URL=https://notifications.automatisch.io
" >> .env
cd $CURRENT_DIR
echo "Installing and linking dependencies..."
yarn
yarn lerna bootstrap
echo "Migrating database..."
cd packages/backend
yarn db:migrate
yarn db:seed:user
echo "Done!"

View File

@@ -0,0 +1,53 @@
{
"name": "Automatisch",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/git:1": {
"version": "latest"
},
"ghcr.io/devcontainers/features/node:1": {
"version": 16
},
"ghcr.io/devcontainers/features/common-utils:1": {
"username": "vscode",
"uid": 1000,
"gid": 1000,
"installZsh": true,
"installOhMyZsh": true,
"configureZshAsDefaultShell": true,
"upgradePackages": true
}
},
"hostRequirements": {
"cpus": 4,
"memory": "8gb",
"storage": "32gb"
},
"portsAttributes": {
"3000": {
"label": "Backend",
"onAutoForward": "silent",
"protocol": "http"
},
"3001": {
"label": "Frontend",
"onAutoForward": "silent",
"protocol": "http"
}
},
"forwardPorts": [3000, 3001],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": ["bash", ".devcontainer/boot.sh"]
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View File

@@ -0,0 +1,31 @@
version: '3.9'
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
postgres:
image: 'postgres:14.5-alpine'
environment:
- POSTGRES_DB=automatisch
- POSTGRES_USER=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
redis:
image: 'redis:7.0.4-alpine'
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:

1
.yarnrc Normal file
View File

@@ -0,0 +1 @@
network-timeout 400000

View File

@@ -10,7 +10,7 @@
There are other existing solutions in the market, like Zapier and Integromat, so you might be wondering why you should use Automatisch. There are other existing solutions in the market, like Zapier and Integromat, so you might be wondering why you should use Automatisch.
The most significant advantage of having Automatisch is keeping your data on your own servers. Not all companies want to use an automation service in the cloud, and the current open-source or self-hosted solutions mainly focus on developers rather than a user without a technical background. One of the main benefits of using Automatisch is that it allows you to store your data on your own servers, which is essential for businesses that handle sensitive user information and cannot risk sharing it with external cloud services. This is especially relevant for industries such as healthcare and finance, as well as for European companies that must adhere to the General Data Protection Regulation (GDPR).
🤓 Your contributions are vital to the development of Automatisch. As an open-source software, anyone can have an impact on how it is being developed. 🤓 Your contributions are vital to the development of Automatisch. As an open-source software, anyone can have an impact on how it is being developed.
@@ -24,16 +24,18 @@ The official documentation can be found here: [https://automatisch.io/docs](http
```bash ```bash
# Clone the repository # Clone the repository
git clone git@github.com:automatisch/automatisch.git git clone https://github.com/automatisch/automatisch.git
# Go to the repository folder # Go to the repository folder
cd automatisch/docker/compose cd automatisch
# Start # Start
docker compose up docker compose up
``` ```
You can use `user@automatisch.io` email address and `sample` password to login to Automatisch. You can also change your email and password later on from the settings page. You can use `user@automatisch.io` email address and `sample` password to login to Automatisch. Please do not forget to change your email and password from the settings page.
For other installation types, you can check the [installation](https://automatisch.io/docs/guide/installation) guide.
## Community Links ## Community Links

70
docker-compose.yml Normal file
View File

@@ -0,0 +1,70 @@
version: '3.9'
services:
main:
build:
context: ./docker
dockerfile: Dockerfile.compose
entrypoint: /compose-entrypoint.sh
ports:
- '3000:3000'
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
environment:
- HOST=localhost
- PROTOCOL=http
- PORT=3000
- APP_ENV=production
- REDIS_HOST=redis
- POSTGRES_HOST=postgres
- POSTGRES_DATABASE=automatisch
- POSTGRES_USERNAME=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
- ENCRYPTION_KEY
- WEBHOOK_SECRET_KEY
- APP_SECRET_KEY
volumes:
- automatisch_storage:/automatisch/storage
worker:
build:
context: ./docker
dockerfile: Dockerfile.compose
entrypoint: /compose-entrypoint.sh
depends_on:
- main
environment:
- APP_ENV=production
- REDIS_HOST=redis
- POSTGRES_HOST=postgres
- POSTGRES_DATABASE=automatisch
- POSTGRES_USERNAME=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
- ENCRYPTION_KEY
- WEBHOOK_SECRET_KEY
- APP_SECRET_KEY
- WORKER=true
volumes:
- automatisch_storage:/automatisch/storage
postgres:
image: 'postgres:14.5'
environment:
- POSTGRES_DB=automatisch
- POSTGRES_USER=automatisch_user
- POSTGRES_PASSWORD=automatisch_password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
redis:
image: 'redis:7.0.4'
volumes:
- redis_data:/data
volumes:
automatisch_storage:
postgres_data:
redis_data:

14
docker/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
# syntax=docker/dockerfile:1
FROM node:16-alpine
WORKDIR /automatisch
RUN apk --no-cache add --virtual build-dependencies python3 build-base
COPY ./entrypoint.sh /entrypoint.sh
RUN yarn global add @automatisch/cli@0.4.0 --network-timeout 1000000
RUN apk del build-dependencies python3 build-base
EXPOSE 3000
ENTRYPOINT ["sh", "/entrypoint.sh"]

11
docker/Dockerfile.compose Normal file
View File

@@ -0,0 +1,11 @@
# syntax=docker/dockerfile:1
FROM automatischio/automatisch:0.4.0
WORKDIR /automatisch
RUN apk add --no-cache openssl dos2unix
COPY ./compose-entrypoint.sh /compose-entrypoint.sh
RUN dos2unix /compose-entrypoint.sh
EXPOSE 3000
ENTRYPOINT ["sh", "/compose-entrypoint.sh"]

26
docker/compose-entrypoint.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
set -e
if [ ! -f /automatisch/storage/.env ]; then
>&2 echo "Saving environment variables"
ENCRYPTION_KEY="${ENCRYPTION_KEY:-$(openssl rand -base64 36)}"
WEBHOOK_SECRET_KEY="${WEBHOOK_SECRET_KEY:-$(openssl rand -base64 36)}"
APP_SECRET_KEY="${APP_SECRET_KEY:-$(openssl rand -base64 36)}"
echo "ENCRYPTION_KEY=$ENCRYPTION_KEY" >> /automatisch/storage/.env
echo "WEBHOOK_SECRET_KEY=$WEBHOOK_SECRET_KEY" >> /automatisch/storage/.env
echo "APP_SECRET_KEY=$APP_SECRET_KEY" >> /automatisch/storage/.env
fi
# initiate env. vars. from /automatisch/storage/.env file
export $(grep -v '^#' /automatisch/storage/.env | xargs)
# migration for webhook secret key, will be removed in the future.
if [[ -z "${WEBHOOK_SECRET_KEY}" ]]; then
WEBHOOK_SECRET_KEY="$(openssl rand -base64 36)"
echo "WEBHOOK_SECRET_KEY=$WEBHOOK_SECRET_KEY" >> /automatisch/storage/.env
fi
echo "Environment variables have been set!"
sh /entrypoint.sh

View File

@@ -1,46 +0,0 @@
version: '3.9'
services:
main:
build:
context: ../images/main
network: host
ports:
- '3000:3000'
depends_on:
- postgres
- redis
environment:
- HOST=localhost
- PROTOCOL=http
- PORT=3000
- APP_ENV=production
- REDIS_HOST=redis
- POSTGRES_HOST=postgres
- POSTGRES_DATABASE=automatisch
- POSTGRES_USERNAME=automatisch_user
volumes:
- automatisch_storage:/automatisch/storage
worker:
build:
context: ../images/worker
network: host
depends_on:
- main
environment:
- APP_ENV=production
- REDIS_HOST=redis
- POSTGRES_HOST=postgres
- POSTGRES_DATABASE=automatisch
- POSTGRES_USERNAME=automatisch_user
volumes:
- automatisch_storage:/automatisch/storage
postgres:
image: 'postgres:14.5'
environment:
POSTGRES_HOST_AUTH_METHOD: trust
POSTGRES_DB: automatisch
POSTGRES_USER: automatisch_user
redis:
image: 'redis:7.0.4'
volumes:
automatisch_storage:

9
docker/entrypoint.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
set -e
if [ -n "$WORKER" ]; then
automatisch start-worker
else
automatisch start
fi

View File

@@ -1,15 +0,0 @@
# syntax=docker/dockerfile:1
FROM node:16
WORKDIR /automatisch
RUN apt-get update && apt-get install -y postgresql-client
COPY ./wait-for-postgres.sh /automatisch/wait-for-postgres.sh
RUN mkdir -p /automatisch/storage
RUN touch /automatisch/storage/.env
RUN echo "ENCRYPTION_KEY=$(openssl rand -base64 36)" >> /automatisch/storage/.env
RUN echo "APP_SECRET_KEY=$(openssl rand -base64 36)" >> /automatisch/storage/.env
RUN yarn global add @automatisch/cli@0.1.5
EXPOSE 3000
CMD sh /automatisch/wait-for-postgres.sh automatisch start --env-file=/automatisch/storage/.env

View File

@@ -1,11 +0,0 @@
#!/bin/sh
set -e
until psql -h "$POSTGRES_HOST" -U "$POSTGRES_USERNAME" -d "$POSTGRES_HOST" -c '\q'; do
>&2 echo "Waiting for Postgres to be ready..."
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec "$@"

View File

@@ -1,10 +0,0 @@
# syntax=docker/dockerfile:1
FROM node:16
WORKDIR /automatisch
RUN apt-get update && apt-get install -y postgresql-client
COPY ./wait-for-postgres.sh /automatisch/wait-for-postgres.sh
RUN yarn global add @automatisch/cli@0.1.5
CMD sh /automatisch/wait-for-postgres.sh automatisch start-worker --env-file /automatisch/storage/.env

View File

@@ -1,11 +0,0 @@
#!/bin/sh
set -e
until psql -h "$POSTGRES_HOST" -U "$POSTGRES_USERNAME" -d "$POSTGRES_HOST" -c '\q'; do
>&2 echo "Waiting for Postgres to be ready..."
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec "$@"

View File

@@ -2,7 +2,7 @@
"packages": [ "packages": [
"packages/*" "packages/*"
], ],
"version": "0.2.0", "version": "0.5.0",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"command": { "command": {

View File

@@ -2,6 +2,7 @@ HOST=localhost
PROTOCOL=http PROTOCOL=http
PORT=3000 PORT=3000
WEB_APP_URL=http://localhost:3001 WEB_APP_URL=http://localhost:3001
WEBHOOK_URL=http://localhost:3000
APP_ENV=development APP_ENV=development
POSTGRES_DATABASE=automatisch_development POSTGRES_DATABASE=automatisch_development
POSTGRES_PORT=5432 POSTGRES_PORT=5432
@@ -10,8 +11,12 @@ POSTGRES_USERNAME=automatish_development_user
POSTGRES_PASSWORD= POSTGRES_PASSWORD=
POSTGRES_ENABLE_SSL=false POSTGRES_ENABLE_SSL=false
ENCRYPTION_KEY=sample-encryption-key ENCRYPTION_KEY=sample-encryption-key
WEBHOOK_SECRET_KEY=sample-webhook-key
APP_SECRET_KEY=sample-app-secret-key APP_SECRET_KEY=sample-app-secret-key
REDIS_PORT=6379 REDIS_PORT=6379
REDIS_HOST=127.0.0.1 REDIS_HOST=127.0.0.1
REDIS_USERNAME=redis_username
REDIS_PASSWORD=redis_password
REDIS_TLS=true
ENABLE_BULLMQ_DASHBOARD=false ENABLE_BULLMQ_DASHBOARD=false
SERVE_WEB_APP_SEPARATELY=true SERVE_WEB_APP_SEPARATELY=true

View File

@@ -1,6 +1,6 @@
{ {
"name": "@automatisch/backend", "name": "@automatisch/backend",
"version": "0.2.0", "version": "0.5.0",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"description": "The open source Zapier alternative. Build workflow automation without spending time and money.", "description": "The open source Zapier alternative. Build workflow automation without spending time and money.",
"scripts": { "scripts": {
@@ -22,7 +22,7 @@
"prebuild": "rm -rf ./dist" "prebuild": "rm -rf ./dist"
}, },
"dependencies": { "dependencies": {
"@automatisch/web": "^0.2.0", "@automatisch/web": "^0.5.0",
"@bull-board/express": "^3.10.1", "@bull-board/express": "^3.10.1",
"@graphql-tools/graphql-file-loader": "^7.3.4", "@graphql-tools/graphql-file-loader": "^7.3.4",
"@graphql-tools/load": "^7.5.2", "@graphql-tools/load": "^7.5.2",
@@ -37,7 +37,7 @@
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"debug": "~2.6.9", "debug": "~2.6.9",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "~4.16.1", "express": "~4.18.2",
"express-basic-auth": "^1.2.1", "express-basic-auth": "^1.2.1",
"express-graphql": "^0.12.0", "express-graphql": "^0.12.0",
"fast-xml-parser": "^4.0.11", "fast-xml-parser": "^4.0.11",
@@ -46,11 +46,12 @@
"graphql-tools": "^8.2.0", "graphql-tools": "^8.2.0",
"graphql-type-json": "^0.3.2", "graphql-type-json": "^0.3.2",
"http-errors": "~1.6.3", "http-errors": "~1.6.3",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^9.0.0",
"knex": "^0.95.11", "knex": "^2.4.0",
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"luxon": "2.3.1", "luxon": "2.5.2",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"multer": "1.4.5-lts.1",
"nodemailer": "6.7.0", "nodemailer": "6.7.0",
"oauth-1.0a": "^2.2.6", "oauth-1.0a": "^2.2.6",
"objection": "^3.0.0", "objection": "^3.0.0",
@@ -93,16 +94,17 @@
"url": "https://github.com/automatisch/automatisch/issues" "url": "https://github.com/automatisch/automatisch/issues"
}, },
"devDependencies": { "devDependencies": {
"@automatisch/types": "^0.2.0", "@automatisch/types": "^0.5.0",
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/bull": "^3.15.8", "@types/bull": "^3.15.8",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/crypto-js": "^4.0.2", "@types/crypto-js": "^4.0.2",
"@types/express": "^4.17.13", "@types/express": "^4.17.15",
"@types/http-errors": "^1.8.1", "@types/http-errors": "^1.8.1",
"@types/jsonwebtoken": "^8.5.8", "@types/jsonwebtoken": "^8.5.8",
"@types/lodash.get": "^4.4.6", "@types/lodash.get": "^4.4.6",
"@types/morgan": "^1.9.3", "@types/morgan": "^1.9.3",
"@types/multer": "1.4.7",
"@types/node": "^16.10.2", "@types/node": "^16.10.2",
"@types/nodemailer": "^6.4.4", "@types/nodemailer": "^6.4.4",
"@types/pg": "^8.6.1", "@types/pg": "^8.6.1",

View File

@@ -1,8 +1,8 @@
import createError from 'http-errors'; import createError from 'http-errors';
import express, { Request, Response, NextFunction } from 'express'; import express from 'express';
import appConfig from './config/app';
import cors from 'cors'; import cors from 'cors';
import corsOptions from './config/cors-options'; import corsOptions from './config/cors-options';
import graphQLInstance from './helpers/graphql-instance';
import morgan from './helpers/morgan'; import morgan from './helpers/morgan';
import appAssetsHandler from './helpers/app-assets-handler'; import appAssetsHandler from './helpers/app-assets-handler';
import webUIHandler from './helpers/web-ui-handler'; import webUIHandler from './helpers/web-ui-handler';
@@ -13,6 +13,8 @@ import {
serverAdapter, serverAdapter,
} from './helpers/create-bull-board-handler'; } from './helpers/create-bull-board-handler';
import injectBullBoardHandler from './helpers/inject-bull-board-handler'; import injectBullBoardHandler from './helpers/inject-bull-board-handler';
import router from './routes';
import { IRequest } from '@automatisch/types';
createBullBoardHandler(serverAdapter); createBullBoardHandler(serverAdapter);
@@ -23,15 +25,28 @@ injectBullBoardHandler(app, serverAdapter);
appAssetsHandler(app); appAssetsHandler(app);
app.use(morgan); app.use(morgan);
app.use(express.json()); app.use(
app.use(express.urlencoded({ extended: false })); express.json({
limit: appConfig.requestBodySizeLimit,
verify(req, res, buf) {
(req as IRequest).rawBody = buf;
},
})
);
app.use(express.urlencoded({
extended: false,
limit: appConfig.requestBodySizeLimit,
verify(req, res, buf) {
(req as IRequest).rawBody = buf;
},
}));
app.use(cors(corsOptions)); app.use(cors(corsOptions));
app.use('/graphql', graphQLInstance); app.use('/', router);
webUIHandler(app); webUIHandler(app);
// catch 404 and forward to error handler // catch 404 and forward to error handler
app.use(function (req: Request, res: Response, next: NextFunction) { app.use(function (req, res, next) {
next(createError(404)); next(createError(404));
}); });

View File

@@ -0,0 +1,56 @@
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Delay For',
key: 'delayFor',
description:
'Delays the execution of the next action by a specified amount of time.',
arguments: [
{
label: 'Delay for unit',
key: 'delayForUnit',
type: 'dropdown' as const,
required: true,
value: null,
description: 'Delay for unit, e.g. minutes, hours, days, weeks.',
variables: false,
options: [
{
label: 'Minutes',
value: 'minutes',
},
{
label: 'Hours',
value: 'hours',
},
{
label: 'Days',
value: 'days',
},
{
label: 'Weeks',
value: 'weeks',
},
],
},
{
label: 'Delay for value',
key: 'delayForValue',
type: 'string' as const,
required: true,
description: 'Delay for value, use a number, e.g. 1, 2, 3.',
variables: true,
},
],
async run($) {
const { delayForUnit, delayForValue } = $.step.parameters;
const dataItem = {
delayForUnit,
delayForValue,
};
$.setActionItem({ raw: dataItem });
},
});

View File

@@ -0,0 +1,28 @@
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Delay Until',
key: 'delayUntil',
description:
'Delays the execution of the next action until a specified date.',
arguments: [
{
label: 'Delay until (Date)',
key: 'delayUntil',
type: 'string' as const,
required: true,
description: 'Delay until the date. E.g. 2022-12-18',
variables: true,
},
],
async run($) {
const { delayUntil } = $.step.parameters;
const dataItem = {
delayUntil,
};
$.setActionItem({ raw: dataItem });
},
});

View File

@@ -0,0 +1,4 @@
import delayFor from './delay-for';
import delayUntil from './delay-until';
export default [delayFor, delayUntil];

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 122.88 100.6" style="enable-background:new 0 0 122.88 100.6" xml:space="preserve">
<style type="text/css">.st0{fill:#272727;} .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#000000;}</style>
<g>
<path class="st0" d="M72.58,0c6.8,0,13.3,1.36,19.23,3.81c6.16,2.55,11.7,6.29,16.33,10.92l0,0c4.63,4.63,8.37,10.17,10.92,16.34 c2.46,5.93,3.81,12.43,3.81,19.23c0,6.8-1.36,13.3-3.81,19.23c-2.55,6.16-6.29,11.7-10.92,16.33l0,0 c-4.63,4.63-10.17,8.37-16.34,10.92c-5.93,2.46-12.43,3.81-19.23,3.81c-6.8,0-13.3-1.36-19.23-3.81 c-6.15-2.55-11.69-6.28-16.33-10.92l-0.01-0.01c-4.64-4.64-8.37-10.17-10.92-16.33c-0.79-1.91-1.47-3.87-2.02-5.89 c1.05,0.1,2.12,0.15,3.2,0.15c2.05,0,4.05-0.19,6-0.54c0.32,0.97,0.67,1.93,1.06,2.87c2.09,5.05,5.17,9.6,8.99,13.43 c3.82,3.82,8.38,6.9,13.43,8.99c4.87,2.02,10.21,3.13,15.83,3.13c5.62,0,10.96-1.11,15.83-3.13c5.05-2.09,9.6-5.17,13.43-8.99 c3.82-3.82,6.9-8.38,8.99-13.43c2.02-4.87,3.13-10.21,3.13-15.83c0-5.62-1.11-10.96-3.13-15.83c-2.09-5.05-5.17-9.6-8.99-13.43 c-3.82-3.82-8.38-6.9-13.43-8.99c-4.87-2.02-10.21-3.13-15.83-3.13c-5.62,0-10.96,1.11-15.83,3.13c-0.44,0.18-0.87,0.37-1.3,0.56 c-1.65-2.61-3.66-4.97-5.95-7.02c1.25-0.65,2.53-1.24,3.84-1.79C59.28,1.36,65.78,0,72.58,0L72.58,0z M66.8,26.39 c0-1.23,0.5-2.35,1.31-3.16c0.81-0.81,1.93-1.31,3.16-1.31c1.23,0,2.35,0.5,3.16,1.31c0.81,0.81,1.31,1.93,1.31,3.16v23.47 l17.54,10.4c1.05,0.62,1.76,1.62,2.05,2.73c0.28,1.1,0.15,2.31-0.47,3.37l0,0.01l0,0c-0.62,1.05-1.62,1.76-2.73,2.05 c-1.1,0.28-2.31,0.15-3.37-0.47l-0.01,0l0,0L69.1,56.29c-0.67-0.38-1.24-0.92-1.64-1.57c-0.42-0.68-0.66-1.48-0.66-2.32V26.39 L66.8,26.39z"/>
<path class="st1" d="M27.27,3.18c15.06,0,27.27,12.21,27.27,27.27c0,15.06-12.21,27.27-27.27,27.27C12.21,57.73,0,45.52,0,30.45 C0,15.39,12.21,3.18,27.27,3.18L27.27,3.18z M24.35,41.34h5.82v5.16h-5.82V41.34L24.35,41.34L24.35,41.34z M30.17,37.77h-5.82 c-0.58-7.07-1.8-11.56-1.8-18.63c0-2.61,2.12-4.72,4.72-4.72c2.61,0,4.72,2.12,4.72,4.72C32,26.2,30.76,30.7,30.17,37.77 L30.17,37.77L30.17,37.77L30.17,37.77z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

View File

@@ -0,0 +1,14 @@
import defineApp from '../../helpers/define-app';
import actions from './actions';
export default defineApp({
name: 'Delay',
key: 'delay',
iconUrl: '{BASE_URL}/apps/delay/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/delay/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',
primaryColor: '001F52',
actions,
});

View File

@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="762.564" height="769.312" viewBox="0 0 772772" fill="none">
<g clip-path="url(#clip0_493_7535)">
<path d="M747.782 474.701C725.051 423.2 683.614 383.657 631.048 363.294L413.561 279.117L429.189 369.569L602.633 436.697C670.591 462.98 704.451 539.58 678.168 607.537C651.885 675.494 575.285 709.354 507.328 683.071C473.231 669.811 446.711 643.883 432.741 610.023C429.426 601.854 426.939 593.33 425.164 584.569L358.509 636.07C358.982 637.372 359.338 638.674 359.811 639.858C382.069 693.963 424.216 735.282 478.795 756.356C503.776 765.946 529.349 770.563 554.566 770.563C639.098 770.563 719.131 719.299 751.334 635.833C771.697 583.267 770.277 526.083 747.545 474.583L747.782 474.701Z" fill="#02AFC7"/>
<path d="M440.91 419.881L294.459 533.064C287.119 538.628 279.187 543.482 270.781 547.507C237.631 563.254 200.693 564.556 166.477 551.414C133.564 538.628 107.636 513.884 93.3109 481.563C78.9854 449.242 78.1567 413.369 90.943 380.456C103.729 347.543 128.473 321.615 160.794 307.29C190.866 294.03 224.134 292.491 255.271 302.672L241.064 219.206C147.061 207.13 53.2943 259.815 17.6583 352.042C-2.70517 404.608 -1.28446 461.792 21.4468 513.292C44.1781 564.793 85.6154 604.336 138.181 624.699C162.57 634.171 188.38 638.788 214.189 638.788C245.208 638.788 276.227 632.039 304.641 618.543C318.019 612.268 330.687 604.454 342.29 595.575L527.81 452.083L440.91 419.762V419.881Z" fill="#31DEA4"/>
<path d="M624.42 193.396C629.629 229.624 619.921 265.379 597.19 294.148C594.822 297.108 592.335 299.831 589.731 302.554L665.62 333.454C696.402 289.649 709.899 235.307 702.203 182.149C694.153 126.386 665.028 77.135 619.921 43.3933C574.932 9.76989 519.406 -4.43717 463.643 3.49511C407.88 11.5458 358.629 40.6703 324.888 85.7777C291.146 130.885 276.939 186.411 284.989 242.055L323.23 457.529L393.673 404.371L362.773 230.334C357.919 195.646 366.798 161.075 387.872 133.016C409.064 104.72 439.846 86.488 474.89 81.3972C509.935 76.4247 544.623 85.3041 572.801 106.378C601.096 127.57 619.329 158.47 624.42 193.396V193.396Z" fill="#FF5986"/>
</g>
<defs>
<clipPath id="clip0_493_7535">
<rect width="762.564" height="769.312" fill="white" transform="translate(3.33301 1.36719)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,43 @@
import verifyCredentials from './verify-credentials';
import isStillVerified from './is-still-verified';
export default {
fields: [
{
key: 'username',
label: 'Username',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'password',
label: 'Password',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'apiKey',
label: 'API Key',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified,
};

View File

@@ -0,0 +1,10 @@
import { IGlobalVariable } from '@automatisch/types';
import verifyCredentials from './verify-credentials';
const isStillVerified = async ($: IGlobalVariable) => {
await verifyCredentials($);
return true;
};
export default isStillVerified;

View File

@@ -0,0 +1,20 @@
import { IGlobalVariable } from '@automatisch/types';
import getWebhooks from '../common/get-webhooks';
const verifyCredentials = async ($: IGlobalVariable) => {
const response = await getWebhooks($);
const successful = Array.isArray(response.data);
if (!successful) {
throw new Error('Failed while authorizing!');
}
await $.auth.set({
screenName: $.auth.data.username,
username: $.auth.data.username,
password: $.auth.data.password,
apiKey: $.auth.data.apiKey,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,18 @@
import { TBeforeRequest } from '@automatisch/types';
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
const { data } = $.auth;
if (data?.username && data.password && data.apiKey) {
requestConfig.headers['x-api-key'] = data.apiKey as string;
requestConfig.auth = {
username: data.username as string,
password: data.password as string,
};
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -0,0 +1,5 @@
import type { IGlobalVariable } from "@automatisch/types";
export default async function getWebhooks($: IGlobalVariable) {
return await $.http.get('/v2/public/api/webhooks');
}

View File

@@ -0,0 +1,488 @@
const webhookFilters = [
{
label: "Contact Company Created",
value: "CONTACT_COMPANY_CREATED"
},
{
label: "Contact Company Deleted",
value: "CONTACT_COMPANY_DELETED"
},
{
label: "Contact Company Updated",
value: "CONTACT_COMPANY_UPDATED"
},
{
label: "Contact Created",
value: "CONTACT_CREATED"
},
{
label: "Contact Deleted",
value: "CONTACT_DELETED"
},
{
label: "Contact Updated",
value: "CONTACT_UPDATED"
},
{
label: "Customer Created",
value: "CUSTOMER_CREATED"
},
{
label: "Customer Updated",
value: "CUSTOMER_UPDATED"
},
{
label: "Document Deleted",
value: "DOCUMENT_DELETED"
},
{
label: "Document Downloaded",
value: "DOCUMENT_DOWNLOADED"
},
{
label: "Document Saved",
value: "DOCUMENT_SAVED"
},
{
label: "Document Updated",
value: "DOCUMENT_UPDATED"
},
{
label: "Flow Archived",
value: "FLOW_ARCHIVED"
},
{
label: "Flow Created",
value: "FLOW_CREATED"
},
{
label: "Flow Object Automation Action Created",
value: "FLOW_OBJECT_AUTOMATION_ACTION_CREATED"
},
{
label: "Flow Object Automation Action Deleted",
value: "FLOW_OBJECT_AUTOMATION_ACTION_DELETED"
},
{
label: "Flow Object Automation Created",
value: "FLOW_OBJECT_AUTOMATION_CREATED"
},
{
label: "Flow Object Automation Deleted",
value: "FLOW_OBJECT_AUTOMATION_DELETED"
},
{
label: "Flow Object Automation Updated",
value: "FLOW_OBJECT_AUTOMATION_UPDATED"
},
{
label: "Flow Object Automation Webdav Created",
value: "FLOW_OBJECT_AUTOMATION_WEBDAV_CREATED"
},
{
label: "Flow Object Automation Webdav Deleted",
value: "FLOW_OBJECT_AUTOMATION_WEBDAV_DELETED"
},
{
label: "Flow Object Automation Webdav Updated",
value: "FLOW_OBJECT_AUTOMATION_WEBDAV_UPDATED"
},
{
label: "Flow Object Created",
value: "FLOW_OBJECT_CREATED"
},
{
label: "Flow Object Deleted",
value: "FLOW_OBJECT_DELETED"
},
{
label: "Flow Object Document Added",
value: "FLOW_OBJECT_DOCUMENT_ADDED"
},
{
label: "Flow Object Document Removed",
value: "FLOW_OBJECT_DOCUMENT_REMOVED"
},
{
label: "Flow Object Resource Created",
value: "FLOW_OBJECT_RESOURCE_CREATED"
},
{
label: "Flow Object Resource Deleted",
value: "FLOW_OBJECT_RESOURCE_DELETED"
},
{
label: "Flow Object Resource Updated",
value: "FLOW_OBJECT_RESOURCE_UPDATED"
},
{
label: "Flow Object Task Condition Created",
value: "FLOW_OBJECT_TASK_CONDITION_CREATED"
},
{
label: "Flow Object Task Condition Deleted",
value: "FLOW_OBJECT_TASK_CONDITION_DELETED"
},
{
label: "Flow Object Task Condition Updated",
value: "FLOW_OBJECT_TASK_CONDITION_UPDATED"
},
{
label: "Flow Object Task Created",
value: "FLOW_OBJECT_TASK_CREATED"
},
{
label: "Flow Object Task Deleted",
value: "FLOW_OBJECT_TASK_DELETED"
},
{
label: "Flow Object Task Updated",
value: "FLOW_OBJECT_TASK_UPDATED"
},
{
label: "Flow Object Updated",
value: "FLOW_OBJECT_UPDATED"
},
{
label: "Flow Objects Connection Created",
value: "FLOW_OBJECTS_CONNECTION_CREATED"
},
{
label: "Flow Objects Connection Deleted",
value: "FLOW_OBJECTS_CONNECTION_DELETED"
},
{
label: "Flow Objects Connection Updated",
value: "FLOW_OBJECTS_CONNECTION_UPDATED"
},
{
label: "Flow Objects External Connection Created",
value: "FLOW_OBJECTS_EXTERNAL_CONNECTION_CREATED"
},
{
label: "Flow Objects External Connection Deleted",
value: "FLOW_OBJECTS_EXTERNAL_CONNECTION_DELETED"
},
{
label: "Flow Objects External Connection Updated",
value: "FLOW_OBJECTS_EXTERNAL_CONNECTION_UPDATED"
},
{
label: "Flow Objects External Connections Group Created",
value: "FLOW_OBJECTS_EXTERNAL_CONNECTIONS_GROUP_CREATED"
},
{
label: "Flow Objects External Connections Group Deleted",
value: "FLOW_OBJECTS_EXTERNAL_CONNECTIONS_GROUP_DELETED"
},
{
label: "Flow Objects External Connections Group Updated",
value: "FLOW_OBJECTS_EXTERNAL_CONNECTIONS_GROUP_UPDATED"
},
{
label: "Flow Unarchived",
value: "FLOW_UNARCHIVED"
},
{
label: "Flow Updated",
value: "FLOW_UPDATED"
},
{
label: "Note Created",
value: "NOTE_CREATED"
},
{
label: "Note Deleted",
value: "NOTE_DELETED"
},
{
label: "Note Updated",
value: "NOTE_UPDATED"
},
{
label: "Team Created",
value: "TEAM_CREATED"
},
{
label: "Team Deleted",
value: "TEAM_DELETED"
},
{
label: "Team Updated",
value: "TEAM_UPDATED"
},
{
label: "User Added To Team",
value: "USER_ADDED_TO_TEAM"
},
{
label: "User Added To Teamleads",
value: "USER_ADDED_TO_TEAMLEADS"
},
{
label: "User Archived",
value: "USER_ARCHIVED"
},
{
label: "User Changed Password",
value: "USER_CHANGED_PASSWORD"
},
{
label: "User Created",
value: "USER_CREATED"
},
{
label: "User Forgot Password",
value: "USER_FORGOT_PASSWORD"
},
{
label: "User Invited",
value: "USER_INVITED"
},
{
label: "User Logged In",
value: "USER_LOGGED_IN"
},
{
label: "User Notification Settings Changed",
value: "USER_NOTIFICATION_SETTINGS_CHANGED"
},
{
label: "User Profile Updated",
value: "USER_PROFILE_UPDATED"
},
{
label: "User Removed From Team",
value: "USER_REMOVED_FROM_TEAM"
},
{
label: "User Removed From Teamleads",
value: "USER_REMOVED_FROM_TEAMLEADS"
},
{
label: "User Unarchived",
value: "USER_UNARCHIVED"
},
{
label: "Workflow Archived",
value: "WORKFLOW_ARCHIVED"
},
{
label: "Workflow Completed",
value: "WORKFLOW_COMPLETED"
},
{
label: "Workflow Created",
value: "WORKFLOW_CREATED"
},
{
label: "Workflow Creation Failed",
value: "WORKFLOW_CREATION_FAILED"
},
{
label: "Workflow Object Automation Api Get Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_API_GET_COMPLETED"
},
{
label: "Workflow Object Automation Api Get Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_API_GET_FAILED"
},
{
label: "Workflow Object Automation Api Post Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_API_POST_COMPLETED"
},
{
label: "Workflow Object Automation Api Post Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_API_POST_FAILED"
},
{
label: "Workflow Object Automation Datev Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_DATEV_COMPLETED"
},
{
label: "Workflow Object Automation Datev Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_DATEV_FAILED"
},
{
label: "Workflow Object Automation Email Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_EMAIL_COMPLETED"
},
{
label: "Workflow Object Automation Email Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_EMAIL_FAILED"
},
{
label: "Workflow Object Automation Lexoffice Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_LEXOFFICE_COMPLETED"
},
{
label: "Workflow Object Automation Lexoffice Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_LEXOFFICE_FAILED"
},
{
label: "Workflow Object Automation Rejected",
value: "WORKFLOW_OBJECT_AUTOMATION_REJECTED"
},
{
label: "Workflow Object Automation Retried",
value: "WORKFLOW_OBJECT_AUTOMATION_RETRIED"
},
{
label: "Workflow Object Automation Sevdesk Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_SEVDESK_COMPLETED"
},
{
label: "Workflow Object Automation Sevdesk Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_SEVDESK_FAILED"
},
{
label: "Workflow Object Automation Stamp Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_STAMP_COMPLETED"
},
{
label: "Workflow Object Automation Stamp Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_STAMP_FAILED"
},
{
label: "Workflow Object Automation Task Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_TASK_COMPLETED"
},
{
label: "Workflow Object Automation Task Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_TASK_FAILED"
},
{
label: "Workflow Object Automation Template Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_TEMPLATE_COMPLETED"
},
{
label: "Workflow Object Automation Template Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_TEMPLATE_FAILED"
},
{
label: "Workflow Object Automation Webdav Document Uploaded",
value: "WORKFLOW_OBJECT_AUTOMATION_WEBDAV_DOCUMENT_UPLOADED"
},
{
label: "Workflow Object Automation Zapier Completed",
value: "WORKFLOW_OBJECT_AUTOMATION_ZAPIER_COMPLETED"
},
{
label: "Workflow Object Automation Zapier Failed",
value: "WORKFLOW_OBJECT_AUTOMATION_ZAPIER_FAILED"
},
{
label: "Workflow Object Combination Task Group Created",
value: "WORKFLOW_OBJECT_COMBINATION_TASK_GROUP_CREATED"
},
{
label: "Workflow Object Combination Task Group Deleted",
value: "WORKFLOW_OBJECT_COMBINATION_TASK_GROUP_DELETED"
},
{
label: "Workflow Object Completed Automations Finished",
value: "WORKFLOW_OBJECT_COMPLETED_AUTOMATIONS_FINISHED"
},
{
label: "Workflow Object Completed",
value: "WORKFLOW_OBJECT_COMPLETED"
},
{
label: "Workflow Object Created",
value: "WORKFLOW_OBJECT_CREATED"
},
{
label: "Workflow Object Document Added",
value: "WORKFLOW_OBJECT_DOCUMENT_ADDED"
},
{
label: "Workflow Object Document Lock Added",
value: "WORKFLOW_OBJECT_DOCUMENT_LOCK_ADDED"
},
{
label: "Workflow Object Document Lock Deleted",
value: "WORKFLOW_OBJECT_DOCUMENT_LOCK_DELETED"
},
{
label: "Workflow Object Document Removed",
value: "WORKFLOW_OBJECT_DOCUMENT_REMOVED"
},
{
label: "Workflow Object Email Added",
value: "WORKFLOW_OBJECT_EMAIL_ADDED"
},
{
label: "Workflow Object Email Removed",
value: "WORKFLOW_OBJECT_EMAIL_REMOVED"
},
{
label: "Workflow Object External User Created",
value: "WORKFLOW_OBJECT_EXTERNAL_USER_CREATED"
},
{
label: "Workflow Object External User Deleted",
value: "WORKFLOW_OBJECT_EXTERNAL_USER_DELETED"
},
{
label: "Workflow Object Note Added",
value: "WORKFLOW_OBJECT_NOTE_ADDED"
},
{
label: "Workflow Object Note Removed",
value: "WORKFLOW_OBJECT_NOTE_REMOVED"
},
{
label: "Workflow Object Resource Created",
value: "WORKFLOW_OBJECT_RESOURCE_CREATED"
},
{
label: "Workflow Object Snapshot Created",
value: "WORKFLOW_OBJECT_SNAPSHOT_CREATED"
},
{
label: "Workflow Object Task Condition Created",
value: "WORKFLOW_OBJECT_TASK_CONDITION_CREATED"
},
{
label: "Workflow Object Task Created",
value: "WORKFLOW_OBJECT_TASK_CREATED"
},
{
label: "Workflow Object Task Deleted",
value: "WORKFLOW_OBJECT_TASK_DELETED"
},
{
label: "Workflow Object Task Snapshot Created",
value: "WORKFLOW_OBJECT_TASK_SNAPSHOT_CREATED"
},
{
label: "Workflow Object Task Updated",
value: "WORKFLOW_OBJECT_TASK_UPDATED"
},
{
label: "Workflow Object Updated",
value: "WORKFLOW_OBJECT_UPDATED"
},
{
label: "Workflow Objects Connection Created",
value: "WORKFLOW_OBJECTS_CONNECTION_CREATED"
},
{
label: "Workflow Objects External Connection Created",
value: "WORKFLOW_OBJECTS_EXTERNAL_CONNECTION_CREATED"
},
{
label: "Workflow Objects External Connection Group Created",
value: "WORKFLOW_OBJECTS_EXTERNAL_CONNECTION_GROUP_CREATED"
},
{
label: "Workflow Unarchived",
value: "WORKFLOW_UNARCHIVED"
},
{
label: "Workflow Updated",
value: "WORKFLOW_UPDATED"
}
];
export default webhookFilters;

View File

View File

@@ -0,0 +1,18 @@
import defineApp from '../../helpers/define-app';
import addAuthHeader from './common/add-auth-header';
import auth from './auth';
import triggers from './triggers';
export default defineApp({
name: 'Flowers Software',
key: 'flowers-software',
iconUrl: '{BASE_URL}/apps/flowers-software/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/flowers-software/connection',
supportsConnections: true,
baseUrl: 'https://flowers-software.com',
apiBaseUrl: 'https://webapp.flowers-software.com/api',
primaryColor: '02AFC7',
beforeRequest: [addAuthHeader],
auth,
triggers,
});

View File

@@ -0,0 +1,3 @@
import newActivity from './new-activity';
export default [newActivity];

View File

@@ -0,0 +1,54 @@
import isEmpty from 'lodash/isEmpty';
import defineTrigger from '../../../../helpers/define-trigger';
import webhookFilters from '../../common/webhook-filters';
export default defineTrigger({
name: 'New activity',
key: 'newActivity',
type: 'webhook',
description: 'Triggers when a new activity occurs.',
arguments: [
{
label: 'Activity type',
key: 'filters',
type: 'dropdown' as const,
required: true,
description: 'Pick an activity type to receive events for.',
variables: false,
options: webhookFilters,
},
],
async testRun($) {
if (!isEmpty($.lastExecutionStep?.dataOut)) {
$.pushTriggerItem({
raw: $.lastExecutionStep.dataOut,
meta: {
internalId: '',
}
});
}
},
async registerHook($) {
const payload = {
name: $.flow.id,
type: 'POST',
url: $.webhookUrl,
filters: [$.step.parameters.filters]
};
const { data } = await $.http.post(
`/v2/public/api/webhooks`,
payload
);
await $.flow.setRemoteWebhookId(data.id);
},
async unregisterHook($) {
await $.http.delete(
`/v2/public/api/webhooks/${$.flow.remoteWebhookId}`
);
},
});

View File

@@ -13,9 +13,8 @@ export default async function generateAuthUrl($: IGlobalVariable) {
scope: scopes.join(','), scope: scopes.join(','),
}); });
const url = `${ const url = `${$.app.baseUrl
$.app.baseUrl }/login/oauth/authorize?${searchParams.toString()}`;
}/login/oauth/authorize?${searchParams.toString()}`;
await $.auth.set({ await $.auth.set({
url, url,

View File

@@ -0,0 +1,41 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1904.8 2500" style="enable-background:new 0 0 1904.8 2500;" xml:space="preserve">
<style type="text/css">
.st0{fill:#673AB7;}
.st1{fill:#F1F1F1;}
.st2{fill:url(#SVGID_1_);}
.st3{fill:#B39DDB;}
.st4{fill:#FFFFFF;fill-opacity:0.2;}
.st5{fill:#311B92;fill-opacity:0.2;}
.st6{fill:#311B92;fill-opacity:0.1;}
.st7{fill:url(#SVGID_2_);}
</style>
<g>
<path class="st0" d="M1190.5,0H178.6C83.3,0,0,83.3,0,178.6v2142.9c0,95.2,83.3,178.6,178.6,178.6h1547.6
c95.2,0,178.6-83.3,178.6-178.6V714.3l-416.7-297.6L1190.5,0z"/>
<path class="st1" d="M714.3,1845.2h714.3v-119H714.3V1845.2z M714.3,1071.4v119h714.3v-119H714.3z M607.1,1131
c0,47.6-35.7,95.2-95.2,95.2s-95.2-35.7-95.2-95.2c0-59.5,35.7-95.2,95.2-95.2S607.1,1083.3,607.1,1131z M607.1,1464.3
c0,47.6-35.7,95.2-95.2,95.2s-95.2-35.7-95.2-95.2c0-59.5,35.7-95.2,95.2-95.2S607.1,1416.7,607.1,1464.3z M607.1,1785.7
c0,47.6-35.7,95.2-95.2,95.2s-95.2-35.7-95.2-95.2c0-59.5,35.7-95.2,95.2-95.2S607.1,1738.1,607.1,1785.7z M714.3,1547.6h714.3
v-119.1H714.3L714.3,1547.6L714.3,1547.6z"/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="122.5479" y1="1635.2429" x2="122.5479" y2="1634.3186" gradientTransform="matrix(666.67 0 0 -654.7559 -80127.6016 1071403.75)">
<stop offset="0" style="stop-color:#311B92;stop-opacity:0.2"/>
<stop offset="1" style="stop-color:#311B92;stop-opacity:2.000000e-02"/>
</linearGradient>
<path class="st2" d="M1238.1,666.7l666.7,654.8V714.3L1238.1,666.7z"/>
<path class="st3" d="M1190.5,0v535.7c0,95.2,83.3,178.6,178.6,178.6h535.7L1190.5,0z"/>
<path class="st4" d="M178.6,0C83.3,0,0,83.3,0,178.6v11.9C0,95.2,83.3,11.9,178.6,11.9h1011.9V0H178.6L178.6,0z"/>
<path class="st5" d="M1726.2,2488.1H178.6C83.3,2488.1,0,2404.8,0,2309.5v11.9c0,95.2,83.3,178.6,178.6,178.6h1547.6
c95.2,0,178.6-83.3,178.6-178.6v-11.9C1904.8,2404.8,1821.4,2488.1,1726.2,2488.1z"/>
<path class="st6" d="M1369,714.3c-95.2,0-178.6-83.3-178.6-178.6v11.9c0,95.2,83.3,178.6,178.6,178.6h535.7v-11.9L1369,714.3
L1369,714.3z"/>
<radialGradient id="SVGID_2_" cx="122.6324" cy="1634.4275" r="12.899" gradientTransform="matrix(1904.7655 0 0 -1904.75 -233525.7031 3113242.5)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.1"/>
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
</radialGradient>
<path class="st7" d="M1190.5,0H178.6C83.3,0,0,83.3,0,178.6v2142.9c0,95.2,83.3,178.6,178.6,178.6h1547.6
c95.2,0,178.6-83.3,178.6-178.6V714.3L1190.5,0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,24 @@
import { IField, IGlobalVariable } from '@automatisch/types';
import { URLSearchParams } from 'url';
import authScope from '../common/auth-scope';
export default async function generateAuthUrl($: IGlobalVariable) {
const oauthRedirectUrlField = $.app.auth.fields.find(
(field: IField) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value as string;
const searchParams = new URLSearchParams({
client_id: $.auth.data.clientId as string,
redirect_uri: redirectUri,
prompt: 'select_account',
scope: authScope.join(' '),
response_type: 'code',
access_type: 'offline',
});
const url = `https://accounts.google.com/o/oauth2/v2/auth?${searchParams.toString()}`;
await $.auth.set({
url,
});
}

View File

@@ -0,0 +1,48 @@
import generateAuthUrl from './generate-auth-url';
import verifyCredentials from './verify-credentials';
import refreshToken from './refresh-token';
import isStillVerified from './is-still-verified';
export default {
fields: [
{
key: 'oAuthRedirectUrl',
label: 'OAuth Redirect URL',
type: 'string' as const,
required: true,
readOnly: true,
value: '{WEB_APP_URL}/app/google-forms/connections/add',
placeholder: null,
description:
'When asked to input a redirect URL in Google Cloud, enter the URL above.',
clickToCopy: true,
},
{
key: 'clientId',
label: 'Client ID',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'clientSecret',
label: 'Client Secret',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
],
generateAuthUrl,
verifyCredentials,
isStillVerified,
refreshToken,
};

View File

@@ -0,0 +1,9 @@
import { IGlobalVariable } from '@automatisch/types';
import getCurrentUser from '../common/get-current-user';
const isStillVerified = async ($: IGlobalVariable) => {
const currentUser = await getCurrentUser($);
return !!currentUser.resourceName;
};
export default isStillVerified;

View File

@@ -0,0 +1,26 @@
import { URLSearchParams } from 'node:url';
import { IGlobalVariable } from '@automatisch/types';
import authScope from '../common/auth-scope';
const refreshToken = async ($: IGlobalVariable) => {
const params = new URLSearchParams({
client_id: $.auth.data.clientId as string,
client_secret: $.auth.data.clientSecret as string,
grant_type: 'refresh_token',
refresh_token: $.auth.data.refreshToken as string,
});
const { data } = await $.http.post(
'https://oauth2.googleapis.com/token',
params.toString()
);
await $.auth.set({
accessToken: data.access_token,
expiresIn: data.expires_in,
scope: authScope.join(' '),
tokenType: data.token_type,
});
};
export default refreshToken;

View File

@@ -0,0 +1,57 @@
import { IField, IGlobalVariable } from '@automatisch/types';
import getCurrentUser from '../common/get-current-user';
type TUser = {
displayName: string;
metadata: {
primary: boolean;
};
};
type TEmailAddress = {
value: string;
metadata: {
primary: boolean;
};
};
const verifyCredentials = async ($: IGlobalVariable) => {
const oauthRedirectUrlField = $.app.auth.fields.find(
(field: IField) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value as string;
const { data } = await $.http.post(`https://oauth2.googleapis.com/token`, {
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
code: $.auth.data.code,
grant_type: 'authorization_code',
redirect_uri: redirectUri,
});
await $.auth.set({
accessToken: data.access_token,
tokenType: data.token_type,
});
const currentUser = await getCurrentUser($);
const { displayName } = currentUser.names.find(
(name: TUser) => name.metadata.primary
);
const { value: email } = currentUser.emailAddresses.find(
(emailAddress: TEmailAddress) => emailAddress.metadata.primary
);
await $.auth.set({
clientId: $.auth.data.clientId,
clientSecret: $.auth.data.clientSecret,
scope: $.auth.data.scope,
idToken: data.id_token,
expiresIn: data.expires_in,
refreshToken: data.refresh_token,
resourceName: currentUser.resourceName,
screenName: `${displayName} - ${email}`,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,11 @@
import { TBeforeRequest } from '@automatisch/types';
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
if (requestConfig.headers && $.auth.data?.accessToken) {
requestConfig.headers.Authorization = `${$.auth.data.tokenType} ${$.auth.data.accessToken}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -0,0 +1,9 @@
const authScope: string[] = [
'https://www.googleapis.com/auth/forms.body.readonly',
'https://www.googleapis.com/auth/forms.responses.readonly',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/userinfo.email',
'profile',
];
export default authScope;

View File

@@ -0,0 +1,10 @@
import { IGlobalVariable } from '@automatisch/types';
const getCurrentUser = async ($: IGlobalVariable) => {
const { data: currentUser } = await $.http.get(
'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses'
);
return currentUser;
};
export default getCurrentUser;

View File

@@ -0,0 +1,3 @@
import listForms from './list-forms';
export default [listForms];

View File

@@ -0,0 +1,34 @@
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
export default {
name: 'List forms',
key: 'listForms',
async run($: IGlobalVariable) {
const forms: {
data: IJSONObject[];
} = {
data: [],
};
const params = {
q: `mimeType='application/vnd.google-apps.form'`,
spaces: 'drive',
pageToken: undefined as unknown as string,
};
do {
const { data } = await $.http.get(`https://www.googleapis.com/drive/v3/files`, { params });
params.pageToken = data.nextPageToken;
for (const file of data.files) {
forms.data.push({
value: file.id,
name: file.name,
});
}
} while (params.pageToken);
return forms;
},
};

View File

View File

@@ -0,0 +1,20 @@
import defineApp from '../../helpers/define-app';
import addAuthHeader from './common/add-auth-header';
import auth from './auth';
import triggers from './triggers';
import dynamicData from './dynamic-data';
export default defineApp({
name: 'Google Forms',
key: 'google-forms',
baseUrl: 'https://docs.google.com/forms',
apiBaseUrl: 'https://forms.googleapis.com',
iconUrl: '{BASE_URL}/apps/google-forms/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/google-forms/connection',
primaryColor: '673AB7',
supportsConnections: true,
beforeRequest: [addAuthHeader],
auth,
triggers,
dynamicData,
});

View File

@@ -0,0 +1,3 @@
import newFormResponses from './new-form-responses';
export default [newFormResponses];

View File

@@ -0,0 +1,33 @@
import defineTrigger from '../../../../helpers/define-trigger';
import newFormResponses from './new-form-responses';
export default defineTrigger({
name: 'New Form Responses',
key: 'newFormResponses',
pollInterval: 15,
description: 'Triggers when a new form response is submitted.',
arguments: [
{
label: 'Form',
key: 'formId',
type: 'dropdown' as const,
required: true,
description: 'Pick a form to receive form responses.',
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listForms',
},
],
},
},
],
async run($) {
await newFormResponses($);
},
});

View File

@@ -0,0 +1,28 @@
import { IGlobalVariable } from '@automatisch/types';
const newResponses = async ($: IGlobalVariable) => {
const params = {
pageToken: undefined as unknown as string,
};
do {
const pathname = `/v1/forms/${$.step.parameters.formId}/responses`;
const { data } = await $.http.get(pathname, { params });
params.pageToken = data.nextPageToken;
if (data.responses?.length) {
for (const formResponse of data.responses) {
const dataItem = {
raw: formResponse,
meta: {
internalId: formResponse.responseId,
},
};
$.pushTriggerItem(dataItem);
}
}
} while (params.pageToken);
};
export default newResponses;

View File

@@ -0,0 +1,74 @@
import defineAction from '../../../../helpers/define-action';
type TMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
export default defineAction({
name: 'Custom Request',
key: 'customRequest',
description: 'Makes a custom HTTP request by providing raw details.',
arguments: [
{
label: 'Method',
key: 'method',
type: 'dropdown' as const,
required: true,
description: `The HTTP method we'll use to perform the request.`,
value: 'GET',
options: [
{ label: 'DELETE', value: 'DELETE' },
{ label: 'GET', value: 'GET' },
{ label: 'PATCH', value: 'PATCH' },
{ label: 'POST', value: 'POST' },
{ label: 'PUT', value: 'PUT' },
],
},
{
label: 'URL',
key: 'url',
type: 'string' as const,
required: true,
description: 'Any URL with a querystring will be re-encoded properly.',
variables: true,
},
{
label: 'Data',
key: 'data',
type: 'string' as const,
required: false,
description: 'Place raw JSON data here.',
variables: true,
},
],
async run($) {
const method = $.step.parameters.method as TMethod;
const data = $.step.parameters.data as string;
const url = $.step.parameters.url as string;
const maxFileSize = 25 * 1024 * 1024; // 25MB
const metadataResponse = await $.http.head(url);
if (Number(metadataResponse.headers['content-length']) > maxFileSize) {
throw new Error(
`Response is too large. Maximum size is 25MB. Actual size is ${metadataResponse.headers['content-length']}`
);
}
const response = await $.http.request({
url,
method,
data,
headers: {
'Content-Type': 'application/json',
},
});
let responseData = response.data;
if (typeof response.data === 'string') {
responseData = response.data.replaceAll('\u0000', '');
}
$.setActionItem({ raw: { data: responseData } });
},
});

View File

@@ -0,0 +1,3 @@
import customRequest from './custom-request';
export default [customRequest];

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="100px" height="100px"><path d="M 37.09375 0.09375 C 36.316406 0.167969 35.652344 0.691406 35.398438 1.429688 C 35.140625 2.171875 35.339844 2.992188 35.90625 3.53125 L 42.375 10 L 2 10 C 1.9375 9.996094 1.875 9.996094 1.8125 10 C 0.707031 10.050781 -0.144531 10.988281 -0.09375 12.09375 C -0.0429688 13.199219 0.894531 14.050781 2 14 L 42.375 14 L 35.90625 20.46875 C 35.382813 20.96875 35.167969 21.710938 35.347656 22.414063 C 35.527344 23.113281 36.070313 23.664063 36.769531 23.851563 C 37.46875 24.039063 38.214844 23.832031 38.71875 23.3125 L 50.03125 12 L 38.71875 0.6875 C 38.296875 0.253906 37.699219 0.0351563 37.09375 0.09375 Z M 12.5 26.09375 C 12.046875 26.152344 11.628906 26.359375 11.3125 26.6875 L 0 38 L 11.3125 49.3125 C 11.816406 49.832031 12.5625 50.039063 13.261719 49.851563 C 13.960938 49.664063 14.503906 49.113281 14.683594 48.414063 C 14.863281 47.710938 14.648438 46.96875 14.125 46.46875 L 7.65625 40 L 48 40 C 48.722656 40.011719 49.390625 39.632813 49.753906 39.007813 C 50.121094 38.386719 50.121094 37.613281 49.753906 36.992188 C 49.390625 36.367188 48.722656 35.988281 48 36 L 7.65625 36 L 14.125 29.53125 C 14.753906 28.9375 14.929688 28.003906 14.558594 27.222656 C 14.1875 26.441406 13.359375 25.984375 12.5 26.09375 Z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

View File

@@ -0,0 +1,14 @@
import defineApp from '../../helpers/define-app';
import actions from './actions';
export default defineApp({
name: 'HTTP Request',
key: 'http-request',
iconUrl: '{BASE_URL}/apps/http-request/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/http-request/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',
primaryColor: '000000',
actions,
});

View File

@@ -0,0 +1,3 @@
import sendMessage from './send-message';
export default [sendMessage];

View File

@@ -0,0 +1,103 @@
import qs from 'qs';
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Send message',
key: 'sendMessage',
description: 'Sends a message to a topic you specify.',
arguments: [
{
label: 'Topic',
key: 'topic',
type: 'string' as const,
required: true,
description: 'Target topic name.',
variables: true,
},
{
label: 'Message body',
key: 'message',
type: 'string' as const,
required: true,
description: 'Message body to be sent, set to triggered if empty or not passed.',
variables: true,
},
{
label: 'Title',
key: 'title',
type: 'string' as const,
required: false,
description: 'Message title.',
variables: true,
},
{
label: 'Email',
key: 'email',
type: 'string' as const,
required: false,
description: 'E-mail address for e-mail notifications.',
variables: true,
},
{
label: 'Click URL',
key: 'click',
type: 'string' as const,
required: false,
description: 'Website opened when notification is clicked.',
variables: true,
},
{
label: 'Attach file by URL',
key: 'attach',
type: 'string' as const,
required: false,
description: 'URL of an attachment.',
variables: true,
},
{
label: 'Filename',
key: 'filename',
type: 'string' as const,
required: false,
description: 'File name of the attachment.',
variables: true,
},
{
label: 'Delay',
key: 'delay',
type: 'string' as const,
required: false,
description: 'Timestamp or duration for delayed delivery. For example, 30min or 9am.',
variables: true,
},
],
async run($) {
const {
topic,
message,
title,
email,
click,
attach,
filename,
delay
} = $.step.parameters;
const payload = {
topic,
message,
title,
email,
click,
attach,
filename,
delay
};
const response = await $.http.post('/', payload);
$.setActionItem({
raw: response.data,
});
},
});

View File

@@ -0,0 +1 @@
<svg width="50mm" height="50mm" viewBox="0 0 50 50" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="a"><stop style="stop-color:#348878;stop-opacity:1" offset="0"/><stop style="stop-color:#56bda8;stop-opacity:1" offset="1"/></linearGradient><linearGradient xlink:href="#a" id="b" x1="160.722" y1="128.533" x2="168.412" y2="134.326" gradientUnits="userSpaceOnUse" gradientTransform="translate(-845.726 -630.598) scale(5.59448)"/></defs><g style="display:inline"><path style="color:#000;fill:url(#b);stroke:none;stroke-width:3.72347;-inkscape-stroke:none" d="M94.237 89.912H59.499c-2.388 0-4.342 1.844-4.342 4.098l.033 27.754-.648 3.738 9.297-2.806h30.396c2.388 0 4.342-1.845 4.342-4.099V94.01c0-2.254-1.954-4.098-4.342-4.098z" transform="translate(-51.147 -81.516)"/><path style="color:#000;fill:#fff;stroke:none;stroke-width:.762343;-inkscape-stroke:none" d="M58.849 86.79c-3.62 0-6.72 2.848-6.72 6.47v.002l.035 30.273-.91 6.708 12.362-3.284h30.729c3.62 0 6.72-2.852 6.72-6.473V93.26c0-3.62-3.099-6.469-6.717-6.469h-.003zm0 4.566h35.499c1.272 0 2.151.927 2.151 1.903v27.227c0 .977-.88 1.924-2.154 1.903h-31.4l-6.28 1.898.065-.37-.035-30.658c0-.977.88-1.903 2.154-1.903z" transform="translate(-51.147 -81.516)"/><g style="font-size:8.48274px;font-family:sans-serif;letter-spacing:0;word-spacing:0;fill:#000;stroke:none;stroke-width:.525121"><path style="color:#000;-inkscape-font-specification:'JetBrains Mono, Bold';fill:#fff;stroke:none;-inkscape-stroke:none" d="M62.57 116.77v-1.312l3.28-1.459q.159-.068.306-.102.158-.045.283-.068l.271-.022v-.09q-.136-.012-.271-.046-.125-.023-.283-.057-.147-.045-.306-.113l-3.28-1.459v-1.323l5.068 2.319v1.413z" transform="matrix(2.1689 0 0 2.57844 -124.28 -268.742)"/><path style="color:#000;-inkscape-font-specification:'JetBrains Mono, Bold';fill:#fff;stroke:none;-inkscape-stroke:none" d="M62.309 110.31v1.903l3.437 1.53.022.007-.022.008-3.437 1.53v1.892l.37-.17 5.221-2.39v-1.75zm.525.817 4.541 2.08v1.076l-4.541 2.078v-.732l3.12-1.389.003-.002a1.56 1.56 0 0 1 .258-.086h.006l.008-.002c.094-.027.176-.047.246-.06l.498-.041v-.574l-.24-.02a1.411 1.411 0 0 1-.231-.04l-.008-.001-.008-.002a9.077 9.077 0 0 1-.263-.053 2.781 2.781 0 0 1-.266-.097l-.004-.002-3.119-1.39z" transform="matrix(2.1689 0 0 2.57844 -124.28 -268.742)"/></g><g style="font-size:8.48274px;font-family:sans-serif;letter-spacing:0;word-spacing:0;fill:#000;stroke:none;stroke-width:.525121"><path style="color:#000;-inkscape-font-specification:'JetBrains Mono, Bold';fill:#fff;stroke:none;-inkscape-stroke:none" d="M69.171 117.754h5.43v1.278h-5.43Z" transform="matrix(2.16247 0 0 2.48294 -122.76 -261.211)"/><path style="color:#000;-inkscape-font-specification:'JetBrains Mono, Bold';fill:#fff;stroke:none;-inkscape-stroke:none" d="M68.908 117.492v1.802h5.955v-1.802zm.526.524h4.904v.754h-4.904z" transform="matrix(2.16247 0 0 2.48294 -122.76 -261.211)"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,41 @@
import verifyCredentials from './verify-credentials';
import isStillVerified from './is-still-verified';
export default {
fields: [
{
key: 'serverUrl',
label: 'Server URL',
type: 'string' as const,
required: true,
readOnly: false,
value: 'https://ntfy.sh',
placeholder: null,
description: 'ntfy server to use.',
clickToCopy: false,
},
{
key: 'username',
label: 'Username',
type: 'string' as const,
required: false,
readOnly: false,
placeholder: null,
clickToCopy: false,
description: 'You may need to provide your username if your installation requires authentication.',
},
{
key: 'password',
label: 'Password',
type: 'string' as const,
required: false,
readOnly: false,
placeholder: null,
clickToCopy: false,
description: 'You may need to provide your password if your installation requires authentication.',
},
],
verifyCredentials,
isStillVerified,
};

View File

@@ -0,0 +1,9 @@
import { IGlobalVariable } from '@automatisch/types';
import verifyCredentials from './verify-credentials';
const isStillVerified = async ($: IGlobalVariable) => {
await verifyCredentials($);
return true;
};
export default isStillVerified;

View File

@@ -0,0 +1,16 @@
import { IGlobalVariable } from '@automatisch/types';
const verifyCredentials = async ($: IGlobalVariable) => {
await $.http.post('/', { topic: 'automatisch' });
let screenName = $.auth.data.serverUrl;
if ($.auth.data.username) {
screenName = `${$.auth.data.username} @ ${screenName}`
}
await $.auth.set({
screenName,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,18 @@
import { TBeforeRequest } from '@automatisch/types';
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
if ($.auth.data.apiBaseUrl) {
requestConfig.baseURL = $.auth.data.apiBaseUrl as string;
}
if ($.auth.data?.username && $.auth.data?.password) {
requestConfig.auth = {
username: $.auth.data.username as string,
password: $.auth.data.password as string,
}
}
return requestConfig;
};
export default addAuthHeader;

View File

View File

@@ -0,0 +1,18 @@
import defineApp from '../../helpers/define-app';
import addAuthHeader from './common/add-auth-header';
import auth from './auth';
import actions from './actions';
export default defineApp({
name: 'Ntfy',
key: 'ntfy',
iconUrl: '{BASE_URL}/apps/ntfy/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/ntfy/connection',
supportsConnections: true,
baseUrl: 'https://ntfy.sh',
apiBaseUrl: 'https://ntfy.sh',
primaryColor: '56bda8',
beforeRequest: [addAuthHeader],
auth,
actions,
});

View File

@@ -0,0 +1,29 @@
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Check moderation',
key: 'checkModeration',
description: 'Checks for hate, hate/threatening, self-harm, sexual, sexual/minors, violence, or violence/graphic content in the given text.',
arguments: [
{
label: 'Input',
key: 'input',
type: 'string' as const,
required: true,
variables: true,
description: 'The text to analyze.'
},
],
async run($) {
const { data } = await $.http.post('/v1/moderations', {
input: $.step.parameters.input as string,
});
const result = data?.results[0];
$.setActionItem({
raw: result,
});
},
});

View File

@@ -0,0 +1,4 @@
import checkModeration from './check-moderation';
import sendPrompt from './send-prompt';
export default [checkModeration, sendPrompt];

View File

@@ -0,0 +1,104 @@
import defineAction from '../../../../helpers/define-action';
const castFloatOrUndefined = (value: string | null) => {
return value === '' ? undefined : parseFloat(value);
}
export default defineAction({
name: 'Send prompt',
key: 'sendPrompt',
description: 'Creates a completion for the provided prompt and parameters.',
arguments: [
{
label: 'Model',
key: 'model',
type: 'dropdown' as const,
required: true,
variables: false,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listModels',
},
],
},
},
{
label: 'Prompt',
key: 'prompt',
type: 'string' as const,
required: true,
variables: true,
description: 'The text to analyze.'
},
{
label: 'Temperature',
key: 'temperature',
type: 'string' as const,
required: false,
variables: true,
description: 'What sampling temperature to use. Higher values mean the model will take more risk. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer. We generally recommend altering this or Top P but not both.'
},
{
label: 'Maximum tokens',
key: 'maxTokens',
type: 'string' as const,
required: false,
variables: true,
description: 'The maximum number of tokens to generate in the completion.'
},
{
label: 'Stop Sequence',
key: 'stopSequence',
type: 'string' as const,
required: false,
variables: true,
description: 'Single stop sequence where the API will stop generating further tokens. The returned text will not contain the stop sequence.'
},
{
label: 'Top P',
key: 'topP',
type: 'string' as const,
required: false,
variables: true,
description: 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with Top P probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.'
},
{
label: 'Frequency Penalty',
key: 'frequencyPenalty',
type: 'string' as const,
required: false,
variables: true,
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
},
{
label: 'presencePenalty',
key: 'presencePenalty',
type: 'string' as const,
required: false,
variables: true,
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.`
},
],
async run($) {
const payload = {
model: $.step.parameters.model as string,
prompt: $.step.parameters.prompt as string,
temperature: castFloatOrUndefined($.step.parameters.temperature as string),
max_tokens: castFloatOrUndefined($.step.parameters.maxTokens as string),
stop: ($.step.parameters.stopSequence as string || null),
top_p: castFloatOrUndefined($.step.parameters.topP as string),
frequency_penalty: castFloatOrUndefined($.step.parameters.frequencyPenalty as string),
presence_penalty: castFloatOrUndefined($.step.parameters.presencePenalty as string),
};
const { data } = await $.http.post('/v1/completions', payload);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -0,0 +1,6 @@
<svg width="256px" height="260px" viewBox="0 0 256 260" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<title>OpenAI</title>
<g>
<path d="M239.183914,106.202783 C245.054304,88.5242096 243.02228,69.1733805 233.607599,53.0998864 C219.451678,28.4588021 190.999703,15.7836129 163.213007,21.739505 C147.554077,4.32145883 123.794909,-3.42398554 100.87901,1.41873898 C77.9631105,6.26146349 59.3690093,22.9572536 52.0959621,45.2214219 C33.8436494,48.9644867 18.0901721,60.392749 8.86672513,76.5818033 C-5.443491,101.182962 -2.19544431,132.215255 16.8986662,153.320094 C11.0060865,170.990656 13.0197283,190.343991 22.4238231,206.422991 C36.5975553,231.072344 65.0680342,243.746566 92.8695738,237.783372 C105.235639,251.708249 123.001113,259.630942 141.623968,259.52692 C170.105359,259.552169 195.337611,241.165718 204.037777,214.045661 C222.28734,210.296356 238.038489,198.869783 247.267014,182.68528 C261.404453,158.127515 258.142494,127.262775 239.183914,106.202783 L239.183914,106.202783 Z M141.623968,242.541207 C130.255682,242.559177 119.243876,238.574642 110.519381,231.286197 L112.054146,230.416496 L163.724595,200.590881 C166.340648,199.056444 167.954321,196.256818 167.970781,193.224005 L167.970781,120.373788 L189.815614,133.010026 C190.034132,133.121423 190.186235,133.330564 190.224885,133.572774 L190.224885,193.940229 C190.168603,220.758427 168.442166,242.484864 141.623968,242.541207 Z M37.1575749,197.93062 C31.456498,188.086359 29.4094818,176.546984 31.3766237,165.342426 L32.9113895,166.263285 L84.6329973,196.088901 C87.2389349,197.618207 90.4682717,197.618207 93.0742093,196.088901 L156.255402,159.663793 L156.255402,184.885111 C156.243557,185.149771 156.111725,185.394602 155.89729,185.550176 L103.561776,215.733903 C80.3054953,229.131632 50.5924954,221.165435 37.1575749,197.93062 Z M23.5493181,85.3811273 C29.2899861,75.4733097 38.3511911,67.9162648 49.1287482,64.0478825 L49.1287482,125.438515 C49.0891492,128.459425 50.6965386,131.262556 53.3237748,132.754232 L116.198014,169.025864 L94.3531808,181.662102 C94.1132325,181.789434 93.8257461,181.789434 93.5857979,181.662102 L41.3526015,151.529534 C18.1419426,138.076098 10.1817681,108.385562 23.5493181,85.125333 L23.5493181,85.3811273 Z M203.0146,127.075598 L139.935725,90.4458545 L161.7294,77.8607748 C161.969348,77.7334434 162.256834,77.7334434 162.496783,77.8607748 L214.729979,108.044502 C231.032329,117.451747 240.437294,135.426109 238.871504,154.182739 C237.305714,172.939368 225.050719,189.105572 207.414262,195.67963 L207.414262,134.288998 C207.322521,131.276867 205.650697,128.535853 203.0146,127.075598 Z M224.757116,94.3850867 L223.22235,93.4642272 L171.60306,63.3828173 C168.981293,61.8443751 165.732456,61.8443751 163.110689,63.3828173 L99.9806554,99.8079259 L99.9806554,74.5866077 C99.9533004,74.3254088 100.071095,74.0701869 100.287609,73.9215426 L152.520805,43.7889738 C168.863098,34.3743518 189.174256,35.2529043 204.642579,46.0434841 C220.110903,56.8340638 227.949269,75.5923959 224.757116,94.1804513 L224.757116,94.3850867 Z M88.0606409,139.097931 L66.2158076,126.512851 C65.9950399,126.379091 65.8450965,126.154176 65.8065367,125.898945 L65.8065367,65.684966 C65.8314495,46.8285367 76.7500605,29.6846032 93.8270852,21.6883055 C110.90411,13.6920079 131.063833,16.2835462 145.5632,28.338998 L144.028434,29.2086986 L92.3579852,59.0343142 C89.7419327,60.5687513 88.1282597,63.3683767 88.1117998,66.4011901 L88.0606409,139.097931 Z M99.9294965,113.5185 L128.06687,97.3011417 L156.255402,113.5185 L156.255402,145.953218 L128.169187,162.170577 L99.9806554,145.953218 L99.9294965,113.5185 Z" fill="#000000"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,34 @@
import verifyCredentials from './verify-credentials';
import isStillVerified from './is-still-verified';
export default {
fields: [
{
key: 'screenName',
label: 'Screen Name',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description:
'Screen name of your connection to be used on Automatisch UI.',
clickToCopy: false,
},
{
key: 'apiKey',
label: 'API Key',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: 'OpenAI API key of your account.',
docUrl: 'https://automatisch.io/docs/openai#api-key',
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified,
};

View File

@@ -0,0 +1,8 @@
import { IGlobalVariable } from '@automatisch/types';
const isStillVerified = async ($: IGlobalVariable) => {
await $.http.get('/v1/models');
return true;
};
export default isStillVerified;

View File

@@ -0,0 +1,7 @@
import { IGlobalVariable } from '@automatisch/types';
const verifyCredentials = async ($: IGlobalVariable) => {
await $.http.get('/v1/models');
};
export default verifyCredentials;

View File

@@ -0,0 +1,11 @@
import { TBeforeRequest } from '@automatisch/types';
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
if ($.auth.data?.apiKey) {
requestConfig.headers.Authorization = `Bearer ${$.auth.data.apiKey}`;
}
return requestConfig;
};
export default addAuthHeader;

View File

@@ -0,0 +1,3 @@
import listModels from './list-models';
export default [listModels];

View File

@@ -0,0 +1,19 @@
import { IGlobalVariable } from '@automatisch/types';
export default {
name: 'List models',
key: 'listModels',
async run($: IGlobalVariable) {
const response = await $.http.get('/v1/models');
const models = response.data.data.map((model: { id: string }) => {
return {
value: model.id,
name: model.id,
};
});
return { data: models };
},
};

View File

View File

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

View File

@@ -1,16 +1,34 @@
import { IGlobalVariable } from '@automatisch/types'; import { IGlobalVariable, IJSONObject } from '@automatisch/types';
import { XMLParser } from 'fast-xml-parser'; import { XMLParser } from 'fast-xml-parser';
import bcrypt from 'bcrypt';
const getInternalId = async (item: IJSONObject): Promise<string> => {
if (item.guid) {
return item.guid.toString();
} else if (item.id) {
return item.id.toString();
}
return await hashItem(JSON.stringify(item));
};
const hashItem = async (value: string) => {
return await bcrypt.hash(value, 1);
};
const newItemsInFeed = async ($: IGlobalVariable) => { const newItemsInFeed = async ($: IGlobalVariable) => {
const { data } = await $.http.get($.step.parameters.feedUrl as string); const { data } = await $.http.get($.step.parameters.feedUrl as string);
const parser = new XMLParser(); const parser = new XMLParser();
const parsedData = parser.parse(data); const parsedData = parser.parse(data);
for (const item of parsedData.rss.channel.item) { // naive implementation to cover atom and rss feeds
const items = parsedData.rss?.channel?.item || parsedData.feed?.entry || [];
for (const item of items) {
const dataItem = { const dataItem = {
raw: item, raw: item,
meta: { meta: {
internalId: item.guid, internalId: await getInternalId(item),
}, },
}; };

View File

@@ -0,0 +1,52 @@
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Create attachment',
key: 'createAttachment',
description:
'Creates an attachment of a specified object by given parent ID.',
arguments: [
{
label: 'Parent ID',
key: 'parentId',
type: 'string' as const,
required: true,
variables: true,
description:
'ID of the parent object of the attachment. The following objects are supported as parents of attachments: Account, Asset, Campaign, Case, Contact, Contract, Custom objects, EmailMessage, EmailTemplate, Event, Lead, Opportunity, Product2, Solution, Task',
},
{
label: 'Name',
key: 'name',
type: 'string' as const,
required: true,
variables: true,
description: 'Name of the attached file. Maximum size is 255 characters.',
},
{
label: 'Body',
key: 'body',
type: 'string' as const,
required: true,
variables: true,
description: 'File data. (Max size is 25MB)',
},
],
async run($) {
const { parentId, name, body } = $.step.parameters;
const options = {
ParentId: parentId,
Name: name,
Body: body,
};
const { data } = await $.http.post(
'/services/data/v56.0/sobjects/Attachment/',
options
);
$.setActionItem({ raw: data });
},
});

View File

@@ -0,0 +1,79 @@
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Find record',
key: 'findRecord',
description: 'Finds a record of a specified object by a field and value.',
arguments: [
{
label: 'Object',
key: 'object',
type: 'dropdown' as const,
required: true,
description: 'Pick which type of object you want to search for.',
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listObjects',
},
],
},
},
{
label: 'Field',
key: 'field',
type: 'dropdown' as const,
description: 'Pick which field to search by',
required: true,
variables: false,
dependsOn: ['parameters.object'],
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFields',
},
{
name: 'parameters.object',
value: '{parameters.object}',
},
],
},
},
{
label: 'Search value',
key: 'searchValue',
type: 'string' as const,
required: true,
variables: true,
},
],
async run($) {
const query = `
SELECT
FIELDS(ALL)
FROM
${$.step.parameters.object}
WHERE
${$.step.parameters.field} = '${$.step.parameters.searchValue}'
LIMIT 1
`;
const options = {
params: {
q: query,
},
};
const { data } = await $.http.get('/services/data/v56.0/query', options);
const record = data.records[0];
$.setActionItem({ raw: record });
},
});

View File

@@ -0,0 +1,4 @@
import findRecord from './find-record';
import createAttachment from './create-attachment';
export default [findRecord, createAttachment];

View File

@@ -1,6 +1,7 @@
import generateAuthUrl from './generate-auth-url'; import generateAuthUrl from './generate-auth-url';
import verifyCredentials from './verify-credentials'; import verifyCredentials from './verify-credentials';
import isStillVerified from './is-still-verified'; import isStillVerified from './is-still-verified';
import refreshToken from './refresh-token';
export default { export default {
fields: [ fields: [
@@ -61,6 +62,7 @@ export default {
}, },
], ],
refreshToken,
generateAuthUrl, generateAuthUrl,
verifyCredentials, verifyCredentials,
isStillVerified, isStillVerified,

View File

@@ -0,0 +1,25 @@
import { IGlobalVariable } from '@automatisch/types';
import qs from 'querystring';
const refreshToken = async ($: IGlobalVariable) => {
const searchParams = qs.stringify({
grant_type: 'refresh_token',
client_id: $.auth.data.consumerKey as string,
client_secret: $.auth.data.consumerSecret as string,
refresh_token: $.auth.data.refreshToken as string,
});
const { data } = await $.http.post(
`${$.auth.data.oauth2Url}/token?${searchParams}`
);
await $.auth.set({
accessToken: data.access_token,
tokenType: data.token_type,
idToken: data.id_token,
instanceUrl: data.instance_url,
signature: data.signature,
});
};
export default refreshToken;

View File

@@ -20,7 +20,9 @@ const verifyCredentials = async ($: IGlobalVariable) => {
await $.auth.set({ await $.auth.set({
accessToken: data.access_token, accessToken: data.access_token,
refreshToken: data.refresh_token,
tokenType: data.token_type, tokenType: data.token_type,
idToken: data.id_token,
instanceUrl: data.instance_url, instanceUrl: data.instance_url,
signature: data.signature, signature: data.signature,
userId: data.id, userId: data.id,

View File

@@ -2,6 +2,7 @@ import defineApp from '../../helpers/define-app';
import addAuthHeader from './common/add-auth-header'; import addAuthHeader from './common/add-auth-header';
import auth from './auth'; import auth from './auth';
import triggers from './triggers'; import triggers from './triggers';
import actions from './actions';
import dynamicData from './dynamic-data'; import dynamicData from './dynamic-data';
export default defineApp({ export default defineApp({
@@ -16,5 +17,6 @@ export default defineApp({
beforeRequest: [addAuthHeader], beforeRequest: [addAuthHeader],
auth, auth,
triggers, triggers,
actions,
dynamicData, dynamicData,
}); });

View File

@@ -0,0 +1,30 @@
import defineAction from '../../../../helpers/define-action';
export default defineAction({
name: 'Find user by email',
key: 'findUserByEmail',
description: 'Finds a user by email.',
arguments: [
{
label: 'Email',
key: 'email',
type: 'string' as const,
required: true,
variables: true,
},
],
async run($) {
const params = {
email: $.step.parameters.email as string,
};
const { data } = await $.http.get('/users.lookupByEmail', {
params
});
if (data.ok) {
$.setActionItem({ raw: data.user });
}
},
});

View File

@@ -1,4 +1,5 @@
import findMessage from './find-message'; import findMessage from './find-message';
import findUserByEmail from './find-user-by-email';
import sendMessageToChannel from './send-a-message-to-channel'; import sendMessageToChannel from './send-a-message-to-channel';
export default [findMessage, sendMessageToChannel]; export default [findMessage, findUserByEmail, sendMessageToChannel];

View File

@@ -13,7 +13,13 @@ export default {
error: null, error: null,
}; };
const response = await $.http.get('/conversations.list'); const response = await $.http.get('/conversations.list', {
params: {
types: 'public_channel,private_channel',
limit: 1000,
exclude_archived: true,
}
});
if (response.data.ok === false) { if (response.data.ok === false) {
throw new Error(response.data); throw new Error(response.data);

View File

@@ -0,0 +1,10 @@
<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0, 0, 400,400">
<g id="svgg">
<path id="path0"
d="M198.800 76.002 C 192.960 76.301,187.099 76.918,183.400 77.623 C 177.677 78.714,175.057 79.288,171.600 80.207 C 169.510 80.763,167.440 81.382,167.000 81.583 C 166.560 81.783,165.030 82.342,163.600 82.824 C 142.177 90.045,124.260 107.805,117.820 128.200 C 113.910 140.585,112.933 156.448,115.418 167.200 C 116.306 171.043,116.577 172.064,117.276 174.200 C 117.708 175.520,118.588 177.733,119.231 179.118 C 119.874 180.503,120.400 181.708,120.400 181.797 C 120.400 181.885,121.061 183.092,121.869 184.479 C 127.040 193.356,135.581 201.605,146.011 207.795 C 149.302 209.748,159.236 214.800,159.785 214.800 C 159.892 214.800,161.109 215.310,162.490 215.933 C 165.453 217.270,173.763 220.551,179.400 222.609 C 195.215 228.384,198.386 229.722,205.534 233.636 C 220.392 241.770,219.950 260.095,204.800 264.076 C 199.139 265.564,187.804 266.135,181.833 265.232 C 180.495 265.030,177.870 264.655,176.000 264.398 C 174.130 264.142,172.060 263.788,171.400 263.612 C 170.740 263.436,169.120 263.065,167.800 262.789 C 154.801 260.064,141.875 255.414,126.486 247.928 C 122.463 245.972,118.998 244.478,118.786 244.609 C 118.159 244.996,118.271 308.079,118.900 308.899 C 119.725 309.975,133.794 315.264,142.000 317.584 C 142.990 317.864,144.250 318.235,144.800 318.408 C 145.350 318.582,146.610 318.911,147.600 319.140 C 148.590 319.369,150.930 319.912,152.800 320.347 C 154.670 320.782,157.370 321.348,158.800 321.604 C 160.230 321.860,162.300 322.234,163.400 322.435 C 177.558 325.023,201.685 325.201,214.900 322.815 C 216.165 322.587,218.145 322.227,219.300 322.016 C 225.011 320.971,235.080 317.946,239.600 315.918 C 240.590 315.474,242.390 314.665,243.600 314.121 C 250.325 311.097,259.619 304.705,265.005 299.400 C 285.928 278.789,291.480 241.782,277.725 214.602 C 271.038 201.387,255.237 188.197,238.000 181.440 C 237.010 181.052,235.660 180.488,235.000 180.187 C 232.351 178.979,213.304 172.081,208.000 170.409 C 187.266 163.873,178.497 154.218,183.708 143.661 C 190.425 130.050,233.857 133.347,267.600 150.029 C 270.130 151.280,272.335 152.225,272.500 152.128 C 272.665 152.032,272.800 137.647,272.800 120.162 L 272.800 88.372 270.900 87.554 C 268.928 86.705,259.102 83.332,257.000 82.781 C 256.340 82.609,254.075 82.016,251.967 81.464 C 240.954 78.580,228.764 76.709,217.800 76.220 C 207.102 75.743,204.456 75.712,198.800 76.002 "
stroke="none" fill="#ffffff" fill-rule="evenodd"/>
<path id="path1"
d="M0.000 200.000 L 0.000 400.000 200.000 400.000 L 400.000 400.000 400.000 200.000 L 400.000 0.000 200.000 0.000 L 0.000 0.000 0.000 200.000 M217.800 76.220 C 228.764 76.709,240.954 78.580,251.967 81.464 C 254.075 82.016,256.340 82.609,257.000 82.781 C 259.102 83.332,268.928 86.705,270.900 87.554 L 272.800 88.372 272.800 120.162 C 272.800 137.647,272.665 152.032,272.500 152.128 C 272.335 152.225,270.130 151.280,267.600 150.029 C 233.857 133.347,190.425 130.050,183.708 143.661 C 178.497 154.218,187.266 163.873,208.000 170.409 C 213.304 172.081,232.351 178.979,235.000 180.187 C 235.660 180.488,237.010 181.052,238.000 181.440 C 255.237 188.197,271.038 201.387,277.725 214.602 C 291.480 241.782,285.928 278.789,265.005 299.400 C 259.619 304.705,250.325 311.097,243.600 314.121 C 242.390 314.665,240.590 315.474,239.600 315.918 C 235.080 317.946,225.011 320.971,219.300 322.016 C 218.145 322.227,216.165 322.587,214.900 322.815 C 201.685 325.201,177.558 325.023,163.400 322.435 C 162.300 322.234,160.230 321.860,158.800 321.604 C 157.370 321.348,154.670 320.782,152.800 320.347 C 150.930 319.912,148.590 319.369,147.600 319.140 C 146.610 318.911,145.350 318.582,144.800 318.408 C 144.250 318.235,142.990 317.864,142.000 317.584 C 133.794 315.264,119.725 309.975,118.900 308.899 C 118.271 308.079,118.159 244.996,118.786 244.609 C 118.998 244.478,122.463 245.972,126.486 247.928 C 141.875 255.414,154.801 260.064,167.800 262.789 C 169.120 263.065,170.740 263.436,171.400 263.612 C 172.060 263.788,174.130 264.142,176.000 264.398 C 177.870 264.655,180.495 265.030,181.833 265.232 C 187.804 266.135,199.139 265.564,204.800 264.076 C 219.950 260.095,220.392 241.770,205.534 233.636 C 198.386 229.722,195.215 228.384,179.400 222.609 C 173.763 220.551,165.453 217.270,162.490 215.933 C 161.109 215.310,159.892 214.800,159.785 214.800 C 159.236 214.800,149.302 209.748,146.011 207.795 C 135.581 201.605,127.040 193.356,121.869 184.479 C 121.061 183.092,120.400 181.885,120.400 181.797 C 120.400 181.708,119.874 180.503,119.231 179.118 C 118.588 177.733,117.708 175.520,117.276 174.200 C 116.577 172.064,116.306 171.043,115.418 167.200 C 112.933 156.448,113.910 140.585,117.820 128.200 C 124.260 107.805,142.177 90.045,163.600 82.824 C 165.030 82.342,166.560 81.783,167.000 81.583 C 167.440 81.382,169.510 80.763,171.600 80.207 C 175.057 79.288,177.677 78.714,183.400 77.623 C 187.099 76.918,192.960 76.301,198.800 76.002 C 204.456 75.712,207.102 75.743,217.800 76.220 "
stroke="none" fill="#635bff" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,31 @@
import verifyCredentials from "./verify-credentials";
import isStillVerified from "./is-still-verified";
export default {
fields: [
{
key: 'secretKey',
label: 'Secret Key',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: null,
clickToCopy: false,
},
{
key: 'displayName',
label: 'Account Name',
type: 'string' as const,
required: true,
readOnly: false,
value: null,
placeholder: null,
description: 'The display name that identifies this stripe connection - most likely the associated account name',
clickToCopy: false,
},
],
verifyCredentials,
isStillVerified
};

View File

@@ -0,0 +1,9 @@
import { IGlobalVariable } from '@automatisch/types';
import verifyCredentials from "./verify-credentials";
const isStillVerified = async ($: IGlobalVariable) => {
await verifyCredentials($);
return true;
};
export default isStillVerified;

View File

@@ -0,0 +1,12 @@
import { IGlobalVariable } from '@automatisch/types';
const verifyCredentials = async ($: IGlobalVariable) => {
await $.http.get(
`/v1/events`,
);
await $.auth.set({
screenName: $.auth.data?.displayName,
});
};
export default verifyCredentials;

View File

@@ -0,0 +1,8 @@
import {TBeforeRequest} from "@automatisch/types";
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
requestConfig.headers['Authorization'] = `Bearer ${$.auth.data?.secretKey}`
return requestConfig
}
export default addAuthHeader;

View File

View File

@@ -0,0 +1,19 @@
import defineApp from "../../helpers/define-app";
import addAuthHeader from "./common/add-auth-header";
import auth from "./auth"
import triggers from "./triggers"
export default defineApp({
name: 'Stripe',
key: 'stripe',
iconUrl: '{BASE_URL}/apps/stripe/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/stripe/connection',
supportsConnections: true,
baseUrl: 'https://stripe.com',
apiBaseUrl: 'https://api.stripe.com',
primaryColor: '635bff',
beforeRequest: [addAuthHeader],
auth,
triggers,
actions: [],
})

View File

@@ -0,0 +1,32 @@
import {IGlobalVariable, IJSONObject} from "@automatisch/types";
import {URLSearchParams} from "url";
import {isEmpty, omitBy} from "lodash";
const getBalanceTransactions = async ($: IGlobalVariable) => {
let response;
let lastId = undefined;
do {
const params: IJSONObject = {
starting_after: lastId,
ending_before: $.flow.lastInternalId
}
const queryParams = new URLSearchParams(omitBy(params, isEmpty))
const requestPath = `/v1/balance_transactions${
queryParams.toString() ? `?${queryParams.toString()}` : ''
}`;
response = (await $.http.get(requestPath)).data
for (const entry of response.data) {
$.pushTriggerItem({
raw: entry,
meta: {
internalId: entry.id as string
}
})
lastId = entry.id
}
} while (response.has_more)
};
export default getBalanceTransactions;

View File

@@ -0,0 +1,12 @@
import defineTrigger from "../../../../helpers/define-trigger";
import getBalanceTransactions from "./get-balance-transactions";
export default defineTrigger({
name: 'New Balance Transactions',
key: 'newBalanceTransactions',
description: 'Triggers when a new transaction is processed (refund, payout, adjustment, ...)',
pollInterval: 15,
async run($) {
await getBalanceTransactions($)
}
})

Some files were not shown because too many files have changed in this diff Show More