Compare commits

..

36 Commits

Author SHA1 Message Date
Rıdvan Akca
d45c8aa3d0 feat(gitea): add new pull requests trigger 2024-05-13 16:53:14 +02:00
Rıdvan Akca
93fdc05529 feat(gitea): add create issue action 2024-05-13 16:52:13 +02:00
Rıdvan Akca
3e6f22748b feat(gitea): add new issues trigger 2024-04-30 15:18:12 +02:00
Rıdvan Akca
fbd62d8635 feat(gitea): add new watchers trigger 2024-04-30 14:59:52 +02:00
Rıdvan Akca
b8ac73478b feat(gitea): add gitea integration 2024-04-30 14:55:26 +02:00
Rıdvan Akca
f8018ca384 feat(gitea): add new stargazers trigger 2024-04-30 14:54:52 +02:00
Rıdvan Akca
99025c6a7c feat(gitea): add gitea integration 2024-04-30 12:40:34 +02:00
Ömer Faruk Aydın
788530be45 Merge pull request #1843 from automatisch/dockerignore
chore: Add .env and yarn error log files to dockerignore
2024-04-26 17:27:55 +02:00
Faruk AYDIN
7ed392e854 chore: Add .env and yarn error log files to dockerignore 2024-04-26 17:19:18 +02:00
Ömer Faruk Aydın
3932e554da Merge pull request #1842 from automatisch/node-gyp
chore: Explicitly install node-gyp
2024-04-26 16:45:30 +02:00
Faruk AYDIN
1a21624618 chore: Explicitly install node-gyp 2024-04-26 16:39:14 +02:00
Ömer Faruk Aydın
9f292ff018 Merge pull request #1840 from automatisch/update-bcrypt
chore: Update bcrypt version to 5.1.0
2024-04-26 15:43:47 +02:00
Faruk AYDIN
dbb24b3a9b chore: Update bcrypt version to 5.1.0 2024-04-26 15:36:36 +02:00
Ali BARIN
35b2639837 Merge pull request #1839 from automatisch/dockerfile-revision
chore: direct builds in docker
2024-04-26 15:02:37 +02:00
Ali BARIN
35951199cd chore: direct builds in docker 2024-04-26 14:42:56 +02:00
Ali BARIN
79af909c51 Merge pull request #1832 from automatisch/align-404-page-center
fix: align 404 page content to the center
2024-04-26 14:22:26 +02:00
Ali BARIN
3482aa7b76 Merge pull request #1837 from automatisch/logout-endpoint-web-implementation
feat: implement revoke access token with RQ
2024-04-26 14:20:49 +02:00
Ali BARIN
5dbc1f59ef Merge pull request #1835 from automatisch/logout-endpoint
feat: add DELETE /access-tokens/:token
2024-04-26 14:18:59 +02:00
Ali BARIN
2166a3220e style: add break line before variable declaration and beforeEach 2024-04-26 12:02:38 +00:00
Ali BARIN
24a7d1ef10 Merge pull request #1833 from automatisch/aut-931
feat: remove static page title
2024-04-26 11:51:03 +02:00
Ali BARIN
18ffbb7317 fix(AccountDropdownMenu): await token revocation request 2024-04-26 09:27:41 +00:00
Rıdvan Akca
363874de6a feat: implement revoke access token with RQ 2024-04-26 09:25:50 +00:00
Ali BARIN
68d1719b11 feat: add new methods to cors options 2024-04-26 09:25:27 +00:00
Ali BARIN
1a75d81268 test: add test for revoking access token 2024-04-26 09:16:53 +00:00
Ali BARIN
2163be4227 feat: add DELETE /access-tokens/:token 2024-04-24 15:31:22 +00:00
Ali BARIN
b54afcd922 Merge pull request #1825 from automatisch/access-tokens
feat: Use persisted access tokens for authentication
2024-04-24 16:39:57 +02:00
Ali BARIN
0a86641a0f feat: remove static page title 2024-04-24 15:27:37 +02:00
kasia.oczkowska
18464c746a fix: align 404 page content to the center 2024-04-24 13:20:07 +01:00
Ömer Faruk Aydın
ba92cddae1 Merge pull request #1828 from automatisch/aut-932
feat: compute DOCS_URL in authDocUrl
2024-04-24 12:09:19 +02:00
Faruk AYDIN
2a4f8ed45f feat: Add indexes to token and userId columns of access tokens 2024-04-24 12:03:45 +02:00
Ali BARIN
135a0028be feat: introduce DOCS_URL in authDocUrl properties 2024-04-23 12:39:38 +00:00
Ali BARIN
4da6e8372f feat: compute DOCS_URL in authDocUrl 2024-04-23 12:21:51 +00:00
Faruk AYDIN
6a7cdf2570 feat: Use persisted access tokens for authentication 2024-04-22 16:57:34 +02:00
Faruk AYDIN
73c929f25e feat: Create access tokens model 2024-04-22 15:19:17 +02:00
Ali BARIN
754c2d41c2 Merge pull request #1814 from automatisch/AUT-892
feat: remove chatwood
2024-04-17 14:40:17 +02:00
Rıdvan Akca
7201e48111 feat: remove chatwood 2024-04-17 14:29:54 +02:00
160 changed files with 1561 additions and 363 deletions

View File

@@ -4,5 +4,9 @@
**/.devcontainer
**/.github
**/.vscode
**/.env
**/.env.test
**/.env.production
**/yarn-error.log
packages/docs
packages/e2e-test

View File

