Compare commits
1 Commits
AUT-1324
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1f93f3b262 |
4
.github/workflows/playwright.yml
vendored
4
.github/workflows/playwright.yml
vendored
@@ -12,9 +12,6 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BULLMQ_DASHBOARD_USERNAME: root
|
|
||||||
BULLMQ_DASHBOARD_PASSWORD: sample
|
|
||||||
ENABLE_BULLMQ_DASHBOARD: true
|
|
||||||
ENCRYPTION_KEY: sample_encryption_key
|
ENCRYPTION_KEY: sample_encryption_key
|
||||||
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
WEBHOOK_SECRET_KEY: sample_webhook_secret_key
|
||||||
APP_SECRET_KEY: sample_app_secret_key
|
APP_SECRET_KEY: sample_app_secret_key
|
||||||
@@ -25,7 +22,6 @@ env:
|
|||||||
POSTGRES_PASSWORD: automatisch_password
|
POSTGRES_PASSWORD: automatisch_password
|
||||||
REDIS_HOST: localhost
|
REDIS_HOST: localhost
|
||||||
APP_ENV: production
|
APP_ENV: production
|
||||||
PORT: 3000
|
|
||||||
LICENSE_KEY: dummy_license_key
|
LICENSE_KEY: dummy_license_key
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
@@ -36,7 +36,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.18.2",
|
"express": "~4.20.0",
|
||||||
"express-async-errors": "^3.1.1",
|
"express-async-errors": "^3.1.1",
|
||||||
"express-basic-auth": "^1.2.1",
|
"express-basic-auth": "^1.2.1",
|
||||||
"fast-xml-parser": "^4.0.11",
|
"fast-xml-parser": "^4.0.11",
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.airtable.com',
|
apiBaseUrl: 'https://api.airtable.com',
|
||||||
iconUrl: '{BASE_URL}/apps/airtable/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/airtable/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/airtable/connection',
|
authDocUrl: '{DOCS_URL}/apps/airtable/connection',
|
||||||
primaryColor: '#FFBF00',
|
primaryColor: 'FFBF00',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://cloud.appwrite.io',
|
apiBaseUrl: 'https://cloud.appwrite.io',
|
||||||
iconUrl: '{BASE_URL}/apps/appwrite/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/appwrite/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/appwrite/connection',
|
authDocUrl: '{DOCS_URL}/apps/appwrite/connection',
|
||||||
primaryColor: '#FD366E',
|
primaryColor: 'FD366E',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/azure-openai/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/azure-openai/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/azure-openai/connection',
|
authDocUrl: '{DOCS_URL}/apps/azure-openai/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://carbone.io',
|
baseUrl: 'https://carbone.io',
|
||||||
apiBaseUrl: 'https://api.carbone.io',
|
apiBaseUrl: 'https://api.carbone.io',
|
||||||
primaryColor: '#6f42c1',
|
primaryColor: '6f42c1',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -12,8 +12,8 @@ export default defineApp({
|
|||||||
baseUrl: 'https://clickup.com',
|
baseUrl: 'https://clickup.com',
|
||||||
apiBaseUrl: 'https://api.clickup.com/api',
|
apiBaseUrl: 'https://api.clickup.com/api',
|
||||||
iconUrl: '{BASE_URL}/apps/clickup/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/clickup/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/clickup/connection',
|
authDocUrl: 'https://automatisch.io/docs/apps/clickup/connection',
|
||||||
primaryColor: '#FD71AF',
|
primaryColor: 'FD71AF',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -8,7 +8,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/code/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/code/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/code/connection',
|
authDocUrl: '{DOCS_URL}/apps/code/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -9,6 +9,6 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#001F52',
|
primaryColor: '001F52',
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -9,6 +9,6 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#001F52',
|
primaryColor: '001F52',
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://deepl.com',
|
baseUrl: 'https://deepl.com',
|
||||||
apiBaseUrl: 'https://api.deepl.com',
|
apiBaseUrl: 'https://api.deepl.com',
|
||||||
primaryColor: '#0d2d45',
|
primaryColor: '0d2d45',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -9,6 +9,6 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#001F52',
|
primaryColor: '001F52',
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -14,7 +14,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://discord.com',
|
baseUrl: 'https://discord.com',
|
||||||
apiBaseUrl: 'https://discord.com/api',
|
apiBaseUrl: 'https://discord.com/api',
|
||||||
primaryColor: '#5865f2',
|
primaryColor: '5865f2',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
dynamicData,
|
dynamicData,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://disqus.com/api',
|
apiBaseUrl: 'https://disqus.com/api',
|
||||||
iconUrl: '{BASE_URL}/apps/disqus/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/disqus/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/disqus/connection',
|
authDocUrl: '{DOCS_URL}/apps/disqus/connection',
|
||||||
primaryColor: '#2E9FFF',
|
primaryColor: '2E9FFF',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://dropbox.com',
|
baseUrl: 'https://dropbox.com',
|
||||||
apiBaseUrl: 'https://api.dropboxapi.com',
|
apiBaseUrl: 'https://api.dropboxapi.com',
|
||||||
primaryColor: '#0061ff',
|
primaryColor: '0061ff',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -9,6 +9,6 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#001F52',
|
primaryColor: '001F52',
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
iconUrl: '{BASE_URL}/apps/flickr/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/flickr/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/flickr/connection',
|
authDocUrl: '{DOCS_URL}/apps/flickr/connection',
|
||||||
docUrl: 'https://automatisch.io/docs/flickr',
|
docUrl: 'https://automatisch.io/docs/flickr',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://www.flickr.com/',
|
baseUrl: 'https://www.flickr.com/',
|
||||||
apiBaseUrl: 'https://www.flickr.com/services',
|
apiBaseUrl: 'https://www.flickr.com/services',
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://flowers-software.com',
|
baseUrl: 'https://flowers-software.com',
|
||||||
apiBaseUrl: 'https://webapp.flowers-software.com/api',
|
apiBaseUrl: 'https://webapp.flowers-software.com/api',
|
||||||
primaryColor: '#02AFC7',
|
primaryColor: '02AFC7',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#001F52',
|
primaryColor: '001F52',
|
||||||
actions,
|
actions,
|
||||||
dynamicFields,
|
dynamicFields,
|
||||||
});
|
});
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/ghost/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/ghost/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/ghost/connection',
|
authDocUrl: '{DOCS_URL}/apps/ghost/connection',
|
||||||
primaryColor: '#15171A',
|
primaryColor: '15171A',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.github.com',
|
apiBaseUrl: 'https://api.github.com',
|
||||||
iconUrl: '{BASE_URL}/apps/github/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/github/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/github/connection',
|
authDocUrl: '{DOCS_URL}/apps/github/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://gitlab.com',
|
apiBaseUrl: 'https://gitlab.com',
|
||||||
iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/gitlab/connection',
|
authDocUrl: '{DOCS_URL}/apps/gitlab/connection',
|
||||||
primaryColor: '#FC6D26',
|
primaryColor: 'FC6D26',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://www.googleapis.com/calendar',
|
apiBaseUrl: 'https://www.googleapis.com/calendar',
|
||||||
iconUrl: '{BASE_URL}/apps/google-calendar/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/google-calendar/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/google-calendar/connection',
|
authDocUrl: '{DOCS_URL}/apps/google-calendar/connection',
|
||||||
primaryColor: '#448AFF',
|
primaryColor: '448AFF',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://www.googleapis.com/drive',
|
apiBaseUrl: 'https://www.googleapis.com/drive',
|
||||||
iconUrl: '{BASE_URL}/apps/google-drive/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/google-drive/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/google-drive/connection',
|
authDocUrl: '{DOCS_URL}/apps/google-drive/connection',
|
||||||
primaryColor: '#1FA463',
|
primaryColor: '1FA463',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://forms.googleapis.com',
|
apiBaseUrl: 'https://forms.googleapis.com',
|
||||||
iconUrl: '{BASE_URL}/apps/google-forms/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/google-forms/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/google-forms/connection',
|
authDocUrl: '{DOCS_URL}/apps/google-forms/connection',
|
||||||
primaryColor: '#673AB7',
|
primaryColor: '673AB7',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://sheets.googleapis.com',
|
apiBaseUrl: 'https://sheets.googleapis.com',
|
||||||
iconUrl: '{BASE_URL}/apps/google-sheets/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/google-sheets/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/google-sheets/connection',
|
authDocUrl: '{DOCS_URL}/apps/google-sheets/connection',
|
||||||
primaryColor: '#0F9D58',
|
primaryColor: '0F9D58',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://tasks.googleapis.com',
|
apiBaseUrl: 'https://tasks.googleapis.com',
|
||||||
iconUrl: '{BASE_URL}/apps/google-tasks/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/google-tasks/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/google-tasks/connection',
|
authDocUrl: '{DOCS_URL}/apps/google-tasks/connection',
|
||||||
primaryColor: '#0066DA',
|
primaryColor: '0066DA',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://app.tryhelix.ai',
|
apiBaseUrl: 'https://app.tryhelix.ai',
|
||||||
iconUrl: '{BASE_URL}/apps/helix/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/helix/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/helix/connection',
|
authDocUrl: '{DOCS_URL}/apps/helix/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -9,6 +9,6 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://www.hubspot.com',
|
baseUrl: 'https://www.hubspot.com',
|
||||||
apiBaseUrl: 'https://api.hubapi.com',
|
apiBaseUrl: 'https://api.hubapi.com',
|
||||||
primaryColor: '#F95C35',
|
primaryColor: 'F95C35',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://invoicing.co/api',
|
apiBaseUrl: 'https://invoicing.co/api',
|
||||||
iconUrl: '{BASE_URL}/apps/invoice-ninja/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/invoice-ninja/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/invoice-ninja/connection',
|
authDocUrl: '{DOCS_URL}/apps/invoice-ninja/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -9,11 +9,11 @@ export default defineApp({
|
|||||||
name: 'Jotform',
|
name: 'Jotform',
|
||||||
key: 'jotform',
|
key: 'jotform',
|
||||||
iconUrl: '{BASE_URL}/apps/jotform/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/jotform/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/jotform/connection',
|
authDocUrl: 'https://automatisch.io/docs/apps/jotform/connection',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://www.jotform.com',
|
baseUrl: 'https://www.jotform.com',
|
||||||
apiBaseUrl: 'https://api.jotform.com',
|
apiBaseUrl: 'https://api.jotform.com',
|
||||||
primaryColor: '#FF6100',
|
primaryColor: 'FF6100',
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -12,8 +12,8 @@ export default defineApp({
|
|||||||
baseUrl: 'https://mailchimp.com',
|
baseUrl: 'https://mailchimp.com',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/mailchimp/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/mailchimp/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/mailchimp/connection',
|
authDocUrl: 'https://automatisch.io/docs/apps/mailchimp/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -7,11 +7,11 @@ export default defineApp({
|
|||||||
name: 'MailerLite',
|
name: 'MailerLite',
|
||||||
key: 'mailerlite',
|
key: 'mailerlite',
|
||||||
iconUrl: '{BASE_URL}/apps/mailerlite/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/mailerlite/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/mailerlite/connection',
|
authDocUrl: 'https://automatisch.io/docs/apps/mailerlite/connection',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://www.mailerlite.com',
|
baseUrl: 'https://www.mailerlite.com',
|
||||||
apiBaseUrl: 'https://connect.mailerlite.com/api',
|
apiBaseUrl: 'https://connect.mailerlite.com/api',
|
||||||
primaryColor: '#09C269',
|
primaryColor: '09C269',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
authDocUrl: '{DOCS_URL}/apps/mattermost/connection',
|
authDocUrl: '{DOCS_URL}/apps/mattermost/connection',
|
||||||
baseUrl: 'https://mattermost.com',
|
baseUrl: 'https://mattermost.com',
|
||||||
apiBaseUrl: '', // there is no cloud version of this app, user always need to provide address of own instance when creating connection
|
apiBaseUrl: '', // there is no cloud version of this app, user always need to provide address of own instance when creating connection
|
||||||
primaryColor: '#4a154b',
|
primaryColor: '4a154b',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addXRequestedWithHeader, addAuthHeader],
|
beforeRequest: [setBaseUrl, addXRequestedWithHeader, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.miro.com',
|
apiBaseUrl: 'https://api.miro.com',
|
||||||
iconUrl: '{BASE_URL}/apps/miro/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/miro/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/miro/connection',
|
authDocUrl: '{DOCS_URL}/apps/miro/connection',
|
||||||
primaryColor: '#F2CA02',
|
primaryColor: 'F2CA02',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.notion.com',
|
apiBaseUrl: 'https://api.notion.com',
|
||||||
iconUrl: '{BASE_URL}/apps/notion/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/notion/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/notion/connection',
|
authDocUrl: '{DOCS_URL}/apps/notion/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader, addNotionVersionHeader],
|
beforeRequest: [addAuthHeader, addNotionVersionHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://ntfy.sh',
|
baseUrl: 'https://ntfy.sh',
|
||||||
apiBaseUrl: 'https://ntfy.sh',
|
apiBaseUrl: 'https://ntfy.sh',
|
||||||
primaryColor: '#56bda8',
|
primaryColor: '56bda8',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://odoo.com',
|
baseUrl: 'https://odoo.com',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#9c5789',
|
primaryColor: '9c5789',
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.openai.com',
|
apiBaseUrl: 'https://api.openai.com',
|
||||||
iconUrl: '{BASE_URL}/apps/openai/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/openai/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/openai/connection',
|
authDocUrl: '{DOCS_URL}/apps/openai/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/pipedrive/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/pipedrive/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/pipedrive/connection',
|
authDocUrl: '{DOCS_URL}/apps/pipedrive/connection',
|
||||||
primaryColor: '#FFFFFF',
|
primaryColor: 'FFFFFF',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://placetel.de',
|
baseUrl: 'https://placetel.de',
|
||||||
apiBaseUrl: 'https://api.placetel.de',
|
apiBaseUrl: 'https://api.placetel.de',
|
||||||
primaryColor: '#069dd9',
|
primaryColor: '069dd9',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#336791',
|
primaryColor: '336791',
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.pushover.net',
|
apiBaseUrl: 'https://api.pushover.net',
|
||||||
iconUrl: '{BASE_URL}/apps/pushover/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/pushover/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/pushover/connection',
|
authDocUrl: '{DOCS_URL}/apps/pushover/connection',
|
||||||
primaryColor: '#249DF1',
|
primaryColor: '249DF1',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://oauth.reddit.com',
|
apiBaseUrl: 'https://oauth.reddit.com',
|
||||||
iconUrl: '{BASE_URL}/apps/reddit/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/reddit/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/reddit/connection',
|
authDocUrl: '{DOCS_URL}/apps/reddit/connection',
|
||||||
primaryColor: '#FF4500',
|
primaryColor: 'FF4500',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://www.remove.bg',
|
baseUrl: 'https://www.remove.bg',
|
||||||
apiBaseUrl: 'https://api.remove.bg/v1.0',
|
apiBaseUrl: 'https://api.remove.bg/v1.0',
|
||||||
primaryColor: '#55636c',
|
primaryColor: '55636c',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -9,6 +9,6 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#ff8800',
|
primaryColor: 'ff8800',
|
||||||
triggers,
|
triggers,
|
||||||
});
|
});
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://salesforce.com',
|
baseUrl: 'https://salesforce.com',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#00A1E0',
|
primaryColor: '00A1E0',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -9,7 +9,7 @@ export default defineApp({
|
|||||||
authDocUrl: '{DOCS_URL}/apps/scheduler/connection',
|
authDocUrl: '{DOCS_URL}/apps/scheduler/connection',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#0059F7',
|
primaryColor: '0059F7',
|
||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
triggers,
|
triggers,
|
||||||
});
|
});
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/self-hosted-llm/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/self-hosted-llm/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/self-hosted-llm/connection',
|
authDocUrl: '{DOCS_URL}/apps/self-hosted-llm/connection',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://signalwire.com',
|
baseUrl: 'https://signalwire.com',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#044cf6',
|
primaryColor: '044cf6',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://slack.com',
|
baseUrl: 'https://slack.com',
|
||||||
apiBaseUrl: 'https://slack.com/api',
|
apiBaseUrl: 'https://slack.com/api',
|
||||||
primaryColor: '#4a154b',
|
primaryColor: '4a154b',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#2DAAE1',
|
primaryColor: '2DAAE1',
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
});
|
});
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://spotify.com',
|
baseUrl: 'https://spotify.com',
|
||||||
apiBaseUrl: 'https://api.spotify.com',
|
apiBaseUrl: 'https://api.spotify.com',
|
||||||
primaryColor: '#000000',
|
primaryColor: '000000',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://www.strava.com',
|
baseUrl: 'https://www.strava.com',
|
||||||
apiBaseUrl: 'https://www.strava.com/api',
|
apiBaseUrl: 'https://www.strava.com/api',
|
||||||
primaryColor: '#fc4c01',
|
primaryColor: 'fc4c01',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://stripe.com',
|
baseUrl: 'https://stripe.com',
|
||||||
apiBaseUrl: 'https://api.stripe.com',
|
apiBaseUrl: 'https://api.stripe.com',
|
||||||
primaryColor: '#635bff',
|
primaryColor: '635bff',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://telegram.org',
|
baseUrl: 'https://telegram.org',
|
||||||
apiBaseUrl: 'https://api.telegram.org',
|
apiBaseUrl: 'https://api.telegram.org',
|
||||||
primaryColor: '#2AABEE',
|
primaryColor: '2AABEE',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://todoist.com',
|
baseUrl: 'https://todoist.com',
|
||||||
apiBaseUrl: 'https://api.todoist.com/rest/v2',
|
apiBaseUrl: 'https://api.todoist.com/rest/v2',
|
||||||
primaryColor: '#e44332',
|
primaryColor: 'e44332',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
iconUrl: '{BASE_URL}/apps/trello/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/trello/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/trello/connection',
|
authDocUrl: '{DOCS_URL}/apps/trello/connection',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
primaryColor: '#0079bf',
|
primaryColor: '0079bf',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
actions,
|
actions,
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://twilio.com',
|
baseUrl: 'https://twilio.com',
|
||||||
apiBaseUrl: 'https://api.twilio.com',
|
apiBaseUrl: 'https://api.twilio.com',
|
||||||
primaryColor: '#e1000f',
|
primaryColor: 'e1000f',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://twitter.com',
|
baseUrl: 'https://twitter.com',
|
||||||
apiBaseUrl: 'https://api.twitter.com',
|
apiBaseUrl: 'https://api.twitter.com',
|
||||||
primaryColor: '#1da1f2',
|
primaryColor: '1da1f2',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://typeform.com',
|
baseUrl: 'https://typeform.com',
|
||||||
apiBaseUrl: 'https://api.typeform.com',
|
apiBaseUrl: 'https://api.typeform.com',
|
||||||
primaryColor: '#262627',
|
primaryColor: '262627',
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -14,7 +14,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#39a86d',
|
primaryColor: '39a86d',
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
supportsConnections: false,
|
supportsConnections: false,
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#0059F7',
|
primaryColor: '0059F7',
|
||||||
actions,
|
actions,
|
||||||
triggers,
|
triggers,
|
||||||
});
|
});
|
||||||
|
@@ -13,7 +13,7 @@ export default defineApp({
|
|||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
baseUrl: 'https://wordpress.com',
|
baseUrl: 'https://wordpress.com',
|
||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
primaryColor: '#464342',
|
primaryColor: '464342',
|
||||||
beforeRequest: [setBaseUrl, addAuthHeader],
|
beforeRequest: [setBaseUrl, addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
|
@@ -11,7 +11,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.xero.com',
|
apiBaseUrl: 'https://api.xero.com',
|
||||||
iconUrl: '{BASE_URL}/apps/xero/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/xero/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/xero/connection',
|
authDocUrl: '{DOCS_URL}/apps/xero/connection',
|
||||||
primaryColor: '#13B5EA',
|
primaryColor: '13B5EA',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://api.ynab.com/v1',
|
apiBaseUrl: 'https://api.ynab.com/v1',
|
||||||
iconUrl: '{BASE_URL}/apps/you-need-a-budget/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/you-need-a-budget/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/you-need-a-budget/connection',
|
authDocUrl: '{DOCS_URL}/apps/you-need-a-budget/connection',
|
||||||
primaryColor: '#19223C',
|
primaryColor: '19223C',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -10,7 +10,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: 'https://www.googleapis.com/youtube',
|
apiBaseUrl: 'https://www.googleapis.com/youtube',
|
||||||
iconUrl: '{BASE_URL}/apps/youtube/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/youtube/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/youtube/connection',
|
authDocUrl: '{DOCS_URL}/apps/youtube/connection',
|
||||||
primaryColor: '#FF0000',
|
primaryColor: 'FF0000',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -12,7 +12,7 @@ export default defineApp({
|
|||||||
apiBaseUrl: '',
|
apiBaseUrl: '',
|
||||||
iconUrl: '{BASE_URL}/apps/zendesk/assets/favicon.svg',
|
iconUrl: '{BASE_URL}/apps/zendesk/assets/favicon.svg',
|
||||||
authDocUrl: '{DOCS_URL}/apps/zendesk/connection',
|
authDocUrl: '{DOCS_URL}/apps/zendesk/connection',
|
||||||
primaryColor: '#17494d',
|
primaryColor: '17494d',
|
||||||
supportsConnections: true,
|
supportsConnections: true,
|
||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
|
@@ -1,28 +1,23 @@
|
|||||||
|
import pick from 'lodash/pick.js';
|
||||||
import { renderObject } from '../../../../../helpers/renderer.js';
|
import { renderObject } from '../../../../../helpers/renderer.js';
|
||||||
import Config from '../../../../../models/config.js';
|
import Config from '../../../../../models/config.js';
|
||||||
|
|
||||||
export default async (request, response) => {
|
export default async (request, response) => {
|
||||||
const config = await Config.query().updateFirstOrInsert(
|
const config = configParams(request);
|
||||||
configParams(request)
|
|
||||||
);
|
await Config.batchUpdate(config);
|
||||||
|
|
||||||
renderObject(response, config);
|
renderObject(response, config);
|
||||||
};
|
};
|
||||||
|
|
||||||
const configParams = (request) => {
|
const configParams = (request) => {
|
||||||
const {
|
const updatableConfigurationKeys = [
|
||||||
logoSvgData,
|
'logo.svgData',
|
||||||
palettePrimaryDark,
|
'palette.primary.dark',
|
||||||
palettePrimaryLight,
|
'palette.primary.light',
|
||||||
palettePrimaryMain,
|
'palette.primary.main',
|
||||||
title,
|
'title',
|
||||||
} = request.body;
|
];
|
||||||
|
|
||||||
return {
|
return pick(request.body, updatableConfigurationKeys);
|
||||||
logoSvgData,
|
|
||||||
palettePrimaryDark,
|
|
||||||
palettePrimaryLight,
|
|
||||||
palettePrimaryMain,
|
|
||||||
title,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
@@ -5,7 +5,7 @@ import app from '../../../../../app.js';
|
|||||||
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
|
import createAuthTokenByUserId from '../../../../../helpers/create-auth-token-by-user-id.js';
|
||||||
import { createUser } from '../../../../../../test/factories/user.js';
|
import { createUser } from '../../../../../../test/factories/user.js';
|
||||||
import { createRole } from '../../../../../../test/factories/role.js';
|
import { createRole } from '../../../../../../test/factories/role.js';
|
||||||
import { updateConfig } from '../../../../../../test/factories/config.js';
|
import { createBulkConfig } from '../../../../../../test/factories/config.js';
|
||||||
import * as license from '../../../../../helpers/license.ee.js';
|
import * as license from '../../../../../helpers/license.ee.js';
|
||||||
|
|
||||||
describe('PATCH /api/v1/admin/config', () => {
|
describe('PATCH /api/v1/admin/config', () => {
|
||||||
@@ -30,13 +30,13 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
|
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
title,
|
title,
|
||||||
palettePrimaryMain: palettePrimaryMain,
|
'palette.primary.main': palettePrimaryMain,
|
||||||
palettePrimaryDark: palettePrimaryDark,
|
'palette.primary.dark': palettePrimaryDark,
|
||||||
palettePrimaryLight: palettePrimaryLight,
|
'palette.primary.light': palettePrimaryLight,
|
||||||
logoSvgData: logoSvgData,
|
'logo.svgData': logoSvgData,
|
||||||
};
|
};
|
||||||
|
|
||||||
await updateConfig(appConfig);
|
await createBulkConfig(appConfig);
|
||||||
|
|
||||||
const newTitle = 'Updated title';
|
const newTitle = 'Updated title';
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.title).toEqual(newTitle);
|
expect(response.body.data.title).toEqual(newTitle);
|
||||||
expect(response.body.meta.type).toEqual('Config');
|
expect(response.body.meta.type).toEqual('Object');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return created config for unexisting config', async () => {
|
it('should return created config for unexisting config', async () => {
|
||||||
@@ -68,7 +68,7 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.title).toEqual(newTitle);
|
expect(response.body.data.title).toEqual(newTitle);
|
||||||
expect(response.body.meta.type).toEqual('Config');
|
expect(response.body.meta.type).toEqual('Object');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null for deleted config entry', async () => {
|
it('should return null for deleted config entry', async () => {
|
||||||
@@ -83,6 +83,6 @@ describe('PATCH /api/v1/admin/config', () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.data.title).toBeNull();
|
expect(response.body.data.title).toBeNull();
|
||||||
expect(response.body.meta.type).toEqual('Config');
|
expect(response.body.meta.type).toEqual('Object');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,8 +1,25 @@
|
|||||||
|
import appConfig from '../../../../config/app.js';
|
||||||
import Config from '../../../../models/config.js';
|
import Config from '../../../../models/config.js';
|
||||||
import { renderObject } from '../../../../helpers/renderer.js';
|
import { renderObject } from '../../../../helpers/renderer.js';
|
||||||
|
|
||||||
export default async (request, response) => {
|
export default async (request, response) => {
|
||||||
const config = await Config.get();
|
const defaultConfig = {
|
||||||
|
disableNotificationsPage: appConfig.disableNotificationsPage,
|
||||||
|
disableFavicon: appConfig.disableFavicon,
|
||||||
|
additionalDrawerLink: appConfig.additionalDrawerLink,
|
||||||
|
additionalDrawerLinkIcon: appConfig.additionalDrawerLinkIcon,
|
||||||
|
additionalDrawerLinkText: appConfig.additionalDrawerLinkText,
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = await Config.query().orderBy('key', 'asc');
|
||||||
|
|
||||||
|
config = config.reduce((computedConfig, configEntry) => {
|
||||||
|
const { key, value } = configEntry;
|
||||||
|
|
||||||
|
computedConfig[key] = value?.data;
|
||||||
|
|
||||||
|
return computedConfig;
|
||||||
|
}, defaultConfig);
|
||||||
|
|
||||||
renderObject(response, config);
|
renderObject(response, config);
|
||||||
};
|
};
|
||||||
|
@@ -1,47 +1,66 @@
|
|||||||
import { vi, expect, describe, it } from 'vitest';
|
import { vi, expect, describe, it } from 'vitest';
|
||||||
import request from 'supertest';
|
import request from 'supertest';
|
||||||
import { updateConfig } from '../../../../../test/factories/config.js';
|
import { createConfig } from '../../../../../test/factories/config.js';
|
||||||
import app from '../../../../app.js';
|
import app from '../../../../app.js';
|
||||||
import configMock from '../../../../../test/mocks/rest/api/v1/automatisch/config.js';
|
import configMock from '../../../../../test/mocks/rest/api/v1/automatisch/config.js';
|
||||||
import * as license from '../../../../helpers/license.ee.js';
|
import * as license from '../../../../helpers/license.ee.js';
|
||||||
import appConfig from '../../../../config/app.js';
|
import appConfig from '../../../../config/app.js';
|
||||||
|
|
||||||
describe('GET /api/v1/automatisch/config', () => {
|
describe('GET /api/v1/automatisch/config', () => {
|
||||||
it('should return Automatisch config along with static config', async () => {
|
it('should return Automatisch config', async () => {
|
||||||
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
|
||||||
vi.spyOn(appConfig, 'disableNotificationsPage', 'get').mockReturnValue(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
vi.spyOn(appConfig, 'disableFavicon', 'get').mockReturnValue(true);
|
|
||||||
vi.spyOn(appConfig, 'additionalDrawerLink', 'get').mockReturnValue('link');
|
|
||||||
vi.spyOn(appConfig, 'additionalDrawerLinkIcon', 'get').mockReturnValue(
|
|
||||||
'icon'
|
|
||||||
);
|
|
||||||
vi.spyOn(appConfig, 'additionalDrawerLinkText', 'get').mockReturnValue(
|
|
||||||
'text'
|
|
||||||
);
|
|
||||||
|
|
||||||
const config = await updateConfig({
|
const logoConfig = await createConfig({
|
||||||
logoSvgData: '<svg>Sample</svg>',
|
key: 'logo.svgData',
|
||||||
palettePrimaryDark: '#001f52',
|
value: { data: '<svg>Sample</svg>' },
|
||||||
palettePrimaryLight: '#4286FF',
|
});
|
||||||
palettePrimaryMain: '#0059F7',
|
|
||||||
title: 'Sample Title',
|
const primaryDarkConfig = await createConfig({
|
||||||
|
key: 'palette.primary.dark',
|
||||||
|
value: { data: '#001F52' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const primaryLightConfig = await createConfig({
|
||||||
|
key: 'palette.primary.light',
|
||||||
|
value: { data: '#4286FF' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const primaryMainConfig = await createConfig({
|
||||||
|
key: 'palette.primary.main',
|
||||||
|
value: { data: '#0059F7' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const titleConfig = await createConfig({
|
||||||
|
key: 'title',
|
||||||
|
value: { data: 'Sample Title' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.get('/api/v1/automatisch/config')
|
.get('/api/v1/automatisch/config')
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const expectedPayload = configMock({
|
const expectedPayload = configMock(
|
||||||
...config,
|
logoConfig,
|
||||||
disableNotificationsPage: true,
|
primaryDarkConfig,
|
||||||
disableFavicon: true,
|
primaryLightConfig,
|
||||||
additionalDrawerLink: 'link',
|
primaryMainConfig,
|
||||||
additionalDrawerLinkIcon: 'icon',
|
titleConfig
|
||||||
additionalDrawerLinkText: 'text',
|
);
|
||||||
|
|
||||||
|
expect(response.body).toEqual(expectedPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(response.body).toStrictEqual(expectedPayload);
|
it('should return additional environment variables', async () => {
|
||||||
|
vi.spyOn(appConfig, 'disableNotificationsPage', 'get').mockReturnValue(true);
|
||||||
|
vi.spyOn(appConfig, 'disableFavicon', 'get').mockReturnValue(true);
|
||||||
|
vi.spyOn(appConfig, 'additionalDrawerLink', 'get').mockReturnValue('link');
|
||||||
|
vi.spyOn(appConfig, 'additionalDrawerLinkIcon', 'get').mockReturnValue('icon');
|
||||||
|
vi.spyOn(appConfig, 'additionalDrawerLinkText', 'get').mockReturnValue('text');
|
||||||
|
|
||||||
|
expect(appConfig.disableNotificationsPage).toEqual(true);
|
||||||
|
expect(appConfig.disableFavicon).toEqual(true);
|
||||||
|
expect(appConfig.additionalDrawerLink).toEqual('link');
|
||||||
|
expect(appConfig.additionalDrawerLinkIcon).toEqual('icon');
|
||||||
|
expect(appConfig.additionalDrawerLinkText).toEqual('text');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -5,7 +5,7 @@ import Config from '../../../../../models/config.js';
|
|||||||
import User from '../../../../../models/user.js';
|
import User from '../../../../../models/user.js';
|
||||||
import { createRole } from '../../../../../../test/factories/role';
|
import { createRole } from '../../../../../../test/factories/role';
|
||||||
import { createUser } from '../../../../../../test/factories/user';
|
import { createUser } from '../../../../../../test/factories/user';
|
||||||
import { markInstallationCompleted } from '../../../../../../test/factories/config';
|
import { createInstallationCompletedConfig } from '../../../../../../test/factories/config';
|
||||||
|
|
||||||
describe('POST /api/v1/installation/users', () => {
|
describe('POST /api/v1/installation/users', () => {
|
||||||
let adminRole;
|
let adminRole;
|
||||||
@@ -59,7 +59,7 @@ describe('POST /api/v1/installation/users', () => {
|
|||||||
|
|
||||||
describe('for completed installations', () => {
|
describe('for completed installations', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await markInstallationCompleted();
|
await createInstallationCompletedConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should respond with HTTP 403 when installation completed', async () => {
|
it('should respond with HTTP 403 when installation completed', async () => {
|
||||||
|
@@ -1,105 +0,0 @@
|
|||||||
export async function up(knex) {
|
|
||||||
await knex.schema.alterTable('config', (table) => {
|
|
||||||
table.dropUnique('key');
|
|
||||||
|
|
||||||
table.string('key').nullable().alter();
|
|
||||||
table.boolean('installation_completed').defaultTo(false);
|
|
||||||
table.text('logo_svg_data');
|
|
||||||
table.text('palette_primary_dark');
|
|
||||||
table.text('palette_primary_light');
|
|
||||||
table.text('palette_primary_main');
|
|
||||||
table.string('title');
|
|
||||||
});
|
|
||||||
|
|
||||||
const config = await knex('config').select('key', 'value');
|
|
||||||
|
|
||||||
const newConfigData = {
|
|
||||||
logo_svg_data: getValueForKey(config, 'logo.svgData'),
|
|
||||||
palette_primary_dark: getValueForKey(config, 'palette.primary.dark'),
|
|
||||||
palette_primary_light: getValueForKey(config, 'palette.primary.light'),
|
|
||||||
palette_primary_main: getValueForKey(config, 'palette.primary.main'),
|
|
||||||
title: getValueForKey(config, 'title'),
|
|
||||||
installation_completed: getValueForKey(config, 'installation.completed'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const [configEntry] = await knex('config')
|
|
||||||
.insert(newConfigData)
|
|
||||||
.select('id')
|
|
||||||
.returning('id');
|
|
||||||
|
|
||||||
await knex('config').where('id', '!=', configEntry.id).delete();
|
|
||||||
|
|
||||||
await knex.schema.alterTable('config', (table) => {
|
|
||||||
table.dropColumn('key');
|
|
||||||
table.dropColumn('value');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down(knex) {
|
|
||||||
await knex.schema.alterTable('config', (table) => {
|
|
||||||
table.string('key');
|
|
||||||
table.jsonb('value').notNullable().defaultTo({});
|
|
||||||
});
|
|
||||||
|
|
||||||
const configRow = await knex('config').first();
|
|
||||||
|
|
||||||
const config = [
|
|
||||||
{
|
|
||||||
key: 'logo.svgData',
|
|
||||||
value: {
|
|
||||||
data: configRow.logo_svg_data,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'palette.primary.dark',
|
|
||||||
value: {
|
|
||||||
data: configRow.palette_primary_dark,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'palette.primary.light',
|
|
||||||
value: {
|
|
||||||
data: configRow.palette_primary_light,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'palette.primary.main',
|
|
||||||
value: {
|
|
||||||
data: configRow.palette_primary_main,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'title',
|
|
||||||
value: {
|
|
||||||
data: configRow.title,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'installation.completed',
|
|
||||||
value: {
|
|
||||||
data: configRow.installation_completed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
await knex('config').insert(config).returning('id');
|
|
||||||
|
|
||||||
await knex('config').where('id', '=', configRow.id).delete();
|
|
||||||
|
|
||||||
await knex.schema.alterTable('config', (table) => {
|
|
||||||
table.dropColumn('installation_completed');
|
|
||||||
table.dropColumn('logo_svg_data');
|
|
||||||
table.dropColumn('palette_primary_dark');
|
|
||||||
table.dropColumn('palette_primary_light');
|
|
||||||
table.dropColumn('palette_primary_main');
|
|
||||||
table.dropColumn('title');
|
|
||||||
|
|
||||||
table.string('key').unique().notNullable().alter();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getValueForKey(rows, key) {
|
|
||||||
const row = rows.find((row) => row.key === key);
|
|
||||||
|
|
||||||
return row?.value?.data || null;
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`AccessToken model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"expiresIn": {
|
|
||||||
"type": "integer",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"revokedAt": {
|
|
||||||
"format": "date-time",
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"samlSessionId": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"token": {
|
|
||||||
"minLength": 32,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"userId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"token",
|
|
||||||
"expiresIn",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,39 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`AppAuthClient model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"active": {
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"appKey": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"authDefaults": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"formattedAuthDefaults": {
|
|
||||||
"type": "object",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"appKey",
|
|
||||||
"formattedAuthDefaults",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,73 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`App model > list should have list of applications keys 1`] = `
|
|
||||||
[
|
|
||||||
"airtable",
|
|
||||||
"appwrite",
|
|
||||||
"azure-openai",
|
|
||||||
"carbone",
|
|
||||||
"clickup",
|
|
||||||
"code",
|
|
||||||
"cryptography",
|
|
||||||
"datastore",
|
|
||||||
"deepl",
|
|
||||||
"delay",
|
|
||||||
"discord",
|
|
||||||
"disqus",
|
|
||||||
"dropbox",
|
|
||||||
"filter",
|
|
||||||
"flickr",
|
|
||||||
"flowers-software",
|
|
||||||
"formatter",
|
|
||||||
"ghost",
|
|
||||||
"github",
|
|
||||||
"gitlab",
|
|
||||||
"google-calendar",
|
|
||||||
"google-drive",
|
|
||||||
"google-forms",
|
|
||||||
"google-sheets",
|
|
||||||
"google-tasks",
|
|
||||||
"helix",
|
|
||||||
"http-request",
|
|
||||||
"hubspot",
|
|
||||||
"invoice-ninja",
|
|
||||||
"jotform",
|
|
||||||
"mailchimp",
|
|
||||||
"mailerlite",
|
|
||||||
"mattermost",
|
|
||||||
"miro",
|
|
||||||
"notion",
|
|
||||||
"ntfy",
|
|
||||||
"odoo",
|
|
||||||
"openai",
|
|
||||||
"pipedrive",
|
|
||||||
"placetel",
|
|
||||||
"postgresql",
|
|
||||||
"pushover",
|
|
||||||
"reddit",
|
|
||||||
"removebg",
|
|
||||||
"rss",
|
|
||||||
"salesforce",
|
|
||||||
"scheduler",
|
|
||||||
"self-hosted-llm",
|
|
||||||
"signalwire",
|
|
||||||
"slack",
|
|
||||||
"smtp",
|
|
||||||
"spotify",
|
|
||||||
"strava",
|
|
||||||
"stripe",
|
|
||||||
"telegram-bot",
|
|
||||||
"todoist",
|
|
||||||
"trello",
|
|
||||||
"twilio",
|
|
||||||
"twitter",
|
|
||||||
"typeform",
|
|
||||||
"vtiger-crm",
|
|
||||||
"webhook",
|
|
||||||
"wordpress",
|
|
||||||
"xero",
|
|
||||||
"you-need-a-budget",
|
|
||||||
"youtube",
|
|
||||||
"zendesk",
|
|
||||||
]
|
|
||||||
`;
|
|
@@ -1,52 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`Config model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"installationCompleted": {
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"logoSvgData": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"palettePrimaryDark": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"palettePrimaryLight": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"palettePrimaryMain": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,51 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`Connection model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"appAuthClientId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"deletedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"draft": {
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"formattedData": {
|
|
||||||
"type": "object",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"maxLength": 255,
|
|
||||||
"minLength": 1,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"userId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"verified": {
|
|
||||||
"default": false,
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"key",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,36 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`Datastore model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"minLength": 1,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"scope": {
|
|
||||||
"default": "flow",
|
|
||||||
"enum": [
|
|
||||||
"flow",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"scopeId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"key",
|
|
||||||
"value",
|
|
||||||
"scopeId",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,54 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`ExecutionStep model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"dataIn": {
|
|
||||||
"type": [
|
|
||||||
"object",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"dataOut": {
|
|
||||||
"type": [
|
|
||||||
"object",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"deletedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"errorDetails": {
|
|
||||||
"type": [
|
|
||||||
"object",
|
|
||||||
"null",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"executionId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"enum": [
|
|
||||||
"success",
|
|
||||||
"failure",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"stepId": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,33 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`Execution model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"deletedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"flowId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"internalId": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"testRun": {
|
|
||||||
"default": false,
|
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,37 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`Identity model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"providerId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"providerType": {
|
|
||||||
"enum": [
|
|
||||||
"saml",
|
|
||||||
],
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"remoteId": {
|
|
||||||
"minLength": 1,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"userId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"providerId",
|
|
||||||
"remoteId",
|
|
||||||
"userId",
|
|
||||||
"providerType",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,41 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`SamlAuthProvidersRoleMapping model > jsonSchema should have the correct schema 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"remoteRoleName": {
|
|
||||||
"minLength": 1,
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"roleId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"samlAuthProviderId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"samlAuthProviderId",
|
|
||||||
"roleId",
|
|
||||||
"remoteRoleName",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`SamlAuthProvidersRoleMapping model > relationMappings should have samlAuthProvider relation 1`] = `
|
|
||||||
{
|
|
||||||
"join": {
|
|
||||||
"from": "saml_auth_providers_role_mappings.saml_auth_provider_id",
|
|
||||||
"to": "saml_auth_providers.id",
|
|
||||||
},
|
|
||||||
"modelClass": [Function],
|
|
||||||
"relation": [Function],
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,63 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`Subscription model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"cancelUrl": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"cancellationEffectiveDate": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"deletedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"lastBillDate": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"nextBillAmount": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"nextBillDate": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"paddlePlanId": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"paddleSubscriptionId": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"updateUrl": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"userId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"userId",
|
|
||||||
"paddleSubscriptionId",
|
|
||||||
"paddlePlanId",
|
|
||||||
"updateUrl",
|
|
||||||
"cancelUrl",
|
|
||||||
"status",
|
|
||||||
"nextBillAmount",
|
|
||||||
"nextBillDate",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -1,41 +0,0 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
||||||
|
|
||||||
exports[`UsageData model > jsonSchema should have correct validations 1`] = `
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"consumedTaskCount": {
|
|
||||||
"type": "integer",
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"deletedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"nextResetAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"subscriptionId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"updatedAt": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"userId": {
|
|
||||||
"format": "uuid",
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"userId",
|
|
||||||
"consumedTaskCount",
|
|
||||||
"nextResetAt",
|
|
||||||
],
|
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
`;
|
|
@@ -34,25 +34,24 @@ class AccessToken extends Base {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.$relatedQuery('user');
|
const user = await this
|
||||||
|
.$relatedQuery('user');
|
||||||
|
|
||||||
const firstIdentity = await user.$relatedQuery('identities').first();
|
const firstIdentity = await user
|
||||||
|
.$relatedQuery('identities')
|
||||||
|
.first();
|
||||||
|
|
||||||
const samlAuthProvider = await firstIdentity
|
const samlAuthProvider = await firstIdentity
|
||||||
.$relatedQuery('samlAuthProvider')
|
.$relatedQuery('samlAuthProvider')
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
const response = await samlAuthProvider.terminateRemoteSession(
|
const response = await samlAuthProvider.terminateRemoteSession(this.samlSessionId);
|
||||||
this.samlSessionId
|
|
||||||
);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async revoke() {
|
async revoke() {
|
||||||
const response = await this.$query().patch({
|
const response = await this.$query().patch({ revokedAt: new Date().toISOString() });
|
||||||
revokedAt: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.terminateRemoteSamlSession();
|
await this.terminateRemoteSamlSession();
|
||||||
|
@@ -1,84 +0,0 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
|
||||||
import AccessToken from './access-token.js';
|
|
||||||
import User from './user.js';
|
|
||||||
import Base from './base.js';
|
|
||||||
import SamlAuthProvider from './saml-auth-provider.ee.js';
|
|
||||||
import { createAccessToken } from '../../test/factories/access-token.js';
|
|
||||||
import { createUser } from '../../test/factories/user.js';
|
|
||||||
import { createIdentity } from '../../test/factories/identity.js';
|
|
||||||
|
|
||||||
describe('AccessToken model', () => {
|
|
||||||
it('tableName should return correct name', () => {
|
|
||||||
expect(AccessToken.tableName).toBe('access_tokens');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('jsonSchema should have correct validations', () => {
|
|
||||||
expect(AccessToken.jsonSchema).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('relationMappings should return correct associations', () => {
|
|
||||||
const relationMappings = AccessToken.relationMappings();
|
|
||||||
|
|
||||||
const expectedRelations = {
|
|
||||||
user: {
|
|
||||||
relation: Base.BelongsToOneRelation,
|
|
||||||
modelClass: User,
|
|
||||||
join: {
|
|
||||||
from: 'access_tokens.user_id',
|
|
||||||
to: 'users.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(relationMappings).toStrictEqual(expectedRelations);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('revoke should set revokedAt and terminate remote SAML session', async () => {
|
|
||||||
const accessToken = await createAccessToken();
|
|
||||||
|
|
||||||
const terminateRemoteSamlSessionSpy = vi
|
|
||||||
.spyOn(accessToken, 'terminateRemoteSamlSession')
|
|
||||||
.mockImplementation(() => {});
|
|
||||||
|
|
||||||
await accessToken.revoke();
|
|
||||||
|
|
||||||
expect(terminateRemoteSamlSessionSpy).toHaveBeenCalledOnce();
|
|
||||||
expect(accessToken.revokedAt).not.toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('terminateRemoteSamlSession', () => {
|
|
||||||
it('should terminate remote SAML session when exists', async () => {
|
|
||||||
const user = await createUser();
|
|
||||||
const accessToken = await createAccessToken({
|
|
||||||
userId: user.id,
|
|
||||||
samlSessionId: 'random-remote-session-id',
|
|
||||||
});
|
|
||||||
await createIdentity({ userId: user.id });
|
|
||||||
|
|
||||||
const terminateRemoteSamlSessionSpy = vi
|
|
||||||
.spyOn(SamlAuthProvider.prototype, 'terminateRemoteSession')
|
|
||||||
.mockImplementation(() => {});
|
|
||||||
|
|
||||||
await accessToken.terminateRemoteSamlSession();
|
|
||||||
|
|
||||||
expect(terminateRemoteSamlSessionSpy).toHaveBeenCalledWith(
|
|
||||||
accessToken.samlSessionId
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should return undefined when remote SALM session doesn't exist`, async () => {
|
|
||||||
const user = await createUser();
|
|
||||||
const accessToken = await createAccessToken({ userId: user.id });
|
|
||||||
await createIdentity({ userId: user.id });
|
|
||||||
|
|
||||||
const terminateRemoteSamlSessionSpy = vi
|
|
||||||
.spyOn(SamlAuthProvider.prototype, 'terminateRemoteSession')
|
|
||||||
.mockImplementation(() => {});
|
|
||||||
|
|
||||||
const expected = await accessToken.terminateRemoteSamlSession();
|
|
||||||
|
|
||||||
expect(terminateRemoteSamlSessionSpy).not.toHaveBeenCalledOnce();
|
|
||||||
expect(expected).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -31,7 +31,6 @@ class AppAuthClient extends Base {
|
|||||||
|
|
||||||
delete this.formattedAuthDefaults;
|
delete this.formattedAuthDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
decryptData() {
|
decryptData() {
|
||||||
if (!this.eligibleForDecryption()) return;
|
if (!this.eligibleForDecryption()) return;
|
||||||
|
|
||||||
|
@@ -1,179 +0,0 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
|
||||||
import AES from 'crypto-js/aes.js';
|
|
||||||
import enc from 'crypto-js/enc-utf8.js';
|
|
||||||
|
|
||||||
import AppAuthClient from './app-auth-client.js';
|
|
||||||
import appConfig from '../config/app.js';
|
|
||||||
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
|
||||||
|
|
||||||
describe('AppAuthClient model', () => {
|
|
||||||
it('tableName should return correct name', () => {
|
|
||||||
expect(AppAuthClient.tableName).toBe('app_auth_clients');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('jsonSchema should have correct validations', () => {
|
|
||||||
expect(AppAuthClient.jsonSchema).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('encryptData', () => {
|
|
||||||
it('should return undefined if eligibleForEncryption is not true', async () => {
|
|
||||||
vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'eligibleForEncryption'
|
|
||||||
).mockReturnValue(false);
|
|
||||||
|
|
||||||
const appAuthClient = new AppAuthClient();
|
|
||||||
|
|
||||||
expect(appAuthClient.encryptData()).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should encrypt formattedAuthDefaults and set it to authDefaults', async () => {
|
|
||||||
vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'eligibleForEncryption'
|
|
||||||
).mockReturnValue(true);
|
|
||||||
|
|
||||||
const formattedAuthDefaults = {
|
|
||||||
key: 'value',
|
|
||||||
};
|
|
||||||
|
|
||||||
const appAuthClient = new AppAuthClient();
|
|
||||||
appAuthClient.formattedAuthDefaults = formattedAuthDefaults;
|
|
||||||
appAuthClient.encryptData();
|
|
||||||
|
|
||||||
const expectedDecryptedValue = JSON.parse(
|
|
||||||
AES.decrypt(
|
|
||||||
appAuthClient.authDefaults,
|
|
||||||
appConfig.encryptionKey
|
|
||||||
).toString(enc)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(formattedAuthDefaults).toStrictEqual(expectedDecryptedValue);
|
|
||||||
expect(appAuthClient.authDefaults).not.toEqual(formattedAuthDefaults);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should encrypt formattedAuthDefaults and remove formattedAuthDefaults', async () => {
|
|
||||||
vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'eligibleForEncryption'
|
|
||||||
).mockReturnValue(true);
|
|
||||||
|
|
||||||
const formattedAuthDefaults = {
|
|
||||||
key: 'value',
|
|
||||||
};
|
|
||||||
|
|
||||||
const appAuthClient = new AppAuthClient();
|
|
||||||
appAuthClient.formattedAuthDefaults = formattedAuthDefaults;
|
|
||||||
appAuthClient.encryptData();
|
|
||||||
|
|
||||||
expect(appAuthClient.formattedAuthDefaults).not.toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('decryptData', () => {
|
|
||||||
it('should return undefined if eligibleForDecryption is not true', () => {
|
|
||||||
vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'eligibleForDecryption'
|
|
||||||
).mockReturnValue(false);
|
|
||||||
|
|
||||||
const appAuthClient = new AppAuthClient();
|
|
||||||
|
|
||||||
expect(appAuthClient.decryptData()).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should decrypt authDefaults and set it to formattedAuthDefaults', async () => {
|
|
||||||
vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'eligibleForDecryption'
|
|
||||||
).mockReturnValue(true);
|
|
||||||
|
|
||||||
const formattedAuthDefaults = {
|
|
||||||
key: 'value',
|
|
||||||
};
|
|
||||||
|
|
||||||
const authDefaults = AES.encrypt(
|
|
||||||
JSON.stringify(formattedAuthDefaults),
|
|
||||||
appConfig.encryptionKey
|
|
||||||
).toString();
|
|
||||||
|
|
||||||
const appAuthClient = new AppAuthClient();
|
|
||||||
appAuthClient.authDefaults = authDefaults;
|
|
||||||
appAuthClient.decryptData();
|
|
||||||
|
|
||||||
expect(appAuthClient.formattedAuthDefaults).toStrictEqual(
|
|
||||||
formattedAuthDefaults
|
|
||||||
);
|
|
||||||
expect(appAuthClient.authDefaults).not.toEqual(formattedAuthDefaults);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('eligibleForEncryption', () => {
|
|
||||||
it('should return true when formattedAuthDefaults property exists', async () => {
|
|
||||||
const appAuthClient = await createAppAuthClient();
|
|
||||||
|
|
||||||
expect(appAuthClient.eligibleForEncryption()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return false when formattedAuthDefaults property doesn't exist", async () => {
|
|
||||||
const appAuthClient = await createAppAuthClient();
|
|
||||||
|
|
||||||
delete appAuthClient.formattedAuthDefaults;
|
|
||||||
|
|
||||||
expect(appAuthClient.eligibleForEncryption()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('eligibleForDecryption', () => {
|
|
||||||
it('should return true when authDefaults property exists', async () => {
|
|
||||||
const appAuthClient = await createAppAuthClient();
|
|
||||||
|
|
||||||
expect(appAuthClient.eligibleForDecryption()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return false when authDefaults property doesn't exist", async () => {
|
|
||||||
const appAuthClient = await createAppAuthClient();
|
|
||||||
|
|
||||||
delete appAuthClient.authDefaults;
|
|
||||||
|
|
||||||
expect(appAuthClient.eligibleForDecryption()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('$beforeInsert should call AppAuthClient.encryptData', async () => {
|
|
||||||
const appAuthClientBeforeInsertSpy = vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'encryptData'
|
|
||||||
);
|
|
||||||
|
|
||||||
await createAppAuthClient();
|
|
||||||
|
|
||||||
expect(appAuthClientBeforeInsertSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('$beforeUpdate should call AppAuthClient.encryptData', async () => {
|
|
||||||
const appAuthClient = await createAppAuthClient();
|
|
||||||
|
|
||||||
const appAuthClientBeforeUpdateSpy = vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'encryptData'
|
|
||||||
);
|
|
||||||
|
|
||||||
await appAuthClient.$query().patchAndFetch({ name: 'sample' });
|
|
||||||
|
|
||||||
expect(appAuthClientBeforeUpdateSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('$afterFind should call AppAuthClient.decryptData', async () => {
|
|
||||||
const appAuthClient = await createAppAuthClient();
|
|
||||||
|
|
||||||
const appAuthClientAfterFindSpy = vi.spyOn(
|
|
||||||
AppAuthClient.prototype,
|
|
||||||
'decryptData'
|
|
||||||
);
|
|
||||||
|
|
||||||
await appAuthClient.$query();
|
|
||||||
|
|
||||||
expect(appAuthClientAfterFindSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
});
|
|
@@ -8,7 +8,6 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|||||||
|
|
||||||
class App {
|
class App {
|
||||||
static folderPath = join(__dirname, '../apps');
|
static folderPath = join(__dirname, '../apps');
|
||||||
|
|
||||||
static list = fs
|
static list = fs
|
||||||
.readdirSync(this.folderPath)
|
.readdirSync(this.folderPath)
|
||||||
.filter((file) => fs.statSync(join(this.folderPath, file)).isDirectory());
|
.filter((file) => fs.statSync(join(this.folderPath, file)).isDirectory());
|
||||||
|
@@ -1,418 +0,0 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
|
||||||
|
|
||||||
import App from './app.js';
|
|
||||||
import * as getAppModule from '../helpers/get-app.js';
|
|
||||||
import * as appInfoConverterModule from '../helpers/app-info-converter.js';
|
|
||||||
|
|
||||||
describe('App model', () => {
|
|
||||||
it('folderPath should return correct path', () => {
|
|
||||||
expect(App.folderPath.endsWith('/packages/backend/src/apps')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('list should have list of applications keys', () => {
|
|
||||||
expect(App.list).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findAll', () => {
|
|
||||||
it('should return all applications', async () => {
|
|
||||||
const apps = await App.findAll();
|
|
||||||
|
|
||||||
expect(apps.length).toBe(App.list.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return matching applications when name argument is given', async () => {
|
|
||||||
const apps = await App.findAll('deepl');
|
|
||||||
|
|
||||||
expect(apps.length).toBe(1);
|
|
||||||
expect(apps[0].key).toBe('deepl');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return matching applications in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const appFindOneByNameSpy = vi.spyOn(App, 'findOneByName');
|
|
||||||
|
|
||||||
await App.findAll('deepl', true);
|
|
||||||
|
|
||||||
expect(appFindOneByNameSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findOneByName', () => {
|
|
||||||
it('should return app info for given app name', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => 'mock-app');
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation(() => 'app-info');
|
|
||||||
|
|
||||||
const app = await App.findOneByName('DeepL');
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
|
||||||
expect(app).toStrictEqual('app-info');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app info for given app name in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => 'mock-app');
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation(() => 'app-info');
|
|
||||||
|
|
||||||
const app = await App.findOneByName('DeepL', true);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
|
||||||
expect(app).toStrictEqual('app-info');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findOneByKey', () => {
|
|
||||||
it('should return app info for given app key', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => 'mock-app');
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation(() => 'app-info');
|
|
||||||
|
|
||||||
const app = await App.findOneByKey('deepl');
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
|
||||||
expect(app).toStrictEqual('app-info');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app info for given app key in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => 'mock-app');
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation(() => 'app-info');
|
|
||||||
|
|
||||||
const app = await App.findOneByKey('deepl', true);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
|
||||||
expect(app).toStrictEqual('app-info');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findAuthByKey', () => {
|
|
||||||
it('should return app auth for given app key', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({ auth: 'mock-auth' }));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appAuth = await App.findAuthByKey('deepl');
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({ auth: 'mock-auth' });
|
|
||||||
expect(appAuth).toStrictEqual('mock-auth');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app auth for given app key in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({ auth: 'mock-auth' }));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appAuth = await App.findAuthByKey('deepl', true);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({ auth: 'mock-auth' });
|
|
||||||
expect(appAuth).toStrictEqual('mock-auth');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findTriggersByKey', () => {
|
|
||||||
it('should return app triggers for given app key', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({ triggers: 'mock-triggers' }));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appTriggers = await App.findTriggersByKey('deepl');
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
triggers: 'mock-triggers',
|
|
||||||
});
|
|
||||||
expect(appTriggers).toStrictEqual('mock-triggers');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app triggers for given app key in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({ triggers: 'mock-triggers' }));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appTriggers = await App.findTriggersByKey('deepl', true);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
triggers: 'mock-triggers',
|
|
||||||
});
|
|
||||||
expect(appTriggers).toStrictEqual('mock-triggers');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findTriggerSubsteps', () => {
|
|
||||||
it('should return app trigger substeps for given app key', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appTriggerSubsteps = await App.findTriggerSubsteps(
|
|
||||||
'deepl',
|
|
||||||
'mock-trigger'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
|
||||||
});
|
|
||||||
expect(appTriggerSubsteps).toStrictEqual('mock-substeps');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app trigger substeps for given app key in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appTriggerSubsteps = await App.findTriggerSubsteps(
|
|
||||||
'deepl',
|
|
||||||
'mock-trigger',
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
|
||||||
});
|
|
||||||
expect(appTriggerSubsteps).toStrictEqual('mock-substeps');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findActionsByKey', () => {
|
|
||||||
it('should return app actions for given app key', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({ actions: 'mock-actions' }));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appActions = await App.findActionsByKey('deepl');
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
actions: 'mock-actions',
|
|
||||||
});
|
|
||||||
expect(appActions).toStrictEqual('mock-actions');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app actions for given app key in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({ actions: 'mock-actions' }));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appActions = await App.findActionsByKey('deepl', true);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
actions: 'mock-actions',
|
|
||||||
});
|
|
||||||
expect(appActions).toStrictEqual('mock-actions');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('findActionSubsteps', () => {
|
|
||||||
it('should return app action substeps for given app key', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appActionSubsteps = await App.findActionSubsteps(
|
|
||||||
'deepl',
|
|
||||||
'mock-action'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
|
||||||
});
|
|
||||||
expect(appActionSubsteps).toStrictEqual('mock-substeps');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return app action substeps for given app key in plain JSON when stripFunc argument is true', async () => {
|
|
||||||
const getAppSpy = vi
|
|
||||||
.spyOn(getAppModule, 'default')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appInfoConverterSpy = vi
|
|
||||||
.spyOn(appInfoConverterModule, 'default')
|
|
||||||
.mockImplementation((input) => input);
|
|
||||||
|
|
||||||
const appActionSubsteps = await App.findActionSubsteps(
|
|
||||||
'deepl',
|
|
||||||
'mock-action',
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
|
||||||
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
|
||||||
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
|
||||||
});
|
|
||||||
expect(appActionSubsteps).toStrictEqual('mock-substeps');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('checkAppAndAction', () => {
|
|
||||||
it('should return undefined when app and action exist', async () => {
|
|
||||||
const findOneByKeySpy = vi
|
|
||||||
.spyOn(App, 'findOneByKey')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
key: 'translate-text',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appAndActionExist = await App.checkAppAndAction(
|
|
||||||
'deepl',
|
|
||||||
'translate-text'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(findOneByKeySpy).toHaveBeenCalledWith('deepl');
|
|
||||||
expect(appAndActionExist).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return undefined when app exists without action argument provided', async () => {
|
|
||||||
const actionFindSpy = vi.fn();
|
|
||||||
const findOneByKeySpy = vi
|
|
||||||
.spyOn(App, 'findOneByKey')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
actions: {
|
|
||||||
find: actionFindSpy,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appAndActionExist = await App.checkAppAndAction('deepl');
|
|
||||||
|
|
||||||
expect(findOneByKeySpy).toHaveBeenCalledWith('deepl');
|
|
||||||
expect(actionFindSpy).not.toHaveBeenCalled();
|
|
||||||
expect(appAndActionExist).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when app exists, but action does not', async () => {
|
|
||||||
const findOneByKeySpy = vi
|
|
||||||
.spyOn(App, 'findOneByKey')
|
|
||||||
.mockImplementation(() => ({ name: 'deepl' }));
|
|
||||||
|
|
||||||
await expect(() =>
|
|
||||||
App.checkAppAndAction('deepl', 'non-existing-action')
|
|
||||||
).rejects.toThrowError(
|
|
||||||
'deepl does not have an action with the "non-existing-action" key!'
|
|
||||||
);
|
|
||||||
expect(findOneByKeySpy).toHaveBeenCalledWith('deepl');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('checkAppAndTrigger', () => {
|
|
||||||
it('should return undefined when app and trigger exist', async () => {
|
|
||||||
const findOneByKeySpy = vi
|
|
||||||
.spyOn(App, 'findOneByKey')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
triggers: [
|
|
||||||
{
|
|
||||||
key: 'catch-raw-webhook',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appAndTriggerExist = await App.checkAppAndTrigger(
|
|
||||||
'webhook',
|
|
||||||
'catch-raw-webhook'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(findOneByKeySpy).toHaveBeenCalledWith('webhook');
|
|
||||||
expect(appAndTriggerExist).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return undefined when app exists without trigger argument provided', async () => {
|
|
||||||
const triggerFindSpy = vi.fn();
|
|
||||||
const findOneByKeySpy = vi
|
|
||||||
.spyOn(App, 'findOneByKey')
|
|
||||||
.mockImplementation(() => ({
|
|
||||||
actions: {
|
|
||||||
find: triggerFindSpy,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const appAndTriggerExist = await App.checkAppAndTrigger('webhook');
|
|
||||||
|
|
||||||
expect(findOneByKeySpy).toHaveBeenCalledWith('webhook');
|
|
||||||
expect(triggerFindSpy).not.toHaveBeenCalled();
|
|
||||||
expect(appAndTriggerExist).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error when app exists, but trigger does not', async () => {
|
|
||||||
const findOneByKeySpy = vi
|
|
||||||
.spyOn(App, 'findOneByKey')
|
|
||||||
.mockImplementation(() => ({ name: 'webhook' }));
|
|
||||||
|
|
||||||
await expect(() =>
|
|
||||||
App.checkAppAndTrigger('webhook', 'non-existing-trigger')
|
|
||||||
).rejects.toThrowError(
|
|
||||||
'webhook does not have a trigger with the "non-existing-trigger" key!'
|
|
||||||
);
|
|
||||||
expect(findOneByKeySpy).toHaveBeenCalledWith('webhook');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,4 +1,3 @@
|
|||||||
import appConfig from '../config/app.js';
|
|
||||||
import Base from './base.js';
|
import Base from './base.js';
|
||||||
|
|
||||||
class Config extends Base {
|
class Config extends Base {
|
||||||
@@ -6,79 +5,68 @@ class Config extends Base {
|
|||||||
|
|
||||||
static jsonSchema = {
|
static jsonSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
required: ['key', 'value'],
|
||||||
|
|
||||||
properties: {
|
properties: {
|
||||||
id: { type: 'string', format: 'uuid' },
|
id: { type: 'string', format: 'uuid' },
|
||||||
installationCompleted: { type: 'boolean' },
|
key: { type: 'string', minLength: 1 },
|
||||||
logoSvgData: { type: ['string', 'null'] },
|
value: { type: 'object' },
|
||||||
palettePrimaryDark: { type: ['string', 'null'] },
|
|
||||||
palettePrimaryLight: { type: ['string', 'null'] },
|
|
||||||
palettePrimaryMain: { type: ['string', 'null'] },
|
|
||||||
title: { type: ['string', 'null'] },
|
|
||||||
createdAt: { type: 'string' },
|
|
||||||
updatedAt: { type: 'string' },
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static get virtualAttributes() {
|
|
||||||
return [
|
|
||||||
'disableNotificationsPage',
|
|
||||||
'disableFavicon',
|
|
||||||
'additionalDrawerLink',
|
|
||||||
'additionalDrawerLinkIcon',
|
|
||||||
'additionalDrawerLinkText',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
get disableNotificationsPage() {
|
|
||||||
return appConfig.disableNotificationsPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
get disableFavicon() {
|
|
||||||
return appConfig.disableFavicon;
|
|
||||||
}
|
|
||||||
|
|
||||||
get additionalDrawerLink() {
|
|
||||||
return appConfig.additionalDrawerLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
get additionalDrawerLinkIcon() {
|
|
||||||
return appConfig.additionalDrawerLinkIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
get additionalDrawerLinkText() {
|
|
||||||
return appConfig.additionalDrawerLinkText;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async get() {
|
|
||||||
const existingConfig = await this.query().limit(1).first();
|
|
||||||
|
|
||||||
if (!existingConfig) {
|
|
||||||
return await this.query().insertAndFetch({});
|
|
||||||
}
|
|
||||||
|
|
||||||
return existingConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async update(config) {
|
|
||||||
const configEntry = await this.get();
|
|
||||||
|
|
||||||
return await configEntry.$query().patchAndFetch(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async isInstallationCompleted() {
|
static async isInstallationCompleted() {
|
||||||
const config = await this.get();
|
const installationCompletedEntry = await this.query()
|
||||||
|
.where({
|
||||||
|
key: 'installation.completed',
|
||||||
|
})
|
||||||
|
.first();
|
||||||
|
|
||||||
return config.installationCompleted;
|
const installationCompleted =
|
||||||
|
installationCompletedEntry?.value?.data === true;
|
||||||
|
|
||||||
|
return installationCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async markInstallationCompleted() {
|
static async markInstallationCompleted() {
|
||||||
const config = await this.get();
|
return await this.query().insert({
|
||||||
|
key: 'installation.completed',
|
||||||
return await config.$query().patchAndFetch({
|
value: {
|
||||||
installationCompleted: true,
|
data: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async batchUpdate(config) {
|
||||||
|
const configKeys = Object.keys(config);
|
||||||
|
const updates = [];
|
||||||
|
|
||||||
|
for (const key of configKeys) {
|
||||||
|
const newValue = config[key];
|
||||||
|
|
||||||
|
if (newValue) {
|
||||||
|
const entryUpdate = Config.query()
|
||||||
|
.insert({
|
||||||
|
key,
|
||||||
|
value: {
|
||||||
|
data: newValue,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.onConflict('key')
|
||||||
|
.merge({
|
||||||
|
value: {
|
||||||
|
data: newValue,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
updates.push(entryUpdate);
|
||||||
|
} else {
|
||||||
|
const entryUpdate = Config.query().findOne({ key }).delete();
|
||||||
|
updates.push(entryUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Promise.all(updates);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Config;
|
export default Config;
|
||||||
|
@@ -1,137 +0,0 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
|
||||||
import appConfig from '../config/app.js';
|
|
||||||
import Config from './config';
|
|
||||||
import { createConfig } from '../../test/factories/config.js';
|
|
||||||
|
|
||||||
describe('Config model', () => {
|
|
||||||
it('tableName should return correct name', () => {
|
|
||||||
expect(Config.tableName).toBe('config');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('jsonSchema should have correct validations', () => {
|
|
||||||
expect(Config.jsonSchema).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('virtualAttributes should return correct attributes', () => {
|
|
||||||
const virtualAttributes = Config.virtualAttributes;
|
|
||||||
|
|
||||||
const expectedAttributes = [
|
|
||||||
'disableNotificationsPage',
|
|
||||||
'disableFavicon',
|
|
||||||
'additionalDrawerLink',
|
|
||||||
'additionalDrawerLinkIcon',
|
|
||||||
'additionalDrawerLinkText',
|
|
||||||
];
|
|
||||||
|
|
||||||
expect(virtualAttributes).toStrictEqual(expectedAttributes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disableNotificationsPage should return its value in appConfig', async () => {
|
|
||||||
const disableNotificationsPageSpy = vi.spyOn(
|
|
||||||
appConfig,
|
|
||||||
'disableNotificationsPage',
|
|
||||||
'get'
|
|
||||||
);
|
|
||||||
|
|
||||||
new Config().disableNotificationsPage;
|
|
||||||
|
|
||||||
expect(disableNotificationsPageSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('disableFavicon should return its value in appConfig', async () => {
|
|
||||||
const disableFaviconSpy = vi
|
|
||||||
.spyOn(appConfig, 'disableFavicon', 'get')
|
|
||||||
.mockReturnValue(true);
|
|
||||||
|
|
||||||
new Config().disableFavicon;
|
|
||||||
|
|
||||||
expect(disableFaviconSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('additionalDrawerLink should return its value in appConfig', async () => {
|
|
||||||
const additionalDrawerLinkSpy = vi
|
|
||||||
.spyOn(appConfig, 'additionalDrawerLink', 'get')
|
|
||||||
.mockReturnValue('https://automatisch.io');
|
|
||||||
|
|
||||||
new Config().additionalDrawerLink;
|
|
||||||
|
|
||||||
expect(additionalDrawerLinkSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('additionalDrawerLinkIcon should return its value in appConfig', async () => {
|
|
||||||
const additionalDrawerLinkIconSpy = vi
|
|
||||||
.spyOn(appConfig, 'additionalDrawerLinkIcon', 'get')
|
|
||||||
.mockReturnValue('SampleIcon');
|
|
||||||
|
|
||||||
new Config().additionalDrawerLinkIcon;
|
|
||||||
|
|
||||||
expect(additionalDrawerLinkIconSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('additionalDrawerLinkText should return its value in appConfig', async () => {
|
|
||||||
const additionalDrawerLinkTextSpy = vi
|
|
||||||
.spyOn(appConfig, 'additionalDrawerLinkText', 'get')
|
|
||||||
.mockReturnValue('Go back to Automatisch');
|
|
||||||
|
|
||||||
new Config().additionalDrawerLinkText;
|
|
||||||
|
|
||||||
expect(additionalDrawerLinkTextSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('get', () => {
|
|
||||||
it('should return single config record when it exists', async () => {
|
|
||||||
const createdConfig = await createConfig({
|
|
||||||
title: 'Automatisch',
|
|
||||||
});
|
|
||||||
|
|
||||||
const config = await Config.get();
|
|
||||||
|
|
||||||
expect(config).toStrictEqual(createdConfig);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create config record and return when it does not exist', async () => {
|
|
||||||
const configBefore = await Config.query().first();
|
|
||||||
|
|
||||||
expect(configBefore).toBeUndefined();
|
|
||||||
|
|
||||||
const config = await Config.get();
|
|
||||||
|
|
||||||
expect(config).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('update should update existing single record', async () => {
|
|
||||||
const patchAndFetchSpy = vi
|
|
||||||
.fn()
|
|
||||||
.mockImplementation((newConfig) => newConfig);
|
|
||||||
|
|
||||||
vi.spyOn(Config, 'get').mockImplementation(() => ({
|
|
||||||
$query: () => ({
|
|
||||||
patchAndFetch: patchAndFetchSpy,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const config = await Config.update({ title: 'Automatisch' });
|
|
||||||
|
|
||||||
expect(patchAndFetchSpy).toHaveBeenCalledWith({ title: 'Automatisch' });
|
|
||||||
expect(config).toStrictEqual({ title: 'Automatisch' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isInstallationCompleted should return installationCompleted value', async () => {
|
|
||||||
const configGetSpy = vi.spyOn(Config, 'get').mockImplementation(() => ({
|
|
||||||
installationCompleted: true,
|
|
||||||
}));
|
|
||||||
|
|
||||||
await Config.isInstallationCompleted();
|
|
||||||
|
|
||||||
expect(configGetSpy).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('markInstallationCompleted should update installationCompleted as true', async () => {
|
|
||||||
await Config.update({ installationCompleted: false });
|
|
||||||
|
|
||||||
const config = await Config.markInstallationCompleted();
|
|
||||||
|
|
||||||
expect(config.installationCompleted).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -160,6 +160,35 @@ class Connection extends Base {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make another abstraction like beforeSave instead of using
|
||||||
|
// beforeInsert and beforeUpdate separately for the same operation.
|
||||||
|
async $beforeInsert(queryContext) {
|
||||||
|
await super.$beforeInsert(queryContext);
|
||||||
|
|
||||||
|
await this.checkEligibilityForCreation();
|
||||||
|
|
||||||
|
this.encryptData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async $beforeUpdate(opt, queryContext) {
|
||||||
|
await super.$beforeUpdate(opt, queryContext);
|
||||||
|
this.encryptData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async $afterFind() {
|
||||||
|
this.decryptData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async $afterInsert(queryContext) {
|
||||||
|
await super.$afterInsert(queryContext);
|
||||||
|
Telemetry.connectionCreated(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async $afterUpdate(opt, queryContext) {
|
||||||
|
await super.$afterUpdate(opt, queryContext);
|
||||||
|
Telemetry.connectionUpdated(this);
|
||||||
|
}
|
||||||
|
|
||||||
async getApp() {
|
async getApp() {
|
||||||
if (!this.key) return null;
|
if (!this.key) return null;
|
||||||
|
|
||||||
@@ -249,35 +278,6 @@ class Connection extends Base {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make another abstraction like beforeSave instead of using
|
|
||||||
// beforeInsert and beforeUpdate separately for the same operation.
|
|
||||||
async $beforeInsert(queryContext) {
|
|
||||||
await super.$beforeInsert(queryContext);
|
|
||||||
|
|
||||||
await this.checkEligibilityForCreation();
|
|
||||||
|
|
||||||
this.encryptData();
|
|
||||||
}
|
|
||||||
|
|
||||||
async $beforeUpdate(opt, queryContext) {
|
|
||||||
await super.$beforeUpdate(opt, queryContext);
|
|
||||||
this.encryptData();
|
|
||||||
}
|
|
||||||
|
|
||||||
async $afterFind() {
|
|
||||||
this.decryptData();
|
|
||||||
}
|
|
||||||
|
|
||||||
async $afterInsert(queryContext) {
|
|
||||||
await super.$afterInsert(queryContext);
|
|
||||||
Telemetry.connectionCreated(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $afterUpdate(opt, queryContext) {
|
|
||||||
await super.$afterUpdate(opt, queryContext);
|
|
||||||
Telemetry.connectionUpdated(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Connection;
|
export default Connection;
|
||||||
|
@@ -1,163 +0,0 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
|
||||||
import AES from 'crypto-js/aes.js';
|
|
||||||
import enc from 'crypto-js/enc-utf8.js';
|
|
||||||
import appConfig from '../config/app.js';
|
|
||||||
import AppAuthClient from './app-auth-client.js';
|
|
||||||
import AppConfig from './app-config.js';
|
|
||||||
import Base from './base.js';
|
|
||||||
import Connection from './connection';
|
|
||||||
import Step from './step.js';
|
|
||||||
import User from './user.js';
|
|
||||||
|
|
||||||
describe('Connection model', () => {
|
|
||||||
it('tableName should return correct name', () => {
|
|
||||||
expect(Connection.tableName).toBe('connections');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('jsonSchema should have correct validations', () => {
|
|
||||||
expect(Connection.jsonSchema).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('virtualAttributes should return correct attributes', () => {
|
|
||||||
const virtualAttributes = Connection.virtualAttributes;
|
|
||||||
|
|
||||||
const expectedAttributes = ['reconnectable'];
|
|
||||||
|
|
||||||
expect(virtualAttributes).toStrictEqual(expectedAttributes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('relationMappings should return correct associations', () => {
|
|
||||||
const relationMappings = Connection.relationMappings();
|
|
||||||
|
|
||||||
const expectedRelations = {
|
|
||||||
user: {
|
|
||||||
relation: Base.BelongsToOneRelation,
|
|
||||||
modelClass: User,
|
|
||||||
join: {
|
|
||||||
from: 'connections.user_id',
|
|
||||||
to: 'users.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
steps: {
|
|
||||||
relation: Base.HasManyRelation,
|
|
||||||
modelClass: Step,
|
|
||||||
join: {
|
|
||||||
from: 'connections.id',
|
|
||||||
to: 'steps.connection_id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
triggerSteps: {
|
|
||||||
relation: Base.HasManyRelation,
|
|
||||||
modelClass: Step,
|
|
||||||
join: {
|
|
||||||
from: 'connections.id',
|
|
||||||
to: 'steps.connection_id',
|
|
||||||
},
|
|
||||||
filter: expect.any(Function),
|
|
||||||
},
|
|
||||||
appConfig: {
|
|
||||||
relation: Base.BelongsToOneRelation,
|
|
||||||
modelClass: AppConfig,
|
|
||||||
join: {
|
|
||||||
from: 'connections.key',
|
|
||||||
to: 'app_configs.key',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
appAuthClient: {
|
|
||||||
relation: Base.BelongsToOneRelation,
|
|
||||||
modelClass: AppAuthClient,
|
|
||||||
join: {
|
|
||||||
from: 'connections.app_auth_client_id',
|
|
||||||
to: 'app_auth_clients.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(relationMappings).toStrictEqual(expectedRelations);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.todo('reconnectable');
|
|
||||||
|
|
||||||
describe('encryptData', () => {
|
|
||||||
it('should return undefined if eligibleForEncryption is not true', async () => {
|
|
||||||
vi.spyOn(Connection.prototype, 'eligibleForEncryption').mockReturnValue(
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
const connection = new Connection();
|
|
||||||
|
|
||||||
expect(connection.encryptData()).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should encrypt formattedData and set it to data', async () => {
|
|
||||||
vi.spyOn(Connection.prototype, 'eligibleForEncryption').mockReturnValue(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
const formattedData = {
|
|
||||||
key: 'value',
|
|
||||||
};
|
|
||||||
|
|
||||||
const connection = new Connection();
|
|
||||||
connection.formattedData = formattedData;
|
|
||||||
connection.encryptData();
|
|
||||||
|
|
||||||
const expectedDecryptedValue = JSON.parse(
|
|
||||||
AES.decrypt(connection.data, appConfig.encryptionKey).toString(enc)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(formattedData).toStrictEqual(expectedDecryptedValue);
|
|
||||||
expect(connection.data).not.toEqual(formattedData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should encrypt formattedData and remove formattedData', async () => {
|
|
||||||
vi.spyOn(Connection.prototype, 'eligibleForEncryption').mockReturnValue(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
const formattedData = {
|
|
||||||
key: 'value',
|
|
||||||
};
|
|
||||||
|
|
||||||
const connection = new Connection();
|
|
||||||
connection.formattedData = formattedData;
|
|
||||||
connection.encryptData();
|
|
||||||
|
|
||||||
expect(connection.formattedData).not.toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('decryptData', () => {
|
|
||||||
it('should return undefined if eligibleForDecryption is not true', () => {
|
|
||||||
vi.spyOn(Connection.prototype, 'eligibleForDecryption').mockReturnValue(
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
const connection = new Connection();
|
|
||||||
|
|
||||||
expect(connection.decryptData()).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should decrypt data and set it to formattedData', async () => {
|
|
||||||
vi.spyOn(Connection.prototype, 'eligibleForDecryption').mockReturnValue(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
const formattedData = {
|
|
||||||
key: 'value',
|
|
||||||
};
|
|
||||||
|
|
||||||
const data = AES.encrypt(
|
|
||||||
JSON.stringify(formattedData),
|
|
||||||
appConfig.encryptionKey
|
|
||||||
).toString();
|
|
||||||
|
|
||||||
const connection = new Connection();
|
|
||||||
connection.data = data;
|
|
||||||
connection.decryptData();
|
|
||||||
|
|
||||||
expect(connection.formattedData).toStrictEqual(formattedData);
|
|
||||||
expect(connection.data).not.toEqual(formattedData);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@@ -5,7 +5,7 @@ class Datastore extends Base {
|
|||||||
|
|
||||||
static jsonSchema = {
|
static jsonSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['key', 'value', 'scopeId'],
|
required: ['key', 'value', 'scope', 'scopeId'],
|
||||||
|
|
||||||
properties: {
|
properties: {
|
||||||
id: { type: 'string', format: 'uuid' },
|
id: { type: 'string', format: 'uuid' },
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
|
||||||
import Datastore from './datastore';
|
|
||||||
|
|
||||||
describe('Datastore model', () => {
|
|
||||||
it('tableName should return correct name', () => {
|
|
||||||
expect(Datastore.tableName).toBe('datastore');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('jsonSchema should have correct validations', () => {
|
|
||||||
expect(Datastore.jsonSchema).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
@@ -47,32 +47,22 @@ class ExecutionStep extends Base {
|
|||||||
return this.status === 'failure';
|
return this.status === 'failure';
|
||||||
}
|
}
|
||||||
|
|
||||||
async isSucceededNonTestRun() {
|
async $afterInsert(queryContext) {
|
||||||
const execution = await this.$relatedQuery('execution');
|
await super.$afterInsert(queryContext);
|
||||||
return !execution.testRun && !this.isFailed;
|
Telemetry.executionStepCreated(this);
|
||||||
}
|
|
||||||
|
|
||||||
async updateUsageData() {
|
if (appConfig.isCloud) {
|
||||||
const execution = await this.$relatedQuery('execution');
|
const execution = await this.$relatedQuery('execution');
|
||||||
|
|
||||||
|
if (!execution.testRun && !this.isFailed) {
|
||||||
const flow = await execution.$relatedQuery('flow');
|
const flow = await execution.$relatedQuery('flow');
|
||||||
const user = await flow.$relatedQuery('user');
|
const user = await flow.$relatedQuery('user');
|
||||||
const usageData = await user.$relatedQuery('currentUsageData');
|
const usageData = await user.$relatedQuery('currentUsageData');
|
||||||
|
|
||||||
await usageData.increaseConsumedTaskCountByOne();
|
await usageData.increaseConsumedTaskCountByOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
async increaseUsageCount() {
|
|
||||||
if (appConfig.isCloud && this.isSucceededNonTestRun()) {
|
|
||||||
await this.updateUsageData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async $afterInsert(queryContext) {
|
|
||||||
await super.$afterInsert(queryContext);
|
|
||||||
Telemetry.executionStepCreated(this);
|
|
||||||
await this.increaseUsageCount();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ExecutionStep;
|
export default ExecutionStep;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user