@@ -1,14 +1,25 @@
# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /automatisch
ENV PORT 3000
RUN \
apk --no-cache add --virtual build-dependencies python3 build-base git
WORKDIR /automatisch
# copy the app, note .dockerignore
COPY . /automatisch
RUN yarn
RUN cd packages/web && yarn build
RUN \
apk --no-cache add --virtual build-dependencies python3 build-base && \
yarn global add @automatisch/cli@0.10.0 --network-timeout 1000000 && \
rm -rf /usr/local/share/.cache/ && \
apk del build-dependencies
COPY ./entrypoint.sh /entrypoint.sh
COPY ./docker/entrypoint.sh /entrypoint.sh
EXPOSE 3000
ENTRYPOINT ["sh", "/entrypoint.sh"]

View File

@@ -2,8 +2,12 @@
set -e
cd packages/backend
if [ -n "$WORKER" ]; then
automatisch start-worker
yarn start:worker
else
automatisch start
yarn db:migrate
yarn db:seed:user
yarn start
fi

View File

@@ -31,7 +31,7 @@
"accounting": "^0.4.1",
"ajv-formats": "^2.1.1",
"axios": "1.6.0",
"bcrypt": "^5.0.1",
"bcrypt": "^5.1.0",
"bullmq": "^3.0.0",
"cors": "^2.8.5",
"crypto-js": "^4.1.1",
@@ -95,6 +95,7 @@
"url": "https://github.com/automatisch/automatisch/issues"
},
"devDependencies": {
"node-gyp": "^10.1.0",
"nodemon": "^2.0.13",
"supertest": "^6.3.3",
"vitest": "^1.1.3"

View File

@@ -11,7 +11,7 @@ export default defineApp({
'https://azure.microsoft.com/en-us/products/ai-services/openai-service',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/azure-openai/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/azure-openai/connection',
authDocUrl: '{DOCS_URL}/apps/azure-openai/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Carbone',
key: 'carbone',
iconUrl: '{BASE_URL}/apps/carbone/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/carbone/connection',
authDocUrl: '{DOCS_URL}/apps/carbone/connection',
supportsConnections: true,
baseUrl: 'https://carbone.io',
apiBaseUrl: 'https://api.carbone.io',

View File

@@ -5,7 +5,7 @@ export default defineApp({
name: 'Datastore',
key: 'datastore',
iconUrl: '{BASE_URL}/apps/datastore/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/datastore/connection',
authDocUrl: '{DOCS_URL}/apps/datastore/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'DeepL',
key: 'deepl',
iconUrl: '{BASE_URL}/apps/deepl/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/deepl/connection',
authDocUrl: '{DOCS_URL}/apps/deepl/connection',
supportsConnections: true,
baseUrl: 'https://deepl.com',
apiBaseUrl: 'https://api.deepl.com',

View File

@@ -5,7 +5,7 @@ export default defineApp({
name: 'Delay',
key: 'delay',
iconUrl: '{BASE_URL}/apps/delay/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/delay/connection',
authDocUrl: '{DOCS_URL}/apps/delay/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -10,7 +10,7 @@ export default defineApp({
name: 'Discord',
key: 'discord',
iconUrl: '{BASE_URL}/apps/discord/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/discord/connection',
authDocUrl: '{DOCS_URL}/apps/discord/connection',
supportsConnections: true,
baseUrl: 'https://discord.com',
apiBaseUrl: 'https://discord.com/api',

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Dropbox',
key: 'dropbox',
iconUrl: '{BASE_URL}/apps/dropbox/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/dropbox/connection',
authDocUrl: '{DOCS_URL}/apps/dropbox/connection',
supportsConnections: true,
baseUrl: 'https://dropbox.com',
apiBaseUrl: 'https://api.dropboxapi.com',

View File

@@ -5,7 +5,7 @@ export default defineApp({
name: 'Filter',
key: 'filter',
iconUrl: '{BASE_URL}/apps/filter/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/filter/connection',
authDocUrl: '{DOCS_URL}/apps/filter/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -8,7 +8,7 @@ export default defineApp({
name: 'Flickr',
key: 'flickr',
iconUrl: '{BASE_URL}/apps/flickr/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/flickr/connection',
authDocUrl: '{DOCS_URL}/apps/flickr/connection',
docUrl: 'https://automatisch.io/docs/flickr',
primaryColor: '000000',
supportsConnections: true,

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Flowers Software',
key: 'flowers-software',
iconUrl: '{BASE_URL}/apps/flowers-software/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/flowers-software/connection',
authDocUrl: '{DOCS_URL}/apps/flowers-software/connection',
supportsConnections: true,
baseUrl: 'https://flowers-software.com',
apiBaseUrl: 'https://webapp.flowers-software.com/api',

View File

@@ -6,7 +6,7 @@ export default defineApp({
name: 'Formatter',
key: 'formatter',
iconUrl: '{BASE_URL}/apps/formatter/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/formatter/connection',
authDocUrl: '{DOCS_URL}/apps/formatter/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://ghost.org',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/ghost/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/ghost/connection',
authDocUrl: '{DOCS_URL}/apps/ghost/connection',
primaryColor: '15171A',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -0,0 +1,102 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create issue',
key: 'createIssue',
description: 'Creates a new issue.',
arguments: [
{
label: 'Repo',
key: 'repo',
type: 'dropdown',
required: true,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listRepos',
},
],
},
},
{
label: 'Title',
key: 'title',
type: 'string',
required: true,
variables: true,
},
{
label: 'Body',
key: 'body',
type: 'string',
required: true,
variables: true,
},
{
label: 'Labels',
key: 'labels',
type: 'dynamic',
required: false,
fields: [
{
label: 'Label',
key: 'label',
type: 'dropdown',
description: 'Only trigger on issues when this label is added.',
required: false,
variables: true,
dependsOn: ['parameters.repo'],
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLabels',
},
{
name: 'parameters.repo',
value: '{parameters.repo}',
},
{
name: 'parameters.showLabelId',
value: 'true',
},
],
},
},
],
},
],
async run($) {
const repoOwner = $.auth.data.repoOwner;
const repo = $.step.parameters.repo;
const title = $.step.parameters.title;
const issueBody = $.step.parameters.body;
const allLabels = $.step.parameters.labels;
const formattedAllLabels = allLabels
.filter((label) => label.label !== '')
.map((label) => label.label);
const body = {
title,
body: issueBody,
};
if (formattedAllLabels.length) {
body.labels = formattedAllLabels;
}
const response = await $.http.post(
`/repos/${repoOwner}/${repo}/issues`,
body
);
$.setActionItem({ raw: response.data });
},
});

View File

@@ -0,0 +1,3 @@
import createIssue from './create-issue/index.js';
export default [createIssue];

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" style="enable-background:new 0 0 640 640" xml:space="preserve" width="32" height="32"><path style="fill:#fff" d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12z"/><path style="fill:#609926" d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6zM125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1zm300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1z"/><path style="fill:#609926" d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8-1.9 8 2 16.3 9.1 20 7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3 7.8 4 17.4 1.7 22.5-5.3 5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8l-24.6 50.4z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,24 @@
import { URLSearchParams } from 'url';
export default async function generateAuthUrl($) {
const oauthRedirectUrlField = $.app.auth.fields.find(
(field) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value;
const state = Math.random().toString();
const searchParams = new URLSearchParams({
client_id: $.auth.data.clientId,
redirect_uri: redirectUri,
response_type: 'code',
state: state,
});
const url = `${
$.auth.data.instanceUrl
}/login/oauth/authorize?${searchParams.toString()}`;
await $.auth.set({
url,
originalState: state,
});
}

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
import { URLSearchParams } from 'node:url';
const refreshToken = async ($) => {
const params = new URLSearchParams({
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
grant_type: 'refresh_token',
refresh_token: $.auth.data.refreshToken,
});
const { data } = await $.http.post(
`${$.auth.data.instanceUrl}/login/oauth/access_token`,
params.toString(),
{
additionalProperties: {
skipAddingBaseUrl: true,
},
}
);
await $.auth.set({
accessToken: data.access_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
refreshToken: data.refresh_token,
});
};
export default refreshToken;

View File

@@ -0,0 +1,50 @@
import getCurrentUser from '../common/get-current-user.js';
import { URLSearchParams } from 'url';
const verifyCredentials = async ($) => {
if ($.auth.data.originalState !== $.auth.data.state) {
throw new Error(`The 'state' parameter does not match.`);
}
const oauthRedirectUrlField = $.app.auth.fields.find(
(field) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value;
const params = new URLSearchParams({
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
code: $.auth.data.code,
grant_type: 'authorization_code',
redirect_uri: redirectUri,
});
const { data } = await $.http.post(
`${$.auth.data.instanceUrl}/login/oauth/access_token`,
params.toString(),
{
additionalProperties: {
skipAddingBaseUrl: true,
},
}
);
await $.auth.set({
accessToken: data.access_token,
tokenType: data.token_type,
});
const currentUser = await getCurrentUser($);
const screenName = [currentUser.username, currentUser.email]
.filter(Boolean)
.join(' @ ');
await $.auth.set({
clientId: $.auth.data.clientId,
clientSecret: $.auth.data.clientSecret,
expiresIn: data.expires_in,
refreshToken: data.refresh_token,
repoOwner: currentUser.username,
screenName,
});
};
export default verifyCredentials;

View File

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

View File

@@ -0,0 +1,6 @@
const getCurrentUser = async ($) => {
const { data: currentUser } = await $.http.get(`/user`);
return currentUser;
};
export default getCurrentUser;

View File

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

View File

@@ -0,0 +1,4 @@
import listLabels from './list-labels/index.js';
import listRepos from './list-repos/index.js';
export default [listLabels, listRepos];

View File

@@ -0,0 +1,42 @@
export default {
name: 'List labels',
key: 'listLabels',
async run($) {
const labels = {
data: [],
};
const repoOwner = $.auth.data.repoOwner;
const repo = $.step.parameters.repo;
const showLabelId = $.step.parameters.showLabelId === 'true';
const params = {
page: 1,
limit: 100,
};
let totalCount;
let totalRequestedCount;
do {
const { data, headers } = await $.http.get(
`/repos/${repoOwner}/${repo}/labels`,
{ params }
);
params.page = params.page + 1;
totalCount = Number(headers['x-total-count']);
totalRequestedCount = params.page * params.limit;
if (data?.length) {
for (const label of data) {
const value = showLabelId ? label.id : label.name;
labels.data.push({
value,
name: label.name,
});
}
}
} while (totalRequestedCount <= totalCount);
return labels;
},
};

View File

@@ -0,0 +1,35 @@
export default {
name: 'List repos',
key: 'listRepos',
async run($) {
const repos = {
data: [],
};
const params = {
page: 1,
limit: 100,
};
let totalCount;
let totalRequestedCount;
do {
const { data, headers } = await $.http.get('/user/repos', { params });
params.page = params.page + 1;
totalCount = Number(headers['x-total-count']);
totalRequestedCount = params.page * params.limit;
if (data?.length) {
for (const repo of data) {
repos.data.push({
value: repo.name,
name: repo.name,
});
}
}
} while (totalRequestedCount <= totalCount);
return repos;
},
};

View File

@@ -0,0 +1,23 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import setBaseUrl from './common/set-base-url.js';
import triggers from './triggers/index.js';
import dynamicData from './dynamic-data/index.js';
import actions from './actions/index.js';
export default defineApp({
name: 'Gitea',
key: 'gitea',
iconUrl: '{BASE_URL}/apps/gitea/assets/favicon.svg',
authDocUrl: '{DOCS_URL}/apps/gitea/connection',
supportsConnections: true,
baseUrl: '',
apiBaseUrl: '',
primaryColor: '609926',
beforeRequest: [setBaseUrl, addAuthHeader],
auth,
triggers,
dynamicData,
actions,
});

View File

@@ -0,0 +1,6 @@
import newIssues from './new-issues/index.js';
import newPullRequests from './new-pull-requests/index.js';
import newStargazers from './new-stargazers/index.js';
import newWatchers from './new-watchers/index.js';
export default [newIssues, newPullRequests, newStargazers, newWatchers];

View File

@@ -0,0 +1,121 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New issues',
key: 'newIssues',
pollInterval: 15,
description: 'Triggers when a new issue is created.',
arguments: [
{
label: 'Repo',
key: 'repo',
type: 'dropdown',
required: true,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listRepos',
},
],
},
},
{
label: 'Which types of issues should this trigger on?',
key: 'issueType',
type: 'dropdown',
description: 'Defaults to any issue you can see.',
required: true,
variables: true,
value: 'all',
options: [
{
label: 'Closed',
value: 'closed',
},
{
label: 'Open',
value: 'open',
},
{
label: 'All',
value: 'all',
},
],
},
{
label: 'Labels',
key: 'labels',
type: 'dynamic',
required: false,
fields: [
{
label: 'Label',
key: 'label',
type: 'dropdown',
description: 'Only trigger on issues when this label is added.',
required: false,
variables: true,
dependsOn: ['parameters.repo'],
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLabels',
},
{
name: 'parameters.repo',
value: '{parameters.repo}',
},
],
},
},
],
},
],
async run($) {
const repo = $.step.parameters.repo;
const issueType = $.step.parameters.issueType;
const allLabels = $.step.parameters.labels;
const formattedAllLabels = allLabels.map((label) => label.label).join(',');
const repoOwner = $.auth.data.repoOwner;
const params = {
page: 1,
limit: 100,
state: issueType,
labels: formattedAllLabels,
};
let totalCount;
let totalRequestedCount;
do {
const { data, headers } = await $.http.get(
`/repos/${repoOwner}/${repo}/issues`,
{
params,
}
);
params.page = params.page + 1;
totalCount = Number(headers['x-total-count']);
totalRequestedCount = params.page * params.limit;
if (data?.length) {
for (const issue of data) {
$.pushTriggerItem({
raw: issue,
meta: {
internalId: issue.id.toString(),
},
});
}
}
} while (totalRequestedCount <= totalCount);
},
});

View File

@@ -0,0 +1,123 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New pull requests',
key: 'newPullRequests',
pollInterval: 15,
description: 'Triggers when the user creates a new pull request.',
arguments: [
{
label: 'Repo',
key: 'repo',
type: 'dropdown',
required: true,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listRepos',
},
],
},
},
{
label: 'Which types of pulls should this trigger on?',
key: 'pullType',
type: 'dropdown',
description: '',
required: false,
variables: true,
value: 'all',
options: [
{
label: 'Closed',
value: 'closed',
},
{
label: 'Open',
value: 'open',
},
{
label: 'All',
value: 'all',
},
],
},
{
label: 'Type of Sort?',
key: 'typeOfSort',
type: 'dropdown',
description: '',
required: false,
variables: true,
value: 'all',
options: [
{
label: 'Oldest',
value: 'oldest',
},
{
label: 'Recent Update',
value: 'recentupdate',
},
{
label: 'Least Update',
value: 'leastupdate',
},
{
label: 'Most Comment',
value: 'mostcomment',
},
{
label: 'Least Comment',
value: 'leastcomment',
},
{
label: 'Priority',
value: 'priority',
},
],
},
],
async run($) {
const repo = $.step.parameters.repo;
const typeOfSort = $.step.parameters.typeOfSort;
const pullType = $.step.parameters.pullType;
const repoOwner = $.auth.data.repoOwner;
const params = {
page: 1,
limit: 100,
sort: typeOfSort,
state: pullType,
};
let totalCount;
let totalRequestedCount;
do {
const { data, headers } = await $.http.get(
`/repos/${repoOwner}/${repo}/pulls`,
{
params,
}
);
params.page = params.page + 1;
totalCount = Number(headers['x-total-count']);
totalRequestedCount = params.page * params.limit;
if (data?.length) {
for (const pullRequest of data) {
$.pushTriggerItem({
raw: pullRequest,
meta: {
internalId: pullRequest.id.toString(),
},
});
}
}
} while (totalRequestedCount <= totalCount);
},
});

View File

@@ -0,0 +1,61 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New stargazers',
key: 'newStargazers',
pollInterval: 15,
description: 'Triggers when a user stars a repository.',
arguments: [
{
label: 'Repo',
key: 'repo',
type: 'dropdown',
required: true,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listRepos',
},
],
},
},
],
async run($) {
const repo = $.step.parameters.repo;
const repoOwner = $.auth.data.repoOwner;
const params = {
page: 1,
limit: 100,
};
let totalCount;
let totalRequestedCount;
do {
const { data, headers } = await $.http.get(
`/repos/${repoOwner}/${repo}/stargazers`,
{
params,
}
);
params.page = params.page + 1;
totalCount = Number(headers['x-total-count']);
totalRequestedCount = params.page * params.limit;
if (data?.length) {
for (const stargazer of data) {
$.pushTriggerItem({
raw: stargazer,
meta: {
internalId: stargazer.id.toString(),
},
});
}
}
} while (totalRequestedCount <= totalCount);
},
});

View File

@@ -0,0 +1,61 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New watchers',
key: 'newWatchers',
pollInterval: 15,
description: 'Triggers when a user watches a repository.',
arguments: [
{
label: 'Repo',
key: 'repo',
type: 'dropdown',
required: true,
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listRepos',
},
],
},
},
],
async run($) {
const repo = $.step.parameters.repo;
const repoOwner = $.auth.data.repoOwner;
const params = {
page: 1,
limit: 100,
};
let totalCount;
let totalRequestedCount;
do {
const { data, headers } = await $.http.get(
`/repos/${repoOwner}/${repo}/subscribers`,
{
params,
}
);
params.page = params.page + 1;
totalCount = Number(headers['x-total-count']);
totalRequestedCount = params.page * params.limit;
if (data?.length) {
for (const subscriber of data) {
$.pushTriggerItem({
raw: subscriber,
meta: {
internalId: subscriber.id.toString(),
},
});
}
}
} while (totalRequestedCount <= totalCount);
},
});

View File

@@ -11,7 +11,7 @@ export default defineApp({
baseUrl: 'https://github.com',
apiBaseUrl: 'https://api.github.com',
iconUrl: '{BASE_URL}/apps/github/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/github/connection',
authDocUrl: '{DOCS_URL}/apps/github/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -11,7 +11,7 @@ export default defineApp({
baseUrl: 'https://gitlab.com',
apiBaseUrl: 'https://gitlab.com',
iconUrl: '{BASE_URL}/apps/gitlab/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/gitlab/connection',
authDocUrl: '{DOCS_URL}/apps/gitlab/connection',
primaryColor: 'FC6D26',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://calendar.google.com',
apiBaseUrl: 'https://www.googleapis.com/calendar',
iconUrl: '{BASE_URL}/apps/google-calendar/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/google-calendar/connection',
authDocUrl: '{DOCS_URL}/apps/google-calendar/connection',
primaryColor: '448AFF',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://drive.google.com',
apiBaseUrl: 'https://www.googleapis.com/drive',
iconUrl: '{BASE_URL}/apps/google-drive/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/google-drive/connection',
authDocUrl: '{DOCS_URL}/apps/google-drive/connection',
primaryColor: '1FA463',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://docs.google.com/forms',
apiBaseUrl: 'https://forms.googleapis.com',
iconUrl: '{BASE_URL}/apps/google-forms/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/google-forms/connection',
authDocUrl: '{DOCS_URL}/apps/google-forms/connection',
primaryColor: '673AB7',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -12,7 +12,7 @@ export default defineApp({
baseUrl: 'https://docs.google.com/spreadsheets',
apiBaseUrl: 'https://sheets.googleapis.com',
iconUrl: '{BASE_URL}/apps/google-sheets/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/google-sheets/connection',
authDocUrl: '{DOCS_URL}/apps/google-sheets/connection',
primaryColor: '0F9D58',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://tryhelix.ai',
apiBaseUrl: 'https://app.tryhelix.ai',
iconUrl: '{BASE_URL}/apps/helix/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/helix/connection',
authDocUrl: '{DOCS_URL}/apps/helix/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -5,7 +5,7 @@ export default defineApp({
name: 'HTTP Request',
key: 'http-request',
iconUrl: '{BASE_URL}/apps/http-request/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/http-request/connection',
authDocUrl: '{DOCS_URL}/apps/http-request/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -1,4 +1,3 @@
import createContact from './create-contact/index.js';
import updateContact from './update-contact/index.js';
export default [createContact, updateContact];
export default [createContact];

View File

@@ -1,96 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Update contact',
key: 'updateContact',
description: `Updates an existing contact on user's account.`,
arguments: [
{
label: 'Contact ID',
key: 'contactId',
type: 'string',
required: true,
variables: true,
},
{
label: 'Company name',
key: 'company',
type: 'string',
required: false,
variables: true,
},
{
label: 'Email',
key: 'email',
type: 'string',
required: false,
variables: true,
},
{
label: 'First name',
key: 'firstName',
type: 'string',
required: false,
variables: true,
},
{
label: 'Last name',
key: 'lastName',
type: 'string',
required: false,
description: 'Last name',
variables: true,
},
{
label: 'Phone',
key: 'phone',
type: 'string',
required: false,
variables: true,
},
{
label: 'Website URL',
key: 'website',
type: 'string',
required: false,
variables: true,
},
{
label: 'Owner ID',
key: 'hubspotOwnerId',
type: 'string',
required: false,
variables: true,
},
],
async run($) {
const {
contactId,
company,
email,
firstName,
lastName,
phone,
website,
hubspotOwnerId,
} = $.step.parameters;
const response = await $.http.patch(
`crm/v3/objects/contacts/${contactId}`,
{
properties: {
company,
email,
firstname: firstName,
lastname: lastName,
phone,
website,
hubspot_owner_id: hubspotOwnerId,
},
}
);
$.setActionItem({ raw: response.data });
},
});

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'HubSpot',
key: 'hubspot',
iconUrl: '{BASE_URL}/apps/hubspot/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/hubspot/connection',
authDocUrl: '{DOCS_URL}/apps/hubspot/connection',
supportsConnections: true,
baseUrl: 'https://www.hubspot.com',
apiBaseUrl: 'https://api.hubapi.com',

View File

@@ -12,7 +12,7 @@ export default defineApp({
baseUrl: 'https://invoiceninja.com',
apiBaseUrl: 'https://invoicing.co/api',
iconUrl: '{BASE_URL}/apps/invoice-ninja/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/invoice-ninja/connection',
authDocUrl: '{DOCS_URL}/apps/invoice-ninja/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -10,7 +10,7 @@ export default defineApp({
name: 'Mattermost',
key: 'mattermost',
iconUrl: '{BASE_URL}/apps/mattermost/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/mattermost/connection',
authDocUrl: '{DOCS_URL}/apps/mattermost/connection',
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
primaryColor: '4a154b',

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://miro.com',
apiBaseUrl: 'https://api.miro.com',
iconUrl: '{BASE_URL}/apps/miro/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/miro/connection',
authDocUrl: '{DOCS_URL}/apps/miro/connection',
primaryColor: 'F2CA02',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -12,7 +12,7 @@ export default defineApp({
baseUrl: 'https://notion.com',
apiBaseUrl: 'https://api.notion.com',
iconUrl: '{BASE_URL}/apps/notion/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/notion/connection',
authDocUrl: '{DOCS_URL}/apps/notion/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [addAuthHeader, addNotionVersionHeader],

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Ntfy',
key: 'ntfy',
iconUrl: '{BASE_URL}/apps/ntfy/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/ntfy/connection',
authDocUrl: '{DOCS_URL}/apps/ntfy/connection',
supportsConnections: true,
baseUrl: 'https://ntfy.sh',
apiBaseUrl: 'https://ntfy.sh',

View File

@@ -6,7 +6,7 @@ export default defineApp({
name: 'Odoo',
key: 'odoo',
iconUrl: '{BASE_URL}/apps/odoo/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/odoo/connection',
authDocUrl: '{DOCS_URL}/apps/odoo/connection',
supportsConnections: true,
baseUrl: 'https://odoo.com',
apiBaseUrl: '',

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://openai.com',
apiBaseUrl: 'https://api.openai.com',
iconUrl: '{BASE_URL}/apps/openai/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/openai/connection',
authDocUrl: '{DOCS_URL}/apps/openai/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -12,7 +12,7 @@ export default defineApp({
baseUrl: '',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/pipedrive/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/pipedrive/connection',
authDocUrl: '{DOCS_URL}/apps/pipedrive/connection',
primaryColor: 'FFFFFF',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -8,7 +8,7 @@ export default defineApp({
name: 'Placetel',
key: 'placetel',
iconUrl: '{BASE_URL}/apps/placetel/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/placetel/connection',
authDocUrl: '{DOCS_URL}/apps/placetel/connection',
supportsConnections: true,
baseUrl: 'https://placetel.de',
apiBaseUrl: 'https://api.placetel.de',

View File

@@ -6,7 +6,7 @@ export default defineApp({
name: 'PostgreSQL',
key: 'postgresql',
iconUrl: '{BASE_URL}/apps/postgresql/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/postgresql/connection',
authDocUrl: '{DOCS_URL}/apps/postgresql/connection',
supportsConnections: true,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -9,7 +9,7 @@ export default defineApp({
baseUrl: 'https://pushover.net',
apiBaseUrl: 'https://api.pushover.net',
iconUrl: '{BASE_URL}/apps/pushover/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/pushover/connection',
authDocUrl: '{DOCS_URL}/apps/pushover/connection',
primaryColor: '249DF1',
supportsConnections: true,
auth,

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://www.reddit.com',
apiBaseUrl: 'https://oauth.reddit.com',
iconUrl: '{BASE_URL}/apps/reddit/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/reddit/connection',
authDocUrl: '{DOCS_URL}/apps/reddit/connection',
primaryColor: 'FF4500',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Remove.bg',
key: 'removebg',
iconUrl: '{BASE_URL}/apps/removebg/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/removebg/connection',
authDocUrl: '{DOCS_URL}/apps/removebg/connection',
supportsConnections: true,
baseUrl: 'https://www.remove.bg',
apiBaseUrl: 'https://api.remove.bg/v1.0',

View File

@@ -5,7 +5,7 @@ export default defineApp({
name: 'RSS',
key: 'rss',
iconUrl: '{BASE_URL}/apps/rss/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/rss/connection',
authDocUrl: '{DOCS_URL}/apps/rss/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -9,7 +9,7 @@ export default defineApp({
name: 'Salesforce',
key: 'salesforce',
iconUrl: '{BASE_URL}/apps/salesforce/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/connections/salesforce',
authDocUrl: '{DOCS_URL}/connections/salesforce',
supportsConnections: true,
baseUrl: 'https://salesforce.com',
apiBaseUrl: '',

View File

@@ -6,7 +6,7 @@ export default defineApp({
key: 'scheduler',
iconUrl: '{BASE_URL}/apps/scheduler/assets/favicon.svg',
docUrl: 'https://automatisch.io/docs/scheduler',
authDocUrl: 'https://automatisch.io/docs/apps/scheduler/connection',
authDocUrl: '{DOCS_URL}/apps/scheduler/connection',
baseUrl: '',
apiBaseUrl: '',
primaryColor: '0059F7',

View File

@@ -11,7 +11,7 @@ export default defineApp({
baseUrl: '',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/self-hosted-llm/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/self-hosted-llm/connection',
authDocUrl: '{DOCS_URL}/apps/self-hosted-llm/connection',
primaryColor: '000000',
supportsConnections: true,
beforeRequest: [setBaseUrl, addAuthHeader],

View File

@@ -9,7 +9,7 @@ export default defineApp({
name: 'SignalWire',
key: 'signalwire',
iconUrl: '{BASE_URL}/apps/signalwire/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/signalwire/connection',
authDocUrl: '{DOCS_URL}/apps/signalwire/connection',
supportsConnections: true,
baseUrl: 'https://signalwire.com',
apiBaseUrl: '',

View File

@@ -9,7 +9,7 @@ export default defineApp({
name: 'Slack',
key: 'slack',
iconUrl: '{BASE_URL}/apps/slack/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/slack/connection',
authDocUrl: '{DOCS_URL}/apps/slack/connection',
supportsConnections: true,
baseUrl: 'https://slack.com',
apiBaseUrl: 'https://slack.com/api',

View File

@@ -6,7 +6,7 @@ export default defineApp({
name: 'SMTP',
key: 'smtp',
iconUrl: '{BASE_URL}/apps/smtp/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/smtp/connection',
authDocUrl: '{DOCS_URL}/apps/smtp/connection',
supportsConnections: true,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Spotify',
key: 'spotify',
iconUrl: '{BASE_URL}/apps/spotify/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/spotify/connection',
authDocUrl: '{DOCS_URL}/apps/spotify/connection',
supportsConnections: true,
baseUrl: 'https://spotify.com',
apiBaseUrl: 'https://api.spotify.com',

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Strava',
key: 'strava',
iconUrl: '{BASE_URL}/apps/strava/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/connections/strava',
authDocUrl: '{DOCS_URL}/connections/strava',
supportsConnections: true,
baseUrl: 'https://www.strava.com',
apiBaseUrl: 'https://www.strava.com/api',

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Stripe',
key: 'stripe',
iconUrl: '{BASE_URL}/apps/stripe/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/stripe/connection',
authDocUrl: '{DOCS_URL}/apps/stripe/connection',
supportsConnections: true,
baseUrl: 'https://stripe.com',
apiBaseUrl: 'https://api.stripe.com',

View File

@@ -7,7 +7,7 @@ export default defineApp({
name: 'Telegram',
key: 'telegram-bot',
iconUrl: '{BASE_URL}/apps/telegram-bot/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/telegram-bot/connection',
authDocUrl: '{DOCS_URL}/apps/telegram-bot/connection',
supportsConnections: true,
baseUrl: 'https://telegram.org',
apiBaseUrl: 'https://api.telegram.org',

View File

@@ -9,7 +9,7 @@ export default defineApp({
name: 'Todoist',
key: 'todoist',
iconUrl: '{BASE_URL}/apps/todoist/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/todoist/connection',
authDocUrl: '{DOCS_URL}/apps/todoist/connection',
supportsConnections: true,
baseUrl: 'https://todoist.com',
apiBaseUrl: 'https://api.todoist.com/rest/v2',

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://trello.com/',
apiBaseUrl: 'https://api.trello.com',
iconUrl: '{BASE_URL}/apps/trello/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/trello/connection',
authDocUrl: '{DOCS_URL}/apps/trello/connection',
supportsConnections: true,
primaryColor: '0079bf',
beforeRequest: [addAuthHeader],

View File

@@ -9,7 +9,7 @@ export default defineApp({
name: 'Twilio',
key: 'twilio',
iconUrl: '{BASE_URL}/apps/twilio/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/twilio/connection',
authDocUrl: '{DOCS_URL}/apps/twilio/connection',
supportsConnections: true,
baseUrl: 'https://twilio.com',
apiBaseUrl: 'https://api.twilio.com',

View File

@@ -8,7 +8,7 @@ export default defineApp({
name: 'Twitter',
key: 'twitter',
iconUrl: '{BASE_URL}/apps/twitter/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/twitter/connection',
authDocUrl: '{DOCS_URL}/apps/twitter/connection',
supportsConnections: true,
baseUrl: 'https://twitter.com',
apiBaseUrl: 'https://api.twitter.com',

View File

@@ -8,7 +8,7 @@ export default defineApp({
name: 'Typeform',
key: 'typeform',
iconUrl: '{BASE_URL}/apps/typeform/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/typeform/connection',
authDocUrl: '{DOCS_URL}/apps/typeform/connection',
supportsConnections: true,
baseUrl: 'https://typeform.com',
apiBaseUrl: 'https://api.typeform.com',

View File

@@ -6,7 +6,7 @@ export default defineApp({
name: 'Webhook',
key: 'webhook',
iconUrl: '{BASE_URL}/apps/webhook/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/webhook/connection',
authDocUrl: '{DOCS_URL}/apps/webhook/connection',
supportsConnections: false,
baseUrl: '',
apiBaseUrl: '',

View File

@@ -9,7 +9,7 @@ export default defineApp({
name: 'WordPress',
key: 'wordpress',
iconUrl: '{BASE_URL}/apps/wordpress/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/wordpress/connection',
authDocUrl: '{DOCS_URL}/apps/wordpress/connection',
supportsConnections: true,
baseUrl: 'https://wordpress.com',
apiBaseUrl: '',

View File

@@ -10,7 +10,7 @@ export default defineApp({
baseUrl: 'https://go.xero.com',
apiBaseUrl: 'https://api.xero.com',
iconUrl: '{BASE_URL}/apps/xero/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/xero/connection',
authDocUrl: '{DOCS_URL}/apps/xero/connection',
primaryColor: '13B5EA',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -9,7 +9,7 @@ export default defineApp({
baseUrl: 'https://www.youtube.com/',
apiBaseUrl: 'https://www.googleapis.com/youtube',
iconUrl: '{BASE_URL}/apps/youtube/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/youtube/connection',
authDocUrl: '{DOCS_URL}/apps/youtube/connection',
primaryColor: 'FF0000',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -11,7 +11,7 @@ export default defineApp({
baseUrl: 'https://zendesk.com/',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/zendesk/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/zendesk/connection',
authDocUrl: '{DOCS_URL}/apps/zendesk/connection',
primaryColor: '17494d',
supportsConnections: true,
beforeRequest: [addAuthHeader],

View File

@@ -38,6 +38,9 @@ if (process.env.WEB_APP_URL) {
let webhookUrl = new URL(process.env.WEBHOOK_URL || apiUrl).toString();
webhookUrl = webhookUrl.substring(0, webhookUrl.length - 1);
const publicDocsUrl = 'https://automatisch.io/docs';
const docsUrl = process.env.DOCS_URL || publicDocsUrl;
const appEnv = process.env.APP_ENV || 'development';
const appConfig = {
@@ -73,6 +76,7 @@ const appConfig = {
baseUrl: apiUrl,
webAppUrl,
webhookUrl,
docsUrl,
telemetryEnabled: process.env.TELEMETRY_ENABLED === 'false' ? false : true,
requestBodySizeLimit: '1mb',
smtpHost: process.env.SMTP_HOST,

View File

@@ -2,7 +2,7 @@ import appConfig from './app.js';
const corsOptions = {
origin: appConfig.webAppUrl,
methods: 'POST',
methods: 'GET,HEAD,POST,DELETE',
credentials: true,
optionsSuccessStatus: 200,
};

View File

@@ -0,0 +1,15 @@
export default async (request, response) => {
const token = request.params.token;
const accessToken = await request.currentUser
.$relatedQuery('accessTokens')
.findOne({
token,
revoked_at: null,
})
.throwIfNotFound();
await accessToken.revoke();
response.status(204).send();
};

View File

@@ -0,0 +1,54 @@
import { expect, describe, it, beforeEach } from 'vitest';
import request from 'supertest';
import app from '../../../../app.js';
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id';
import { createUser } from '../../../../../test/factories/user.js';
import AccessToken from '../../../../models/access-token.js';
describe('DELETE /api/v1/access-tokens/:token', () => {
let token;
beforeEach(async () => {
const currentUser = await createUser({
email: 'user@automatisch.io',
password: 'password',
});
token = await createAuthTokenByUserId(currentUser.id);
});
it('should respond with HTTP 204 with correct token', async () => {
await request(app)
.delete(`/api/v1/access-tokens/${token}`)
.set('Authorization', token)
.expect(204);
const revokedToken = await AccessToken.query().findOne({ token });
expect(revokedToken).toBeDefined();
expect(revokedToken.revokedAt).not.toBeNull();
});
it('should respond with HTTP 401 with incorrect credentials', async () => {
await request(app)
.delete(`/api/v1/access-tokens/${token}`)
.set('Authorization', 'wrong-token')
.expect(401);
const unrevokedToken = await AccessToken.query().findOne({ token });
expect(unrevokedToken).toBeDefined();
expect(unrevokedToken.revokedAt).toBeNull();
});
it('should respond with HTTP 404 with correct credentials, but non-valid token', async () => {
await request(app)
.delete('/api/v1/access-tokens/wrong-token')
.set('Authorization', token)
.expect(404);
const unrevokedToken = await AccessToken.query().findOne({ token });
expect(unrevokedToken).toBeDefined();
expect(unrevokedToken.revokedAt).toBeNull();
});
});

View File

@@ -22,7 +22,7 @@ describe('GET /api/v1/admin/apps/:appKey/auth-clients/:appAuthClientId', () => {
appKey: 'deepl',
});
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return specified app auth client', async () => {

View File

@@ -17,7 +17,7 @@ describe('GET /api/v1/admin/apps/:appKey/auth-clients', () => {
adminRole = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: adminRole.id });
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return specified app auth client info', async () => {

View File

@@ -14,7 +14,7 @@ describe('GET /api/v1/admin/permissions/catalog', () => {
role = await createRole({ key: 'admin' });
currentUser = await createUser({ roleId: role.id });
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return roles', async () => {

View File

@@ -18,7 +18,7 @@ describe('GET /api/v1/admin/roles/:roleId', () => {
permissionTwo = await createPermission({ roleId: role.id });
currentUser = await createUser({ roleId: role.id });
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return role', async () => {

View File

@@ -15,7 +15,7 @@ describe('GET /api/v1/admin/roles', () => {
roleTwo = await createRole({ key: 'user' });
currentUser = await createUser({ roleId: roleOne.id });
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return roles', async () => {

View File

@@ -28,7 +28,7 @@ describe('GET /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mapping
remoteRoleName: 'User',
});
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return role mappings', async () => {

View File

@@ -17,7 +17,7 @@ describe('GET /api/v1/admin/saml-auth-provider/:samlAuthProviderId', () => {
currentUser = await createUser({ roleId: role.id });
samlAuthProvider = await createSamlAuthProvider();
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return saml auth provider with specified id', async () => {

View File

@@ -18,7 +18,7 @@ describe('GET /api/v1/admin/saml-auth-providers', () => {
samlAuthProviderOne = await createSamlAuthProvider();
samlAuthProviderTwo = await createSamlAuthProvider();
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return saml auth providers', async () => {

View File

@@ -18,7 +18,7 @@ describe('GET /api/v1/admin/users/:userId', () => {
anotherUser = await createUser();
anotherUserRole = await anotherUser.$relatedQuery('role');
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return specified user info', async () => {

View File

@@ -28,7 +28,7 @@ describe('GET /api/v1/admin/users', () => {
fullName: 'Another User',
});
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return users data', async () => {

View File

@@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/actions/:actionKey/substeps', () => {
beforeEach(async () => {
currentUser = await createUser();
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
exampleApp = await App.findOneByKey('github');
});

View File

@@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/actions', () => {
beforeEach(async () => {
currentUser = await createUser();
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return the app actions', async () => {

View File

@@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey', () => {
beforeEach(async () => {
currentUser = await createUser();
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return the app info', async () => {

View File

@@ -11,7 +11,7 @@ describe('GET /api/v1/apps', () => {
beforeEach(async () => {
currentUser = await createUser();
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
apps = await App.findAll();
});

View File

@@ -19,7 +19,7 @@ describe('GET /api/v1/apps/:appKey/auth-clients/:appAuthClientId', () => {
appKey: 'deepl',
});
token = createAuthTokenByUserId(currentUser.id);
token = await createAuthTokenByUserId(currentUser.id);
});
it('should return specified app auth client', async () => {

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