Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ff72b2ae35 |
@@ -1 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/vscode/devcontainers/base:ubuntu-22.04
|
|
@@ -1,45 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
CURRENT_DIR="$(pwd)"
|
|
||||||
BACKEND_PORT=3000
|
|
||||||
WEB_PORT=3001
|
|
||||||
|
|
||||||
echo "Configuring backend environment variables..."
|
|
||||||
cd packages/backend
|
|
||||||
rm -rf .env
|
|
||||||
echo "
|
|
||||||
PORT=$BACKEND_PORT
|
|
||||||
WEB_APP_URL=http://localhost:$WEB_PORT
|
|
||||||
APP_ENV=development
|
|
||||||
POSTGRES_DATABASE=automatisch
|
|
||||||
POSTGRES_PORT=5432
|
|
||||||
POSTGRES_HOST=postgres
|
|
||||||
POSTGRES_USERNAME=automatisch_user
|
|
||||||
POSTGRES_PASSWORD=automatisch_password
|
|
||||||
ENCRYPTION_KEY=sample_encryption_key
|
|
||||||
WEBHOOK_SECRET_KEY=sample_webhook_secret_key
|
|
||||||
APP_SECRET_KEY=sample_app_secret_key
|
|
||||||
REDIS_HOST=redis
|
|
||||||
SERVE_WEB_APP_SEPARATELY=true" >> .env
|
|
||||||
cd $CURRENT_DIR
|
|
||||||
|
|
||||||
echo "Configuring web environment variables..."
|
|
||||||
cd packages/web
|
|
||||||
rm -rf .env
|
|
||||||
echo "
|
|
||||||
PORT=$WEB_PORT
|
|
||||||
REACT_APP_GRAPHQL_URL=http://localhost:$BACKEND_PORT/graphql
|
|
||||||
REACT_APP_NOTIFICATIONS_URL=https://notifications.automatisch.io
|
|
||||||
" >> .env
|
|
||||||
cd $CURRENT_DIR
|
|
||||||
|
|
||||||
echo "Installing and linking dependencies..."
|
|
||||||
yarn
|
|
||||||
yarn lerna bootstrap
|
|
||||||
|
|
||||||
echo "Migrating database..."
|
|
||||||
cd packages/backend
|
|
||||||
yarn db:migrate
|
|
||||||
yarn db:seed:user
|
|
||||||
|
|
||||||
echo "Done!"
|
|
@@ -1,53 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Automatisch",
|
|
||||||
"dockerComposeFile": "docker-compose.yml",
|
|
||||||
"service": "app",
|
|
||||||
"workspaceFolder": "/workspace",
|
|
||||||
"features": {
|
|
||||||
"ghcr.io/devcontainers/features/git:1": {
|
|
||||||
"version": "latest"
|
|
||||||
},
|
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
|
||||||
"version": 16
|
|
||||||
},
|
|
||||||
"ghcr.io/devcontainers/features/common-utils:1": {
|
|
||||||
"username": "vscode",
|
|
||||||
"uid": 1000,
|
|
||||||
"gid": 1000,
|
|
||||||
"installZsh": true,
|
|
||||||
"installOhMyZsh": true,
|
|
||||||
"configureZshAsDefaultShell": true,
|
|
||||||
"upgradePackages": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"hostRequirements": {
|
|
||||||
"cpus": 4,
|
|
||||||
"memory": "8gb",
|
|
||||||
"storage": "32gb"
|
|
||||||
},
|
|
||||||
|
|
||||||
"portsAttributes": {
|
|
||||||
"3000": {
|
|
||||||
"label": "Backend",
|
|
||||||
"onAutoForward": "silent",
|
|
||||||
"protocol": "http"
|
|
||||||
},
|
|
||||||
"3001": {
|
|
||||||
"label": "Frontend",
|
|
||||||
"onAutoForward": "silent",
|
|
||||||
"protocol": "http"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"forwardPorts": [3000, 3001],
|
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
|
||||||
"postCreateCommand": ["bash", ".devcontainer/boot.sh"]
|
|
||||||
|
|
||||||
// Configure tool-specific properties.
|
|
||||||
// "customizations": {},
|
|
||||||
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
||||||
// "remoteUser": "root"
|
|
||||||
}
|
|
@@ -1,39 +0,0 @@
|
|||||||
version: '3.9'
|
|
||||||
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
build:
|
|
||||||
context: ..
|
|
||||||
dockerfile: .devcontainer/Dockerfile
|
|
||||||
volumes:
|
|
||||||
- ..:/workspace:cached
|
|
||||||
command: sleep infinity
|
|
||||||
postgres:
|
|
||||||
image: 'postgres:14.5-alpine'
|
|
||||||
environment:
|
|
||||||
- POSTGRES_DB=automatisch
|
|
||||||
- POSTGRES_USER=automatisch_user
|
|
||||||
- POSTGRES_PASSWORD=automatisch_password
|
|
||||||
volumes:
|
|
||||||
- postgres_data:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
ports:
|
|
||||||
- '5432:5432'
|
|
||||||
expose:
|
|
||||||
- 5432
|
|
||||||
redis:
|
|
||||||
image: 'redis:7.0.4-alpine'
|
|
||||||
volumes:
|
|
||||||
- redis_data:/data
|
|
||||||
ports:
|
|
||||||
- '6379:6379'
|
|
||||||
expose:
|
|
||||||
- 6379
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
postgres_data:
|
|
||||||
redis_data:
|
|
@@ -1,5 +0,0 @@
|
|||||||
# Automatisch Contributor License Agreement
|
|
||||||
|
|
||||||
I give Automatisch permission to license my contributions on any terms they like. I am giving them this license in order to make it possible for them to accept my contributions into their project.
|
|
||||||
|
|
||||||
**_As far as the law allows, my contributions come as is, without any warranty or condition, and I will not be liable to anyone for any damages related to this software or this license, under any kind of legal claim._**
|
|
3
LICENSE
@@ -1,3 +0,0 @@
|
|||||||
LICENSE.agpl (AGPL-3.0) applies to all files in this
|
|
||||||
repository, except for files that contain ".ee." in their name
|
|
||||||
which are covered by LICENSE.enterprise.
|
|
@@ -1,35 +0,0 @@
|
|||||||
The Automatisch Enterprise license (the “Enterprise License”)
|
|
||||||
Copyright (c) 2023 Ömer Faruk Aydın, Ali Barın.
|
|
||||||
|
|
||||||
With regard to the Automatisch Software:
|
|
||||||
|
|
||||||
This software and associated documentation files (the "Software") may only be
|
|
||||||
used in production, if you (and any entity that you represent) have a valid
|
|
||||||
Automatisch Enterprise license for the correct number of user seats. Subject
|
|
||||||
to the foregoing sentence, you are free to modify this Software and publish
|
|
||||||
patches to the Software. You agree that Automatisch and/or its licensors
|
|
||||||
(as applicable) retain all right, title and interest in and to all such
|
|
||||||
modifications and/or patches, and all such modifications and/or patches may
|
|
||||||
only be used, copied, modified, displayed, distributed, or otherwise exploited
|
|
||||||
with a valid Automatisch Enterprise license for the correct number of user seats.
|
|
||||||
Notwithstanding the foregoing, you may copy and modify the Software for
|
|
||||||
development and testing purposes, without requiring a subscription. You agree
|
|
||||||
that Automatisch and/or its licensors (as applicable) retain all right, title
|
|
||||||
and interest in and to all such modifications. You are not granted any other
|
|
||||||
rights beyond what is expressly stated herein. Subject to the foregoing, it is
|
|
||||||
forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software.
|
|
||||||
|
|
||||||
The full text of this Enterprise License shall be included in all copies or
|
|
||||||
substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
For all third party components incorporated into the Automatisch Software, those
|
|
||||||
components are licensed under the original license provided by the owner of the
|
|
||||||
applicable component.
|
|
16
README.md
@@ -24,7 +24,7 @@ The official documentation can be found here: [https://automatisch.io/docs](http
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the repository
|
# Clone the repository
|
||||||
git clone https://github.com/automatisch/automatisch.git
|
git clone git@github.com:automatisch/automatisch.git
|
||||||
|
|
||||||
# Go to the repository folder
|
# Go to the repository folder
|
||||||
cd automatisch
|
cd automatisch
|
||||||
@@ -44,18 +44,10 @@ For other installation types, you can check the [installation](https://automatis
|
|||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
If you have any questions or problems, please visit our GitHub issues page, and we'll try to help you as soon as possible.
|
If you have any questions or problems, please visit our GitHub discussions page, and we'll try to help you as soon as possible.
|
||||||
|
|
||||||
[https://github.com/automatisch/automatisch/issues](https://github.com/automatisch/automatisch/issues)
|
[https://github.com/automatisch/automatisch/discussions](https://github.com/automatisch/automatisch/discussions)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Automatisch Community Edition (Automatisch CE) is an open-source software with the [AGPL-3.0 license](LICENSE.agpl).
|
Automatisch is an open-source software with the [AGPL 3.0 license](https://github.com/automatisch/automatisch/blob/main/LICENSE.md).
|
||||||
|
|
||||||
Automatisch Enterprise Edition (Automatisch EE) is a commercial offering with the [Enterprise license](LICENSE.enterprise).
|
|
||||||
|
|
||||||
The Automatisch repository contains both AGPL-licensed and Enterprise-licensed files. We maintain a single repository to make development easier.
|
|
||||||
|
|
||||||
All files that contain ".ee." in their name fall under the [Enterprise license](LICENSE.enterprise). All other files fall under the [AGPL-3.0 license](LICENSE.agpl).
|
|
||||||
|
|
||||||
See the [LICENSE](LICENSE) file for more information.
|
|
||||||
|
@@ -2,13 +2,13 @@
|
|||||||
FROM node:16-alpine
|
FROM node:16-alpine
|
||||||
WORKDIR /automatisch
|
WORKDIR /automatisch
|
||||||
|
|
||||||
RUN \
|
RUN apk --no-cache add --virtual build-dependencies python3 build-base
|
||||||
apk --no-cache add --virtual build-dependencies python3 build-base && \
|
|
||||||
yarn global add @automatisch/cli@0.5.0 --network-timeout 1000000 && \
|
|
||||||
rm -rf /usr/local/share/.cache/ && \
|
|
||||||
apk del build-dependencies
|
|
||||||
|
|
||||||
COPY ./entrypoint.sh /entrypoint.sh
|
COPY ./entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
RUN yarn global add @automatisch/cli@0.3.0
|
||||||
|
|
||||||
|
RUN apk del build-dependencies python3 build-base
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
ENTRYPOINT ["sh", "/entrypoint.sh"]
|
ENTRYPOINT ["sh", "/entrypoint.sh"]
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM automatischio/automatisch:0.5.0
|
FROM automatischio/automatisch:0.3.0
|
||||||
WORKDIR /automatisch
|
WORKDIR /automatisch
|
||||||
|
|
||||||
RUN apk add --no-cache openssl dos2unix
|
RUN apk add --no-cache openssl dos2unix
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"version": "0.6.0",
|
"version": "0.4.0",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"command": {
|
"command": {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@automatisch/root",
|
"name": "@automatisch/root",
|
||||||
"license": "See LICENSE file",
|
"license": "AGPL-3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "lerna run --stream --parallel --scope=@*/{web,backend} dev",
|
"start": "lerna run --stream --parallel --scope=@*/{web,backend} dev",
|
||||||
|
@@ -12,8 +12,6 @@ export async function createUser(
|
|||||||
const userParams = {
|
const userParams = {
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
fullName: 'Initial admin',
|
|
||||||
role: 'admin',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@@ -12,7 +12,6 @@ const knexConfig = {
|
|||||||
database: appConfig.postgresDatabase,
|
database: appConfig.postgresDatabase,
|
||||||
ssl: appConfig.postgresEnableSsl,
|
ssl: appConfig.postgresEnableSsl,
|
||||||
},
|
},
|
||||||
searchPath: [appConfig.postgresSchema],
|
|
||||||
pool: { min: 0, max: 20 },
|
pool: { min: 0, max: 20 },
|
||||||
migrations: {
|
migrations: {
|
||||||
directory: __dirname + '/src/db/migrations',
|
directory: __dirname + '/src/db/migrations',
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@automatisch/backend",
|
"name": "@automatisch/backend",
|
||||||
"version": "0.6.0",
|
"version": "0.4.0",
|
||||||
"license": "See LICENSE file",
|
"license": "AGPL-3.0",
|
||||||
"description": "The open source Zapier alternative. Build workflow automation without spending time and money.",
|
"description": "The open source Zapier alternative. Build workflow automation without spending time and money.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "ts-node-dev --exit-child src/server.ts",
|
"dev": "ts-node-dev --exit-child src/server.ts",
|
||||||
@@ -22,13 +22,11 @@
|
|||||||
"prebuild": "rm -rf ./dist"
|
"prebuild": "rm -rf ./dist"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@automatisch/web": "^0.6.0",
|
"@automatisch/web": "^0.4.0",
|
||||||
"@bull-board/express": "^3.10.1",
|
"@bull-board/express": "^3.10.1",
|
||||||
"@graphql-tools/graphql-file-loader": "^7.3.4",
|
"@graphql-tools/graphql-file-loader": "^7.3.4",
|
||||||
"@graphql-tools/load": "^7.5.2",
|
"@graphql-tools/load": "^7.5.2",
|
||||||
"@rudderstack/rudder-sdk-node": "^1.1.2",
|
"@rudderstack/rudder-sdk-node": "^1.1.2",
|
||||||
"@sentry/node": "^7.42.0",
|
|
||||||
"@sentry/tracing": "^7.42.0",
|
|
||||||
"@types/luxon": "^2.3.1",
|
"@types/luxon": "^2.3.1",
|
||||||
"ajv-formats": "^2.1.1",
|
"ajv-formats": "^2.1.1",
|
||||||
"axios": "0.24.0",
|
"axios": "0.24.0",
|
||||||
@@ -47,21 +45,17 @@
|
|||||||
"graphql-shield": "^7.5.0",
|
"graphql-shield": "^7.5.0",
|
||||||
"graphql-tools": "^8.2.0",
|
"graphql-tools": "^8.2.0",
|
||||||
"graphql-type-json": "^0.3.2",
|
"graphql-type-json": "^0.3.2",
|
||||||
"handlebars": "^4.7.7",
|
|
||||||
"http-errors": "~1.6.3",
|
"http-errors": "~1.6.3",
|
||||||
"jsonwebtoken": "^9.0.0",
|
"jsonwebtoken": "^9.0.0",
|
||||||
"knex": "^2.4.0",
|
"knex": "^0.95.11",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
"luxon": "2.5.2",
|
"luxon": "2.5.2",
|
||||||
"memory-cache": "^0.2.0",
|
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
"nodemailer": "6.7.0",
|
"nodemailer": "6.7.0",
|
||||||
"oauth-1.0a": "^2.2.6",
|
"oauth-1.0a": "^2.2.6",
|
||||||
"objection": "^3.0.0",
|
"objection": "^3.0.0",
|
||||||
"pg": "^8.7.1",
|
"pg": "^8.7.1",
|
||||||
"php-serialize": "^4.0.2",
|
|
||||||
"stripe": "^11.13.0",
|
|
||||||
"winston": "^3.7.1"
|
"winston": "^3.7.1"
|
||||||
},
|
},
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -100,7 +94,7 @@
|
|||||||
"url": "https://github.com/automatisch/automatisch/issues"
|
"url": "https://github.com/automatisch/automatisch/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@automatisch/types": "^0.6.0",
|
"@automatisch/types": "^0.4.0",
|
||||||
"@types/bcrypt": "^5.0.0",
|
"@types/bcrypt": "^5.0.0",
|
||||||
"@types/bull": "^3.15.8",
|
"@types/bull": "^3.15.8",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@@ -109,7 +103,6 @@
|
|||||||
"@types/http-errors": "^1.8.1",
|
"@types/http-errors": "^1.8.1",
|
||||||
"@types/jsonwebtoken": "^8.5.8",
|
"@types/jsonwebtoken": "^8.5.8",
|
||||||
"@types/lodash.get": "^4.4.6",
|
"@types/lodash.get": "^4.4.6",
|
||||||
"@types/memory-cache": "^0.2.2",
|
|
||||||
"@types/morgan": "^1.9.3",
|
"@types/morgan": "^1.9.3",
|
||||||
"@types/multer": "1.4.7",
|
"@types/multer": "1.4.7",
|
||||||
"@types/node": "^16.10.2",
|
"@types/node": "^16.10.2",
|
||||||
|
@@ -1,12 +1,8 @@
|
|||||||
import createError from 'http-errors';
|
import createError from 'http-errors';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
|
|
||||||
import { IRequest } from '@automatisch/types';
|
|
||||||
import appConfig from './config/app';
|
|
||||||
import corsOptions from './config/cors-options';
|
import corsOptions from './config/cors-options';
|
||||||
import morgan from './helpers/morgan';
|
import morgan from './helpers/morgan';
|
||||||
import * as Sentry from './helpers/sentry.ee';
|
|
||||||
import appAssetsHandler from './helpers/app-assets-handler';
|
import appAssetsHandler from './helpers/app-assets-handler';
|
||||||
import webUIHandler from './helpers/web-ui-handler';
|
import webUIHandler from './helpers/web-ui-handler';
|
||||||
import errorHandler from './helpers/error-handler';
|
import errorHandler from './helpers/error-handler';
|
||||||
@@ -17,16 +13,12 @@ import {
|
|||||||
} from './helpers/create-bull-board-handler';
|
} from './helpers/create-bull-board-handler';
|
||||||
import injectBullBoardHandler from './helpers/inject-bull-board-handler';
|
import injectBullBoardHandler from './helpers/inject-bull-board-handler';
|
||||||
import router from './routes';
|
import router from './routes';
|
||||||
|
import { IRequest } from '@automatisch/types';
|
||||||
|
|
||||||
createBullBoardHandler(serverAdapter);
|
createBullBoardHandler(serverAdapter);
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
Sentry.init(app);
|
|
||||||
|
|
||||||
Sentry.attachRequestHandler(app);
|
|
||||||
Sentry.attachTracingHandler(app);
|
|
||||||
|
|
||||||
injectBullBoardHandler(app, serverAdapter);
|
injectBullBoardHandler(app, serverAdapter);
|
||||||
|
|
||||||
appAssetsHandler(app);
|
appAssetsHandler(app);
|
||||||
@@ -34,21 +26,17 @@ appAssetsHandler(app);
|
|||||||
app.use(morgan);
|
app.use(morgan);
|
||||||
app.use(
|
app.use(
|
||||||
express.json({
|
express.json({
|
||||||
limit: appConfig.requestBodySizeLimit,
|
|
||||||
verify(req, res, buf) {
|
|
||||||
(req as IRequest).rawBody = buf;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
app.use(
|
|
||||||
express.urlencoded({
|
|
||||||
extended: true,
|
|
||||||
limit: appConfig.requestBodySizeLimit,
|
|
||||||
verify(req, res, buf) {
|
verify(req, res, buf) {
|
||||||
(req as IRequest).rawBody = buf;
|
(req as IRequest).rawBody = buf;
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
app.use(express.urlencoded({
|
||||||
|
extended: false,
|
||||||
|
verify(req, res, buf) {
|
||||||
|
(req as IRequest).rawBody = buf;
|
||||||
|
},
|
||||||
|
}));
|
||||||
app.use(cors(corsOptions));
|
app.use(cors(corsOptions));
|
||||||
app.use('/', router);
|
app.use('/', router);
|
||||||
|
|
||||||
@@ -59,8 +47,6 @@ app.use(function (req, res, next) {
|
|||||||
next(createError(404));
|
next(createError(404));
|
||||||
});
|
});
|
||||||
|
|
||||||
Sentry.attachErrorHandler(app);
|
|
||||||
|
|
||||||
app.use(errorHandler);
|
app.use(errorHandler);
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
import path from 'node:path';
|
|
||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Create folder',
|
|
||||||
key: 'createFolder',
|
|
||||||
description: 'Create a new folder with the given parent folder and folder name',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Folder',
|
|
||||||
key: 'parentFolder',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'Enter the parent folder path, like /TextFiles/ or /Documents/Taxes/',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Folder Name',
|
|
||||||
key: 'folderName',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'Enter the name for the new folder',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const parentFolder = $.step.parameters.parentFolder as string;
|
|
||||||
const folderName = $.step.parameters.folderName as string;
|
|
||||||
const folderPath = path.join(parentFolder, folderName);
|
|
||||||
|
|
||||||
const response = await $.http.post('/2/files/create_folder_v2', { path: folderPath });
|
|
||||||
|
|
||||||
$.setActionItem({ raw: response.data });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,4 +0,0 @@
|
|||||||
import createFolder from "./create-folder";
|
|
||||||
import renameFile from "./rename-file";
|
|
||||||
|
|
||||||
export default [createFolder, renameFile];
|
|
@@ -1,45 +0,0 @@
|
|||||||
import path from 'node:path';
|
|
||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Rename file',
|
|
||||||
key: 'renameFile',
|
|
||||||
description: 'Rename a file with the given file path and new name',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'File Path',
|
|
||||||
key: 'filePath',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description:
|
|
||||||
'Write the full path to the file such as /Folder1/File.pdf',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'New Name',
|
|
||||||
key: 'newName',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: "Enter the new name for the file (without the extension, e.g., '.pdf')",
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const filePath = $.step.parameters.filePath as string;
|
|
||||||
const newName = $.step.parameters.newName as string;
|
|
||||||
const fileObject = path.parse(filePath);
|
|
||||||
const newPath = path.format({
|
|
||||||
dir: fileObject.dir,
|
|
||||||
ext: fileObject.ext,
|
|
||||||
name: newName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await $.http.post('/2/files/move_v2', {
|
|
||||||
from_path: filePath,
|
|
||||||
to_path: newPath,
|
|
||||||
});
|
|
||||||
|
|
||||||
$.setActionItem({ raw: response.data.metadata });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,3 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" aria-label="Dropbox" role="img" viewBox="0 0 512 512" fill="#0061ff">
|
|
||||||
<path d="M158 101l-99 63 295 188 99-63m-99-188l99 63-295 188-99-63m99 83l98 63 98-63-98-62z"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 213 B |
@@ -1,22 +0,0 @@
|
|||||||
import { URLSearchParams } from 'url';
|
|
||||||
import { IField, IGlobalVariable } from '@automatisch/types';
|
|
||||||
import scopes from '../common/scopes';
|
|
||||||
|
|
||||||
export default async function generateAuthUrl($: IGlobalVariable) {
|
|
||||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
|
||||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
|
||||||
);
|
|
||||||
const callbackUrl = oauthRedirectUrlField.value as string;
|
|
||||||
|
|
||||||
const searchParams = new URLSearchParams({
|
|
||||||
client_id: $.auth.data.clientId as string,
|
|
||||||
redirect_uri: callbackUrl,
|
|
||||||
response_type: 'code',
|
|
||||||
scope: scopes.join(' '),
|
|
||||||
token_access_type: 'offline',
|
|
||||||
});
|
|
||||||
|
|
||||||
const url = `${$.app.baseUrl}/oauth2/authorize?${searchParams.toString()}`;
|
|
||||||
|
|
||||||
await $.auth.set({ url });
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
import generateAuthUrl from './generate-auth-url';
|
|
||||||
import verifyCredentials from './verify-credentials';
|
|
||||||
import isStillVerified from './is-still-verified';
|
|
||||||
import refreshToken from './refresh-token';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'oAuthRedirectUrl',
|
|
||||||
label: 'OAuth Redirect URL',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: true,
|
|
||||||
value: '{WEB_APP_URL}/app/dropbox/connections/add',
|
|
||||||
placeholder: null,
|
|
||||||
description:
|
|
||||||
'When asked to input an OAuth callback or redirect URL in Dropbox OAuth, enter the URL above.',
|
|
||||||
clickToCopy: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'clientId',
|
|
||||||
label: 'App Key',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: null,
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'clientSecret',
|
|
||||||
label: 'App Secret',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: null,
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
generateAuthUrl,
|
|
||||||
verifyCredentials,
|
|
||||||
isStillVerified,
|
|
||||||
refreshToken,
|
|
||||||
};
|
|
@@ -1,9 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
import getCurrentAccount from '../common/get-current-account';
|
|
||||||
|
|
||||||
const isStillVerified = async ($: IGlobalVariable) => {
|
|
||||||
const account = await getCurrentAccount($);
|
|
||||||
return !!account;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default isStillVerified;
|
|
@@ -1,41 +0,0 @@
|
|||||||
import { Buffer } from 'node:buffer';
|
|
||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const refreshToken = async ($: IGlobalVariable) => {
|
|
||||||
const params = {
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
refresh_token: $.auth.data.refreshToken as string,
|
|
||||||
};
|
|
||||||
|
|
||||||
const basicAuthToken = Buffer
|
|
||||||
.from(`${$.auth.data.clientId}:${$.auth.data.clientSecret}`)
|
|
||||||
.toString('base64');
|
|
||||||
|
|
||||||
const { data } = await $.http.post(
|
|
||||||
'oauth2/token',
|
|
||||||
null,
|
|
||||||
{
|
|
||||||
params,
|
|
||||||
headers: {
|
|
||||||
Authorization: `Basic ${basicAuthToken}`
|
|
||||||
},
|
|
||||||
additionalProperties: {
|
|
||||||
skipAddingAuthHeader: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
access_token: accessToken,
|
|
||||||
expires_in: expiresIn,
|
|
||||||
token_type: tokenType,
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accessToken,
|
|
||||||
expiresIn,
|
|
||||||
tokenType,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default refreshToken;
|
|
@@ -1,102 +0,0 @@
|
|||||||
import { IGlobalVariable, IField } from '@automatisch/types';
|
|
||||||
import getCurrentAccount from '../common/get-current-account';
|
|
||||||
|
|
||||||
type TAccount = {
|
|
||||||
account_id: string,
|
|
||||||
name: {
|
|
||||||
given_name: string,
|
|
||||||
surname: string,
|
|
||||||
familiar_name: string,
|
|
||||||
display_name: string,
|
|
||||||
abbreviated_name: string,
|
|
||||||
},
|
|
||||||
email: string,
|
|
||||||
email_verified: boolean,
|
|
||||||
disabled: boolean,
|
|
||||||
country: string,
|
|
||||||
locale: string,
|
|
||||||
referral_link: string,
|
|
||||||
is_paired: boolean,
|
|
||||||
account_type: {
|
|
||||||
".tag": string,
|
|
||||||
},
|
|
||||||
root_info: {
|
|
||||||
".tag": string,
|
|
||||||
root_namespace_id: string,
|
|
||||||
home_namespace_id: string,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
|
||||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
|
||||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
|
||||||
);
|
|
||||||
const redirectUrl = oauthRedirectUrlField.value as string;
|
|
||||||
const params = {
|
|
||||||
client_id: $.auth.data.clientId as string,
|
|
||||||
redirect_uri: redirectUrl,
|
|
||||||
client_secret: $.auth.data.clientSecret as string,
|
|
||||||
code: $.auth.data.code as string,
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
}
|
|
||||||
const { data: verifiedCredentials } = await $.http.post(
|
|
||||||
'/oauth2/token',
|
|
||||||
null,
|
|
||||||
{ params }
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
access_token: accessToken,
|
|
||||||
refresh_token: refreshToken,
|
|
||||||
expires_in: expiresIn,
|
|
||||||
scope: scope,
|
|
||||||
token_type: tokenType,
|
|
||||||
account_id: accountId,
|
|
||||||
team_id: teamId,
|
|
||||||
id_token: idToken,
|
|
||||||
uid,
|
|
||||||
} = verifiedCredentials;
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accessToken,
|
|
||||||
refreshToken,
|
|
||||||
expiresIn,
|
|
||||||
scope,
|
|
||||||
tokenType,
|
|
||||||
accountId,
|
|
||||||
teamId,
|
|
||||||
idToken,
|
|
||||||
uid
|
|
||||||
});
|
|
||||||
|
|
||||||
const account = await getCurrentAccount($) as TAccount;
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accountId: account.account_id,
|
|
||||||
name: {
|
|
||||||
givenName: account.name.given_name,
|
|
||||||
surname: account.name.surname,
|
|
||||||
familiarName: account.name.familiar_name,
|
|
||||||
displayName: account.name.display_name,
|
|
||||||
abbreviatedName: account.name.abbreviated_name,
|
|
||||||
},
|
|
||||||
email: account.email,
|
|
||||||
emailVerified: account.email_verified,
|
|
||||||
disabled: account.disabled,
|
|
||||||
country: account.country,
|
|
||||||
locale: account.locale,
|
|
||||||
referralLink: account.referral_link,
|
|
||||||
isPaired: account.is_paired,
|
|
||||||
accountType: {
|
|
||||||
".tag": account.account_type['.tag'],
|
|
||||||
},
|
|
||||||
rootInfo: {
|
|
||||||
".tag": account.root_info['.tag'],
|
|
||||||
rootNamespaceId: account.root_info.root_namespace_id,
|
|
||||||
homeNamespaceId: account.root_info.home_namespace_id,
|
|
||||||
},
|
|
||||||
screenName: `${account.name.display_name} - ${account.email}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default verifyCredentials;
|
|
@@ -1,13 +0,0 @@
|
|||||||
import { TBeforeRequest } from '@automatisch/types';
|
|
||||||
|
|
||||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
|
||||||
requestConfig.headers['Content-Type'] = 'application/json';
|
|
||||||
|
|
||||||
if (!requestConfig.additionalProperties?.skipAddingAuthHeader && $.auth.data?.accessToken) {
|
|
||||||
requestConfig.headers.Authorization = `Bearer ${$.auth.data.accessToken}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default addAuthHeader;
|
|
@@ -1,8 +0,0 @@
|
|||||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
|
||||||
|
|
||||||
const getCurrentAccount = async ($: IGlobalVariable): Promise<IJSONObject> => {
|
|
||||||
const response = await $.http.post('/2/users/get_current_account', null);
|
|
||||||
return response.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getCurrentAccount;
|
|
@@ -1,8 +0,0 @@
|
|||||||
const scopes = [
|
|
||||||
'account_info.read',
|
|
||||||
'files.metadata.read',
|
|
||||||
'files.content.write',
|
|
||||||
'files.content.read',
|
|
||||||
];
|
|
||||||
|
|
||||||
export default scopes;
|
|
@@ -1,18 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
|
||||||
import addAuthHeader from './common/add-auth-header';
|
|
||||||
import auth from './auth';
|
|
||||||
import actions from './actions';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'Dropbox',
|
|
||||||
key: 'dropbox',
|
|
||||||
iconUrl: '{BASE_URL}/apps/dropbox/assets/favicon.svg',
|
|
||||||
authDocUrl: 'https://automatisch.io/docs/apps/dropbox/connection',
|
|
||||||
supportsConnections: true,
|
|
||||||
baseUrl: 'https://dropbox.com',
|
|
||||||
apiBaseUrl: 'https://api.dropboxapi.com',
|
|
||||||
primaryColor: '0061ff',
|
|
||||||
beforeRequest: [addAuthHeader],
|
|
||||||
auth,
|
|
||||||
actions,
|
|
||||||
});
|
|
@@ -1,79 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
type TGroupItem = {
|
|
||||||
key: string;
|
|
||||||
operator: keyof TOperators;
|
|
||||||
value: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type TGroup = Record<'and', TGroupItem[]>;
|
|
||||||
|
|
||||||
const isEqual = (a: string, b: string) => a === b;
|
|
||||||
const isNotEqual = (a: string, b: string) => !isEqual(a, b)
|
|
||||||
const isGreaterThan = (a: string, b: string) => Number(a) > Number(b);
|
|
||||||
const isLessThan = (a: string, b: string) => Number(a) < Number(b);
|
|
||||||
const isGreaterThanOrEqual = (a: string, b: string) => Number(a) >= Number(b);
|
|
||||||
const isLessThanOrEqual = (a: string, b: string) => Number(a) <= Number(b);
|
|
||||||
const contains = (a: string, b: string) => a.includes(b);
|
|
||||||
const doesNotContain = (a: string, b: string) => !contains(a, b);
|
|
||||||
|
|
||||||
type TOperatorFunc = (a: string, b: string) => boolean;
|
|
||||||
|
|
||||||
type TOperators = {
|
|
||||||
equal: TOperatorFunc;
|
|
||||||
not_equal: TOperatorFunc;
|
|
||||||
greater_than: TOperatorFunc;
|
|
||||||
less_than: TOperatorFunc;
|
|
||||||
greater_than_or_equal: TOperatorFunc;
|
|
||||||
less_than_or_equal: TOperatorFunc;
|
|
||||||
contains: TOperatorFunc;
|
|
||||||
not_contains: TOperatorFunc;
|
|
||||||
};
|
|
||||||
|
|
||||||
const operators: TOperators = {
|
|
||||||
'equal': isEqual,
|
|
||||||
'not_equal': isNotEqual,
|
|
||||||
'greater_than': isGreaterThan,
|
|
||||||
'less_than': isLessThan,
|
|
||||||
'greater_than_or_equal': isGreaterThanOrEqual,
|
|
||||||
'less_than_or_equal': isLessThanOrEqual,
|
|
||||||
'contains': contains,
|
|
||||||
'not_contains': doesNotContain,
|
|
||||||
};
|
|
||||||
|
|
||||||
const operate = (operation: keyof TOperators, a: string, b: string) => {
|
|
||||||
return operators[operation](a, b);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Continue if conditions match',
|
|
||||||
key: 'continueIfMatches',
|
|
||||||
description: 'Let the execution continue if the conditions match',
|
|
||||||
arguments: [],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const orGroups = $.step.parameters.or as TGroup[];
|
|
||||||
|
|
||||||
const matchingGroups = orGroups.reduce((groups, group) => {
|
|
||||||
const matchingConditions = group.and
|
|
||||||
.filter((condition) => operate(condition.operator, condition.key, condition.value));
|
|
||||||
|
|
||||||
if (matchingConditions.length) {
|
|
||||||
return groups.concat([{ and: matchingConditions }]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return groups;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (matchingGroups.length === 0) {
|
|
||||||
$.execution.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$.setActionItem({
|
|
||||||
raw: {
|
|
||||||
or: matchingGroups,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,3 +0,0 @@
|
|||||||
import continueIfMatches from './continue';
|
|
||||||
|
|
||||||
export default [continueIfMatches];
|
|
@@ -1,8 +0,0 @@
|
|||||||
<svg width="800px" height="800px" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
||||||
<g id="Shape" fill="#000000" transform="translate(42.666667, 85.333333)">
|
|
||||||
<path d="M3.55271368e-14,1.42108547e-14 L191.565013,234.666667 L192,234.666667 L192,384 L234.666667,384 L234.666667,234.666667 L426.666667,1.42108547e-14 L3.55271368e-14,1.42108547e-14 Z M214.448,192 L211.81248,192 L89.9076267,42.6666667 L336.630187,42.6666667 L214.448,192 Z">
|
|
||||||
</path>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 628 B |
@@ -1,14 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
|
||||||
import actions from './actions';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'Filter',
|
|
||||||
key: 'filter',
|
|
||||||
iconUrl: '{BASE_URL}/apps/filter/assets/favicon.svg',
|
|
||||||
authDocUrl: 'https://automatisch.io/docs/apps/filter/connection',
|
|
||||||
supportsConnections: false,
|
|
||||||
baseUrl: '',
|
|
||||||
apiBaseUrl: '',
|
|
||||||
primaryColor: '001F52',
|
|
||||||
actions,
|
|
||||||
});
|
|
@@ -1,8 +0,0 @@
|
|||||||
<svg viewBox="0 0 87.3 78" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="m6.6 66.85 3.85 6.65c.8 1.4 1.95 2.5 3.3 3.3l13.75-23.8h-27.5c0 1.55.4 3.1 1.2 4.5z" fill="#0066da"/>
|
|
||||||
<path d="m43.65 25-13.75-23.8c-1.35.8-2.5 1.9-3.3 3.3l-25.4 44a9.06 9.06 0 0 0 -1.2 4.5h27.5z" fill="#00ac47"/>
|
|
||||||
<path d="m73.55 76.8c1.35-.8 2.5-1.9 3.3-3.3l1.6-2.75 7.65-13.25c.8-1.4 1.2-2.95 1.2-4.5h-27.502l5.852 11.5z" fill="#ea4335"/>
|
|
||||||
<path d="m43.65 25 13.75-23.8c-1.35-.8-2.9-1.2-4.5-1.2h-18.5c-1.6 0-3.15.45-4.5 1.2z" fill="#00832d"/>
|
|
||||||
<path d="m59.8 53h-32.3l-13.75 23.8c1.35.8 2.9 1.2 4.5 1.2h50.8c1.6 0 3.15-.45 4.5-1.2z" fill="#2684fc"/>
|
|
||||||
<path d="m73.4 26.5-12.7-22c-.8-1.4-1.95-2.5-3.3-3.3l-13.75 23.8 16.15 28h27.45c0-1.55-.4-3.1-1.2-4.5z" fill="#ffba00"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 755 B |
@@ -1,24 +0,0 @@
|
|||||||
import { IField, IGlobalVariable } from '@automatisch/types';
|
|
||||||
import { URLSearchParams } from 'url';
|
|
||||||
import authScope from '../common/auth-scope';
|
|
||||||
|
|
||||||
export default async function generateAuthUrl($: IGlobalVariable) {
|
|
||||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
|
||||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
|
||||||
);
|
|
||||||
const redirectUri = oauthRedirectUrlField.value as string;
|
|
||||||
const searchParams = new URLSearchParams({
|
|
||||||
client_id: $.auth.data.clientId as string,
|
|
||||||
redirect_uri: redirectUri,
|
|
||||||
prompt: 'select_account',
|
|
||||||
scope: authScope.join(' '),
|
|
||||||
response_type: 'code',
|
|
||||||
access_type: 'offline',
|
|
||||||
});
|
|
||||||
|
|
||||||
const url = `https://accounts.google.com/o/oauth2/v2/auth?${searchParams.toString()}`;
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
url,
|
|
||||||
});
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
import generateAuthUrl from './generate-auth-url';
|
|
||||||
import verifyCredentials from './verify-credentials';
|
|
||||||
import refreshToken from './refresh-token';
|
|
||||||
import isStillVerified from './is-still-verified';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'oAuthRedirectUrl',
|
|
||||||
label: 'OAuth Redirect URL',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: true,
|
|
||||||
value: '{WEB_APP_URL}/app/google-drive/connections/add',
|
|
||||||
placeholder: null,
|
|
||||||
description:
|
|
||||||
'When asked to input a redirect URL in Google Cloud, enter the URL above.',
|
|
||||||
clickToCopy: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'clientId',
|
|
||||||
label: 'Client ID',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: null,
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'clientSecret',
|
|
||||||
label: 'Client Secret',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: null,
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
generateAuthUrl,
|
|
||||||
verifyCredentials,
|
|
||||||
isStillVerified,
|
|
||||||
refreshToken,
|
|
||||||
};
|
|
@@ -1,9 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
import getCurrentUser from '../common/get-current-user';
|
|
||||||
|
|
||||||
const isStillVerified = async ($: IGlobalVariable) => {
|
|
||||||
const currentUser = await getCurrentUser($);
|
|
||||||
return !!currentUser.resourceName;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default isStillVerified;
|
|
@@ -1,26 +0,0 @@
|
|||||||
import { URLSearchParams } from 'node:url';
|
|
||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
import authScope from '../common/auth-scope';
|
|
||||||
|
|
||||||
const refreshToken = async ($: IGlobalVariable) => {
|
|
||||||
const params = new URLSearchParams({
|
|
||||||
client_id: $.auth.data.clientId as string,
|
|
||||||
client_secret: $.auth.data.clientSecret as string,
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
refresh_token: $.auth.data.refreshToken as string,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data } = await $.http.post(
|
|
||||||
'https://oauth2.googleapis.com/token',
|
|
||||||
params.toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accessToken: data.access_token,
|
|
||||||
expiresIn: data.expires_in,
|
|
||||||
scope: authScope.join(' '),
|
|
||||||
tokenType: data.token_type,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default refreshToken;
|
|
@@ -1,57 +0,0 @@
|
|||||||
import { IField, IGlobalVariable } from '@automatisch/types';
|
|
||||||
import getCurrentUser from '../common/get-current-user';
|
|
||||||
|
|
||||||
type TUser = {
|
|
||||||
displayName: string;
|
|
||||||
metadata: {
|
|
||||||
primary: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type TEmailAddress = {
|
|
||||||
value: string;
|
|
||||||
metadata: {
|
|
||||||
primary: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
|
||||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
|
||||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
|
||||||
);
|
|
||||||
const redirectUri = oauthRedirectUrlField.value as string;
|
|
||||||
const { data } = await $.http.post(`https://oauth2.googleapis.com/token`, {
|
|
||||||
client_id: $.auth.data.clientId,
|
|
||||||
client_secret: $.auth.data.clientSecret,
|
|
||||||
code: $.auth.data.code,
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
redirect_uri: redirectUri,
|
|
||||||
});
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accessToken: data.access_token,
|
|
||||||
tokenType: data.token_type,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUser = await getCurrentUser($);
|
|
||||||
|
|
||||||
const { displayName } = currentUser.names.find(
|
|
||||||
(name: TUser) => name.metadata.primary
|
|
||||||
);
|
|
||||||
const { value: email } = currentUser.emailAddresses.find(
|
|
||||||
(emailAddress: TEmailAddress) => emailAddress.metadata.primary
|
|
||||||
);
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
clientId: $.auth.data.clientId,
|
|
||||||
clientSecret: $.auth.data.clientSecret,
|
|
||||||
scope: $.auth.data.scope,
|
|
||||||
idToken: data.id_token,
|
|
||||||
expiresIn: data.expires_in,
|
|
||||||
refreshToken: data.refresh_token,
|
|
||||||
resourceName: currentUser.resourceName,
|
|
||||||
screenName: `${displayName} - ${email}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default verifyCredentials;
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { TBeforeRequest } from '@automatisch/types';
|
|
||||||
|
|
||||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
|
||||||
if ($.auth.data?.accessToken) {
|
|
||||||
requestConfig.headers.Authorization = `${$.auth.data.tokenType} ${$.auth.data.accessToken}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default addAuthHeader;
|
|
@@ -1,7 +0,0 @@
|
|||||||
const authScope: string[] = [
|
|
||||||
'https://www.googleapis.com/auth/drive',
|
|
||||||
'https://www.googleapis.com/auth/userinfo.email',
|
|
||||||
'https://www.googleapis.com/auth/userinfo.profile',
|
|
||||||
];
|
|
||||||
|
|
||||||
export default authScope;
|
|
@@ -1,10 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const getCurrentUser = async ($: IGlobalVariable) => {
|
|
||||||
const { data: currentUser } = await $.http.get(
|
|
||||||
'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses'
|
|
||||||
);
|
|
||||||
return currentUser;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getCurrentUser;
|
|
@@ -1,4 +0,0 @@
|
|||||||
import listFolders from './list-folders';
|
|
||||||
import listDrives from './list-drives';
|
|
||||||
|
|
||||||
export default [listFolders, listDrives];
|
|
@@ -1,35 +0,0 @@
|
|||||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'List drives',
|
|
||||||
key: 'listDrives',
|
|
||||||
|
|
||||||
async run($: IGlobalVariable) {
|
|
||||||
const drives: {
|
|
||||||
data: IJSONObject[];
|
|
||||||
} = {
|
|
||||||
data: [{ value: null, name: 'My Google Drive' }],
|
|
||||||
};
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
pageSize: 100,
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(`/v3/drives`, { params });
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.drives) {
|
|
||||||
for (const drive of data.drives) {
|
|
||||||
drives.data.push({
|
|
||||||
value: drive.id,
|
|
||||||
name: drive.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
|
|
||||||
return drives;
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,40 +0,0 @@
|
|||||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'List Folders',
|
|
||||||
key: 'listFolders',
|
|
||||||
|
|
||||||
async run($: IGlobalVariable) {
|
|
||||||
const folders: {
|
|
||||||
data: IJSONObject[];
|
|
||||||
} = {
|
|
||||||
data: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
q: `mimeType='application/vnd.google-apps.folder'`,
|
|
||||||
orderBy: 'createdTime desc',
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
pageSize: 1000,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(
|
|
||||||
`https://www.googleapis.com/drive/v3/files`,
|
|
||||||
{
|
|
||||||
params,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
for (const file of data.files) {
|
|
||||||
folders.data.push({
|
|
||||||
value: file.id,
|
|
||||||
name: file.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
|
|
||||||
return folders;
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,20 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
|
||||||
import addAuthHeader from './common/add-auth-header';
|
|
||||||
import auth from './auth';
|
|
||||||
import triggers from './triggers';
|
|
||||||
import dynamicData from './dynamic-data';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'Google Drive',
|
|
||||||
key: 'google-drive',
|
|
||||||
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',
|
|
||||||
primaryColor: '1FA463',
|
|
||||||
supportsConnections: true,
|
|
||||||
beforeRequest: [addAuthHeader],
|
|
||||||
auth,
|
|
||||||
triggers,
|
|
||||||
dynamicData,
|
|
||||||
});
|
|
@@ -1,6 +0,0 @@
|
|||||||
import newFiles from './new-files';
|
|
||||||
import newFilesInFolder from './new-files-in-folder';
|
|
||||||
import newFolders from './new-folders';
|
|
||||||
import updatedFiles from './updated-files';
|
|
||||||
|
|
||||||
export default [newFiles, newFilesInFolder, newFolders, updatedFiles];
|
|
@@ -1,54 +0,0 @@
|
|||||||
import defineTrigger from '../../../../helpers/define-trigger';
|
|
||||||
import newFilesInFolder from './new-files-in-folder';
|
|
||||||
|
|
||||||
export default defineTrigger({
|
|
||||||
name: 'New Files in Folder',
|
|
||||||
key: 'newFilesInFolder',
|
|
||||||
pollInterval: 15,
|
|
||||||
description:
|
|
||||||
'Triggers when a new file is added directly to a specific folder (but not its subfolder).',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Drive',
|
|
||||||
key: 'driveId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'The Google Drive where your file resides. If nothing is selected, then your personal Google Drive will be used.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listDrives',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Folder',
|
|
||||||
key: 'folderId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Check a specific folder for new files. Please note: new files added to subfolders inside the folder you choose here will NOT trigger this flow. Defaults to the top-level folder if none is picked.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listFolders',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
await newFilesInFolder($);
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,36 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const newFilesInFolder = async ($: IGlobalVariable) => {
|
|
||||||
let q = "mimeType!='application/vnd.google-apps.folder'";
|
|
||||||
if ($.step.parameters.folderId) {
|
|
||||||
q += ` and '${$.step.parameters.folderId}' in parents`;
|
|
||||||
} else {
|
|
||||||
q += ` and parents in 'root'`;
|
|
||||||
}
|
|
||||||
const params = {
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
orderBy: 'createdTime desc',
|
|
||||||
fields: '*',
|
|
||||||
pageSize: 1000,
|
|
||||||
q,
|
|
||||||
driveId: $.step.parameters.driveId,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(`/v3/files`, { params });
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.files?.length) {
|
|
||||||
for (const file of data.files) {
|
|
||||||
$.pushTriggerItem({
|
|
||||||
raw: file,
|
|
||||||
meta: {
|
|
||||||
internalId: file.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default newFilesInFolder;
|
|
@@ -1,34 +0,0 @@
|
|||||||
import defineTrigger from '../../../../helpers/define-trigger';
|
|
||||||
import newFiles from './new-files';
|
|
||||||
|
|
||||||
export default defineTrigger({
|
|
||||||
name: 'New Files',
|
|
||||||
key: 'newFiles',
|
|
||||||
pollInterval: 15,
|
|
||||||
description: 'Triggers when any new file is added (inside of any folder).',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Drive',
|
|
||||||
key: 'driveId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'The Google Drive where your file resides. If nothing is selected, then your personal Google Drive will be used.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listDrives',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
await newFiles($);
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,30 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const newFiles = async ($: IGlobalVariable) => {
|
|
||||||
const params = {
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
orderBy: 'createdTime desc',
|
|
||||||
fields: '*',
|
|
||||||
pageSize: 1000,
|
|
||||||
q: `mimeType!='application/vnd.google-apps.folder'`,
|
|
||||||
driveId: $.step.parameters.driveId,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get('/v3/files', { params });
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.files?.length) {
|
|
||||||
for (const file of data.files) {
|
|
||||||
$.pushTriggerItem({
|
|
||||||
raw: file,
|
|
||||||
meta: {
|
|
||||||
internalId: file.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default newFiles;
|
|
@@ -1,54 +0,0 @@
|
|||||||
import defineTrigger from '../../../../helpers/define-trigger';
|
|
||||||
import newFolders from './new-folders';
|
|
||||||
|
|
||||||
export default defineTrigger({
|
|
||||||
name: 'New Folders',
|
|
||||||
key: 'newFolders',
|
|
||||||
pollInterval: 15,
|
|
||||||
description:
|
|
||||||
'Triggers when a new folder is added directly to a specific folder (but not its subfolder).',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Drive',
|
|
||||||
key: 'driveId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'The Google Drive where your file resides. If nothing is selected, then your personal Google Drive will be used.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listDrives',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Folder',
|
|
||||||
key: 'folderId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Check a specific folder for new subfolders. Please note: new folders added to subfolders inside the folder you choose here will NOT trigger this flow. Defaults to the top-level folder if none is picked.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listFolders',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
await newFolders($);
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,37 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const newFolders = async ($: IGlobalVariable) => {
|
|
||||||
let q = "mimeType='application/vnd.google-apps.folder'";
|
|
||||||
if ($.step.parameters.folderId) {
|
|
||||||
q += ` and '${$.step.parameters.folderId}' in parents`;
|
|
||||||
} else {
|
|
||||||
q += ` and parents in 'root'`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
orderBy: 'createdTime desc',
|
|
||||||
fields: '*',
|
|
||||||
pageSize: 1000,
|
|
||||||
q,
|
|
||||||
driveId: $.step.parameters.driveId,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(`/v3/files`, { params });
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.files?.length) {
|
|
||||||
for (const file of data.files) {
|
|
||||||
$.pushTriggerItem({
|
|
||||||
raw: file,
|
|
||||||
meta: {
|
|
||||||
internalId: file.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default newFolders;
|
|
@@ -1,71 +0,0 @@
|
|||||||
import defineTrigger from '../../../../helpers/define-trigger';
|
|
||||||
import updatedFiles from './updated-files';
|
|
||||||
|
|
||||||
export default defineTrigger({
|
|
||||||
name: 'Updated Files',
|
|
||||||
key: 'updatedFiles',
|
|
||||||
pollInterval: 15,
|
|
||||||
description:
|
|
||||||
'Triggers when a file is updated in a specific folder (but not its subfolder).',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Drive',
|
|
||||||
key: 'driveId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'The Google Drive where your file resides. If nothing is selected, then your personal Google Drive will be used.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listDrives',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Folder',
|
|
||||||
key: 'folderId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description:
|
|
||||||
'Check a specific folder for updated files. Please note: files located in subfolders of the folder you choose here will NOT trigger this flow. Defaults to the top-level folder if none is picked.',
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listFolders',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Include Deleted',
|
|
||||||
key: 'includeDeleted',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: true,
|
|
||||||
value: true,
|
|
||||||
description: 'Should this trigger also on files that are deleted?',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: 'Yes',
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'No',
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
await updatedFiles($);
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,41 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const updatedFiles = async ($: IGlobalVariable) => {
|
|
||||||
let q = `mimeType!='application/vnd.google-apps.folder'`;
|
|
||||||
if ($.step.parameters.includeDeleted === false) {
|
|
||||||
q += ` and trashed=${$.step.parameters.includeDeleted}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($.step.parameters.folderId) {
|
|
||||||
q += ` and '${$.step.parameters.folderId}' in parents`;
|
|
||||||
} else {
|
|
||||||
q += ` and parents in 'root'`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
orderBy: 'modifiedTime desc',
|
|
||||||
fields: '*',
|
|
||||||
pageSize: 1000,
|
|
||||||
q,
|
|
||||||
driveId: $.step.parameters.driveId,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(`/v3/files`, { params });
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.files?.length) {
|
|
||||||
for (const file of data.files) {
|
|
||||||
$.pushTriggerItem({
|
|
||||||
raw: file,
|
|
||||||
meta: {
|
|
||||||
internalId: `${file.id}-${file.modifiedTime}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default updatedFiles;
|
|
@@ -1,89 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg width="49px" height="67px" viewBox="0 0 49 67" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
|
|
||||||
<title>Sheets-icon</title>
|
|
||||||
<desc>Created with Sketch.</desc>
|
|
||||||
<defs>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-1"></path>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-3"></path>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-5"></path>
|
|
||||||
<linearGradient x1="50.0053945%" y1="8.58610612%" x2="50.0053945%" y2="100.013939%" id="linearGradient-7">
|
|
||||||
<stop stop-color="#263238" stop-opacity="0.2" offset="0%"></stop>
|
|
||||||
<stop stop-color="#263238" stop-opacity="0.02" offset="100%"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-8"></path>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-10"></path>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-12"></path>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="path-14"></path>
|
|
||||||
<radialGradient cx="3.16804688%" cy="2.71744318%" fx="3.16804688%" fy="2.71744318%" r="161.248516%" gradientTransform="translate(0.031680,0.027174),scale(1.000000,0.727273),translate(-0.031680,-0.027174)" id="radialGradient-16">
|
|
||||||
<stop stop-color="#FFFFFF" stop-opacity="0.1" offset="0%"></stop>
|
|
||||||
<stop stop-color="#FFFFFF" stop-opacity="0" offset="100%"></stop>
|
|
||||||
</radialGradient>
|
|
||||||
</defs>
|
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
||||||
<g id="Consumer-Apps-Sheets-Large-VD-R8-" transform="translate(-451.000000, -451.000000)">
|
|
||||||
<g id="Hero" transform="translate(0.000000, 63.000000)">
|
|
||||||
<g id="Personal" transform="translate(277.000000, 299.000000)">
|
|
||||||
<g id="Sheets-icon" transform="translate(174.833333, 89.958333)">
|
|
||||||
<g id="Group">
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-2" fill="white">
|
|
||||||
<use xlink:href="#path-1"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L36.9791667,10.3541667 L29.5833333,0 Z" id="Path" fill="#0F9D58" fill-rule="nonzero" mask="url(#mask-2)"></path>
|
|
||||||
</g>
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-4" fill="white">
|
|
||||||
<use xlink:href="#path-3"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<path d="M11.8333333,31.8020833 L11.8333333,53.25 L35.5,53.25 L35.5,31.8020833 L11.8333333,31.8020833 Z M22.1875,50.2916667 L14.7916667,50.2916667 L14.7916667,46.59375 L22.1875,46.59375 L22.1875,50.2916667 Z M22.1875,44.375 L14.7916667,44.375 L14.7916667,40.6770833 L22.1875,40.6770833 L22.1875,44.375 Z M22.1875,38.4583333 L14.7916667,38.4583333 L14.7916667,34.7604167 L22.1875,34.7604167 L22.1875,38.4583333 Z M32.5416667,50.2916667 L25.1458333,50.2916667 L25.1458333,46.59375 L32.5416667,46.59375 L32.5416667,50.2916667 Z M32.5416667,44.375 L25.1458333,44.375 L25.1458333,40.6770833 L32.5416667,40.6770833 L32.5416667,44.375 Z M32.5416667,38.4583333 L25.1458333,38.4583333 L25.1458333,34.7604167 L32.5416667,34.7604167 L32.5416667,38.4583333 Z" id="Shape" fill="#F1F1F1" fill-rule="nonzero" mask="url(#mask-4)"></path>
|
|
||||||
</g>
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-6" fill="white">
|
|
||||||
<use xlink:href="#path-5"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<polygon id="Path" fill="url(#linearGradient-7)" fill-rule="nonzero" mask="url(#mask-6)" points="30.8813021 16.4520313 47.3333333 32.9003646 47.3333333 17.75"></polygon>
|
|
||||||
</g>
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-9" fill="white">
|
|
||||||
<use xlink:href="#path-8"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<g id="Group" mask="url(#mask-9)">
|
|
||||||
<g transform="translate(26.625000, -2.958333)">
|
|
||||||
<path d="M2.95833333,2.95833333 L2.95833333,16.2708333 C2.95833333,18.7225521 4.94411458,20.7083333 7.39583333,20.7083333 L20.7083333,20.7083333 L2.95833333,2.95833333 Z" id="Path" fill="#87CEAC" fill-rule="nonzero"></path>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-11" fill="white">
|
|
||||||
<use xlink:href="#path-10"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<path d="M4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,4.80729167 C0,2.36666667 1.996875,0.369791667 4.4375,0.369791667 L29.5833333,0.369791667 L29.5833333,0 L4.4375,0 Z" id="Path" fill-opacity="0.2" fill="#FFFFFF" fill-rule="nonzero" mask="url(#mask-11)"></path>
|
|
||||||
</g>
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-13" fill="white">
|
|
||||||
<use xlink:href="#path-12"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<path d="M42.8958333,64.7135417 L4.4375,64.7135417 C1.996875,64.7135417 0,62.7166667 0,60.2760417 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,60.2760417 C47.3333333,62.7166667 45.3364583,64.7135417 42.8958333,64.7135417 Z" id="Path" fill-opacity="0.2" fill="#263238" fill-rule="nonzero" mask="url(#mask-13)"></path>
|
|
||||||
</g>
|
|
||||||
<g id="Clipped">
|
|
||||||
<mask id="mask-15" fill="white">
|
|
||||||
<use xlink:href="#path-14"></use>
|
|
||||||
</mask>
|
|
||||||
<g id="SVGID_1_"></g>
|
|
||||||
<path d="M34.0208333,17.75 C31.5691146,17.75 29.5833333,15.7642188 29.5833333,13.3125 L29.5833333,13.6822917 C29.5833333,16.1340104 31.5691146,18.1197917 34.0208333,18.1197917 L47.3333333,18.1197917 L47.3333333,17.75 L34.0208333,17.75 Z" id="Path" fill-opacity="0.1" fill="#263238" fill-rule="nonzero" mask="url(#mask-15)"></path>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path d="M29.5833333,0 L4.4375,0 C1.996875,0 0,1.996875 0,4.4375 L0,60.6458333 C0,63.0864583 1.996875,65.0833333 4.4375,65.0833333 L42.8958333,65.0833333 C45.3364583,65.0833333 47.3333333,63.0864583 47.3333333,60.6458333 L47.3333333,17.75 L29.5833333,0 Z" id="Path" fill="url(#radialGradient-16)" fill-rule="nonzero"></path>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 9.0 KiB |
@@ -1,24 +0,0 @@
|
|||||||
import { IField, IGlobalVariable } from '@automatisch/types';
|
|
||||||
import { URLSearchParams } from 'url';
|
|
||||||
import authScope from '../common/auth-scope';
|
|
||||||
|
|
||||||
export default async function generateAuthUrl($: IGlobalVariable) {
|
|
||||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
|
||||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
|
||||||
);
|
|
||||||
const redirectUri = oauthRedirectUrlField.value as string;
|
|
||||||
const searchParams = new URLSearchParams({
|
|
||||||
client_id: $.auth.data.clientId as string,
|
|
||||||
redirect_uri: redirectUri,
|
|
||||||
prompt: 'select_account',
|
|
||||||
scope: authScope.join(' '),
|
|
||||||
response_type: 'code',
|
|
||||||
access_type: 'offline',
|
|
||||||
});
|
|
||||||
|
|
||||||
const url = `https://accounts.google.com/o/oauth2/v2/auth?${searchParams.toString()}`;
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
url,
|
|
||||||
});
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
import generateAuthUrl from './generate-auth-url';
|
|
||||||
import verifyCredentials from './verify-credentials';
|
|
||||||
import refreshToken from './refresh-token';
|
|
||||||
import isStillVerified from './is-still-verified';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'oAuthRedirectUrl',
|
|
||||||
label: 'OAuth Redirect URL',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: true,
|
|
||||||
value: '{WEB_APP_URL}/app/google-sheets/connections/add',
|
|
||||||
placeholder: null,
|
|
||||||
description:
|
|
||||||
'When asked to input a redirect URL in Google Cloud, enter the URL above.',
|
|
||||||
clickToCopy: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'clientId',
|
|
||||||
label: 'Client ID',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: null,
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'clientSecret',
|
|
||||||
label: 'Client Secret',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: null,
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
generateAuthUrl,
|
|
||||||
verifyCredentials,
|
|
||||||
isStillVerified,
|
|
||||||
refreshToken,
|
|
||||||
};
|
|
@@ -1,9 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
import getCurrentUser from '../common/get-current-user';
|
|
||||||
|
|
||||||
const isStillVerified = async ($: IGlobalVariable) => {
|
|
||||||
const currentUser = await getCurrentUser($);
|
|
||||||
return !!currentUser.resourceName;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default isStillVerified;
|
|
@@ -1,26 +0,0 @@
|
|||||||
import { URLSearchParams } from 'node:url';
|
|
||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
import authScope from '../common/auth-scope';
|
|
||||||
|
|
||||||
const refreshToken = async ($: IGlobalVariable) => {
|
|
||||||
const params = new URLSearchParams({
|
|
||||||
client_id: $.auth.data.clientId as string,
|
|
||||||
client_secret: $.auth.data.clientSecret as string,
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
refresh_token: $.auth.data.refreshToken as string,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data } = await $.http.post(
|
|
||||||
'https://oauth2.googleapis.com/token',
|
|
||||||
params.toString()
|
|
||||||
);
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accessToken: data.access_token,
|
|
||||||
expiresIn: data.expires_in,
|
|
||||||
scope: authScope.join(' '),
|
|
||||||
tokenType: data.token_type,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default refreshToken;
|
|
@@ -1,57 +0,0 @@
|
|||||||
import { IField, IGlobalVariable } from '@automatisch/types';
|
|
||||||
import getCurrentUser from '../common/get-current-user';
|
|
||||||
|
|
||||||
type TUser = {
|
|
||||||
displayName: string;
|
|
||||||
metadata: {
|
|
||||||
primary: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type TEmailAddress = {
|
|
||||||
value: string;
|
|
||||||
metadata: {
|
|
||||||
primary: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
|
||||||
const oauthRedirectUrlField = $.app.auth.fields.find(
|
|
||||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
|
||||||
);
|
|
||||||
const redirectUri = oauthRedirectUrlField.value as string;
|
|
||||||
const { data } = await $.http.post(`https://oauth2.googleapis.com/token`, {
|
|
||||||
client_id: $.auth.data.clientId,
|
|
||||||
client_secret: $.auth.data.clientSecret,
|
|
||||||
code: $.auth.data.code,
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
redirect_uri: redirectUri,
|
|
||||||
});
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
accessToken: data.access_token,
|
|
||||||
tokenType: data.token_type,
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUser = await getCurrentUser($);
|
|
||||||
|
|
||||||
const { displayName } = currentUser.names.find(
|
|
||||||
(name: TUser) => name.metadata.primary
|
|
||||||
);
|
|
||||||
const { value: email } = currentUser.emailAddresses.find(
|
|
||||||
(emailAddress: TEmailAddress) => emailAddress.metadata.primary
|
|
||||||
);
|
|
||||||
|
|
||||||
await $.auth.set({
|
|
||||||
clientId: $.auth.data.clientId,
|
|
||||||
clientSecret: $.auth.data.clientSecret,
|
|
||||||
scope: $.auth.data.scope,
|
|
||||||
idToken: data.id_token,
|
|
||||||
expiresIn: data.expires_in,
|
|
||||||
refreshToken: data.refresh_token,
|
|
||||||
resourceName: currentUser.resourceName,
|
|
||||||
screenName: `${displayName} - ${email}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default verifyCredentials;
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { TBeforeRequest } from '@automatisch/types';
|
|
||||||
|
|
||||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
|
||||||
if ($.auth.data?.accessToken) {
|
|
||||||
requestConfig.headers.Authorization = `${$.auth.data.tokenType} ${$.auth.data.accessToken}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default addAuthHeader;
|
|
@@ -1,8 +0,0 @@
|
|||||||
const authScope: string[] = [
|
|
||||||
'https://www.googleapis.com/auth/drive',
|
|
||||||
'https://www.googleapis.com/auth/spreadsheets',
|
|
||||||
'https://www.googleapis.com/auth/userinfo.email',
|
|
||||||
'https://www.googleapis.com/auth/userinfo.profile',
|
|
||||||
];
|
|
||||||
|
|
||||||
export default authScope;
|
|
@@ -1,10 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const getCurrentUser = async ($: IGlobalVariable) => {
|
|
||||||
const { data: currentUser } = await $.http.get(
|
|
||||||
'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses'
|
|
||||||
);
|
|
||||||
return currentUser;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getCurrentUser;
|
|
@@ -1,3 +0,0 @@
|
|||||||
import listDrives from './list-drives';
|
|
||||||
|
|
||||||
export default [listDrives];
|
|
@@ -1,38 +0,0 @@
|
|||||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'List drives',
|
|
||||||
key: 'listDrives',
|
|
||||||
|
|
||||||
async run($: IGlobalVariable) {
|
|
||||||
const drives: {
|
|
||||||
data: IJSONObject[];
|
|
||||||
} = {
|
|
||||||
data: [{ value: null, name: 'My Google Drive' }],
|
|
||||||
};
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
pageSize: 100,
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(
|
|
||||||
`https://www.googleapis.com/drive/v3/drives`,
|
|
||||||
{ params }
|
|
||||||
);
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.drives) {
|
|
||||||
for (const drive of data.drives) {
|
|
||||||
drives.data.push({
|
|
||||||
value: drive.id,
|
|
||||||
name: drive.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
|
|
||||||
return drives;
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,20 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
|
||||||
import addAuthHeader from './common/add-auth-header';
|
|
||||||
import auth from './auth';
|
|
||||||
import triggers from './triggers';
|
|
||||||
import dynamicData from './dynamic-data';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'Google Sheets',
|
|
||||||
key: 'google-sheets',
|
|
||||||
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',
|
|
||||||
primaryColor: '0F9D58',
|
|
||||||
supportsConnections: true,
|
|
||||||
beforeRequest: [addAuthHeader],
|
|
||||||
auth,
|
|
||||||
triggers,
|
|
||||||
dynamicData,
|
|
||||||
});
|
|
@@ -1,3 +0,0 @@
|
|||||||
import newSpreadsheets from './new-spreadsheets';
|
|
||||||
|
|
||||||
export default [newSpreadsheets];
|
|
@@ -1,33 +0,0 @@
|
|||||||
import defineTrigger from '../../../../helpers/define-trigger';
|
|
||||||
import newSpreadsheets from './new-spreadsheets'
|
|
||||||
|
|
||||||
export default defineTrigger({
|
|
||||||
name: 'New Spreadsheets',
|
|
||||||
key: 'newSpreadsheets',
|
|
||||||
pollInterval: 15,
|
|
||||||
description: 'Triggers when you create a new spreadsheet.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Drive',
|
|
||||||
key: 'driveId',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: false,
|
|
||||||
description: 'The Google Drive where your spreadsheet resides. If nothing is selected, then your personal Google Drive will be used.',
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listDrives',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
await newSpreadsheets($);
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,33 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const newSpreadsheets = async ($: IGlobalVariable) => {
|
|
||||||
const params = {
|
|
||||||
pageToken: undefined as unknown as string,
|
|
||||||
orderBy: 'createdTime desc',
|
|
||||||
q: `mimeType='application/vnd.google-apps.spreadsheet'`,
|
|
||||||
fields: '*',
|
|
||||||
pageSize: 1000,
|
|
||||||
driveId: $.step.parameters.driveId,
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
const { data } = await $.http.get(
|
|
||||||
'https://www.googleapis.com/drive/v3/files',
|
|
||||||
{ params }
|
|
||||||
);
|
|
||||||
params.pageToken = data.nextPageToken;
|
|
||||||
|
|
||||||
if (data.files?.length) {
|
|
||||||
for (const file of data.files) {
|
|
||||||
$.pushTriggerItem({
|
|
||||||
raw: file,
|
|
||||||
meta: {
|
|
||||||
internalId: file.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (params.pageToken);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default newSpreadsheets;
|
|
@@ -1,111 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
type TMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
||||||
|
|
||||||
type THeaderEntry = {
|
|
||||||
key: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type THeaderEntries = THeaderEntry[];
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Custom Request',
|
|
||||||
key: 'customRequest',
|
|
||||||
description: 'Makes a custom HTTP request by providing raw details.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Method',
|
|
||||||
key: 'method',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: true,
|
|
||||||
description: `The HTTP method we'll use to perform the request.`,
|
|
||||||
value: 'GET',
|
|
||||||
options: [
|
|
||||||
{ label: 'DELETE', value: 'DELETE' },
|
|
||||||
{ label: 'GET', value: 'GET' },
|
|
||||||
{ label: 'PATCH', value: 'PATCH' },
|
|
||||||
{ label: 'POST', value: 'POST' },
|
|
||||||
{ label: 'PUT', value: 'PUT' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'URL',
|
|
||||||
key: 'url',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'Any URL with a querystring will be re-encoded properly.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Data',
|
|
||||||
key: 'data',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
description: 'Place raw JSON data here.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Headers',
|
|
||||||
key: 'headers',
|
|
||||||
type: 'dynamic' as const,
|
|
||||||
required: false,
|
|
||||||
description: 'Add or remove headers as needed',
|
|
||||||
value: [{
|
|
||||||
key: 'Content-Type',
|
|
||||||
value: 'application/json'
|
|
||||||
}],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
label: 'Key',
|
|
||||||
key: 'key',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'Header key',
|
|
||||||
variables: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Value',
|
|
||||||
key: 'value',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'Header value',
|
|
||||||
variables: true,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const method = $.step.parameters.method as TMethod;
|
|
||||||
const data = $.step.parameters.data as string;
|
|
||||||
const url = $.step.parameters.url as string;
|
|
||||||
const headers = $.step.parameters.headers as THeaderEntries;
|
|
||||||
const maxFileSize = 25 * 1024 * 1024; // 25MB
|
|
||||||
|
|
||||||
const headersObject = headers.reduce((result, entry) => ({ ...result, [entry.key]: entry.value }), {})
|
|
||||||
|
|
||||||
const metadataResponse = await $.http.head(url, { headers: headersObject });
|
|
||||||
|
|
||||||
if (Number(metadataResponse.headers['content-length']) > maxFileSize) {
|
|
||||||
throw new Error(
|
|
||||||
`Response is too large. Maximum size is 25MB. Actual size is ${metadataResponse.headers['content-length']}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await $.http.request({
|
|
||||||
url,
|
|
||||||
method,
|
|
||||||
data,
|
|
||||||
headers: headersObject,
|
|
||||||
});
|
|
||||||
|
|
||||||
let responseData = response.data;
|
|
||||||
|
|
||||||
if (typeof response.data === 'string') {
|
|
||||||
responseData = response.data.replaceAll('\u0000', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
$.setActionItem({ raw: { data: responseData } });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,3 +0,0 @@
|
|||||||
import customRequest from './custom-request';
|
|
||||||
|
|
||||||
export default [customRequest];
|
|
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="100px" height="100px"><path d="M 37.09375 0.09375 C 36.316406 0.167969 35.652344 0.691406 35.398438 1.429688 C 35.140625 2.171875 35.339844 2.992188 35.90625 3.53125 L 42.375 10 L 2 10 C 1.9375 9.996094 1.875 9.996094 1.8125 10 C 0.707031 10.050781 -0.144531 10.988281 -0.09375 12.09375 C -0.0429688 13.199219 0.894531 14.050781 2 14 L 42.375 14 L 35.90625 20.46875 C 35.382813 20.96875 35.167969 21.710938 35.347656 22.414063 C 35.527344 23.113281 36.070313 23.664063 36.769531 23.851563 C 37.46875 24.039063 38.214844 23.832031 38.71875 23.3125 L 50.03125 12 L 38.71875 0.6875 C 38.296875 0.253906 37.699219 0.0351563 37.09375 0.09375 Z M 12.5 26.09375 C 12.046875 26.152344 11.628906 26.359375 11.3125 26.6875 L 0 38 L 11.3125 49.3125 C 11.816406 49.832031 12.5625 50.039063 13.261719 49.851563 C 13.960938 49.664063 14.503906 49.113281 14.683594 48.414063 C 14.863281 47.710938 14.648438 46.96875 14.125 46.46875 L 7.65625 40 L 48 40 C 48.722656 40.011719 49.390625 39.632813 49.753906 39.007813 C 50.121094 38.386719 50.121094 37.613281 49.753906 36.992188 C 49.390625 36.367188 48.722656 35.988281 48 36 L 7.65625 36 L 14.125 29.53125 C 14.753906 28.9375 14.929688 28.003906 14.558594 27.222656 C 14.1875 26.441406 13.359375 25.984375 12.5 26.09375 Z"/></svg>
|
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,14 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
|
||||||
import actions from './actions';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'HTTP Request',
|
|
||||||
key: 'http-request',
|
|
||||||
iconUrl: '{BASE_URL}/apps/http-request/assets/favicon.svg',
|
|
||||||
authDocUrl: 'https://automatisch.io/docs/apps/http-request/connection',
|
|
||||||
supportsConnections: false,
|
|
||||||
baseUrl: '',
|
|
||||||
apiBaseUrl: '',
|
|
||||||
primaryColor: '000000',
|
|
||||||
actions,
|
|
||||||
});
|
|
@@ -1,8 +1,8 @@
|
|||||||
import { TBeforeRequest } from '@automatisch/types';
|
import { TBeforeRequest } from '@automatisch/types';
|
||||||
|
|
||||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
||||||
if ($.auth.data.serverUrl) {
|
if ($.auth.data.apiBaseUrl) {
|
||||||
requestConfig.baseURL = $.auth.data.serverUrl as string;
|
requestConfig.baseURL = $.auth.data.apiBaseUrl as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($.auth.data?.username && $.auth.data?.password) {
|
if ($.auth.data?.username && $.auth.data?.password) {
|
||||||
|
@@ -1,29 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Check moderation',
|
|
||||||
key: 'checkModeration',
|
|
||||||
description: 'Checks for hate, hate/threatening, self-harm, sexual, sexual/minors, violence, or violence/graphic content in the given text.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Input',
|
|
||||||
key: 'input',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
description: 'The text to analyze.'
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const { data } = await $.http.post('/v1/moderations', {
|
|
||||||
input: $.step.parameters.input as string,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = data?.results[0];
|
|
||||||
|
|
||||||
$.setActionItem({
|
|
||||||
raw: result,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,4 +0,0 @@
|
|||||||
import checkModeration from './check-moderation';
|
|
||||||
import sendPrompt from './send-prompt';
|
|
||||||
|
|
||||||
export default [checkModeration, sendPrompt];
|
|
@@ -1,104 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
const castFloatOrUndefined = (value: string | null) => {
|
|
||||||
return value === '' ? undefined : parseFloat(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Send prompt',
|
|
||||||
key: 'sendPrompt',
|
|
||||||
description: 'Creates a completion for the provided prompt and parameters.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Model',
|
|
||||||
key: 'model',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: true,
|
|
||||||
variables: false,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listModels',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Prompt',
|
|
||||||
key: 'prompt',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
description: 'The text to analyze.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Temperature',
|
|
||||||
key: 'temperature',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
description: 'What sampling temperature to use. Higher values mean the model will take more risk. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer. We generally recommend altering this or Top P but not both.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Maximum tokens',
|
|
||||||
key: 'maxTokens',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
description: 'The maximum number of tokens to generate in the completion.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Stop Sequence',
|
|
||||||
key: 'stopSequence',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
description: 'Single stop sequence where the API will stop generating further tokens. The returned text will not contain the stop sequence.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Top P',
|
|
||||||
key: 'topP',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
description: 'An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with Top P probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Frequency Penalty',
|
|
||||||
key: 'frequencyPenalty',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'presencePenalty',
|
|
||||||
key: 'presencePenalty',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: false,
|
|
||||||
variables: true,
|
|
||||||
description: `Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.`
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const payload = {
|
|
||||||
model: $.step.parameters.model as string,
|
|
||||||
prompt: $.step.parameters.prompt as string,
|
|
||||||
temperature: castFloatOrUndefined($.step.parameters.temperature as string),
|
|
||||||
max_tokens: castFloatOrUndefined($.step.parameters.maxTokens as string),
|
|
||||||
stop: ($.step.parameters.stopSequence as string || null),
|
|
||||||
top_p: castFloatOrUndefined($.step.parameters.topP as string),
|
|
||||||
frequency_penalty: castFloatOrUndefined($.step.parameters.frequencyPenalty as string),
|
|
||||||
presence_penalty: castFloatOrUndefined($.step.parameters.presencePenalty as string),
|
|
||||||
};
|
|
||||||
const { data } = await $.http.post('/v1/completions', payload);
|
|
||||||
|
|
||||||
$.setActionItem({
|
|
||||||
raw: data,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,6 +0,0 @@
|
|||||||
<svg width="256px" height="260px" viewBox="0 0 256 260" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
|
||||||
<title>OpenAI</title>
|
|
||||||
<g>
|
|
||||||
<path d="M239.183914,106.202783 C245.054304,88.5242096 243.02228,69.1733805 233.607599,53.0998864 C219.451678,28.4588021 190.999703,15.7836129 163.213007,21.739505 C147.554077,4.32145883 123.794909,-3.42398554 100.87901,1.41873898 C77.9631105,6.26146349 59.3690093,22.9572536 52.0959621,45.2214219 C33.8436494,48.9644867 18.0901721,60.392749 8.86672513,76.5818033 C-5.443491,101.182962 -2.19544431,132.215255 16.8986662,153.320094 C11.0060865,170.990656 13.0197283,190.343991 22.4238231,206.422991 C36.5975553,231.072344 65.0680342,243.746566 92.8695738,237.783372 C105.235639,251.708249 123.001113,259.630942 141.623968,259.52692 C170.105359,259.552169 195.337611,241.165718 204.037777,214.045661 C222.28734,210.296356 238.038489,198.869783 247.267014,182.68528 C261.404453,158.127515 258.142494,127.262775 239.183914,106.202783 L239.183914,106.202783 Z M141.623968,242.541207 C130.255682,242.559177 119.243876,238.574642 110.519381,231.286197 L112.054146,230.416496 L163.724595,200.590881 C166.340648,199.056444 167.954321,196.256818 167.970781,193.224005 L167.970781,120.373788 L189.815614,133.010026 C190.034132,133.121423 190.186235,133.330564 190.224885,133.572774 L190.224885,193.940229 C190.168603,220.758427 168.442166,242.484864 141.623968,242.541207 Z M37.1575749,197.93062 C31.456498,188.086359 29.4094818,176.546984 31.3766237,165.342426 L32.9113895,166.263285 L84.6329973,196.088901 C87.2389349,197.618207 90.4682717,197.618207 93.0742093,196.088901 L156.255402,159.663793 L156.255402,184.885111 C156.243557,185.149771 156.111725,185.394602 155.89729,185.550176 L103.561776,215.733903 C80.3054953,229.131632 50.5924954,221.165435 37.1575749,197.93062 Z M23.5493181,85.3811273 C29.2899861,75.4733097 38.3511911,67.9162648 49.1287482,64.0478825 L49.1287482,125.438515 C49.0891492,128.459425 50.6965386,131.262556 53.3237748,132.754232 L116.198014,169.025864 L94.3531808,181.662102 C94.1132325,181.789434 93.8257461,181.789434 93.5857979,181.662102 L41.3526015,151.529534 C18.1419426,138.076098 10.1817681,108.385562 23.5493181,85.125333 L23.5493181,85.3811273 Z M203.0146,127.075598 L139.935725,90.4458545 L161.7294,77.8607748 C161.969348,77.7334434 162.256834,77.7334434 162.496783,77.8607748 L214.729979,108.044502 C231.032329,117.451747 240.437294,135.426109 238.871504,154.182739 C237.305714,172.939368 225.050719,189.105572 207.414262,195.67963 L207.414262,134.288998 C207.322521,131.276867 205.650697,128.535853 203.0146,127.075598 Z M224.757116,94.3850867 L223.22235,93.4642272 L171.60306,63.3828173 C168.981293,61.8443751 165.732456,61.8443751 163.110689,63.3828173 L99.9806554,99.8079259 L99.9806554,74.5866077 C99.9533004,74.3254088 100.071095,74.0701869 100.287609,73.9215426 L152.520805,43.7889738 C168.863098,34.3743518 189.174256,35.2529043 204.642579,46.0434841 C220.110903,56.8340638 227.949269,75.5923959 224.757116,94.1804513 L224.757116,94.3850867 Z M88.0606409,139.097931 L66.2158076,126.512851 C65.9950399,126.379091 65.8450965,126.154176 65.8065367,125.898945 L65.8065367,65.684966 C65.8314495,46.8285367 76.7500605,29.6846032 93.8270852,21.6883055 C110.90411,13.6920079 131.063833,16.2835462 145.5632,28.338998 L144.028434,29.2086986 L92.3579852,59.0343142 C89.7419327,60.5687513 88.1282597,63.3683767 88.1117998,66.4011901 L88.0606409,139.097931 Z M99.9294965,113.5185 L128.06687,97.3011417 L156.255402,113.5185 L156.255402,145.953218 L128.169187,162.170577 L99.9806554,145.953218 L99.9294965,113.5185 Z" fill="#000000"></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,34 +0,0 @@
|
|||||||
import verifyCredentials from './verify-credentials';
|
|
||||||
import isStillVerified from './is-still-verified';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
key: 'screenName',
|
|
||||||
label: 'Screen Name',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description:
|
|
||||||
'Screen name of your connection to be used on Automatisch UI.',
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'apiKey',
|
|
||||||
label: 'API Key',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
readOnly: false,
|
|
||||||
value: null,
|
|
||||||
placeholder: null,
|
|
||||||
description: 'OpenAI API key of your account.',
|
|
||||||
docUrl: 'https://automatisch.io/docs/openai#api-key',
|
|
||||||
clickToCopy: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
verifyCredentials,
|
|
||||||
isStillVerified,
|
|
||||||
};
|
|
@@ -1,8 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const isStillVerified = async ($: IGlobalVariable) => {
|
|
||||||
await $.http.get('/v1/models');
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default isStillVerified;
|
|
@@ -1,7 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
|
||||||
await $.http.get('/v1/models');
|
|
||||||
};
|
|
||||||
|
|
||||||
export default verifyCredentials;
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { TBeforeRequest } from '@automatisch/types';
|
|
||||||
|
|
||||||
const addAuthHeader: TBeforeRequest = ($, requestConfig) => {
|
|
||||||
if ($.auth.data?.apiKey) {
|
|
||||||
requestConfig.headers.Authorization = `Bearer ${$.auth.data.apiKey}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default addAuthHeader;
|
|
@@ -1,3 +0,0 @@
|
|||||||
import listModels from './list-models';
|
|
||||||
|
|
||||||
export default [listModels];
|
|
@@ -1,19 +0,0 @@
|
|||||||
import { IGlobalVariable } from '@automatisch/types';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'List models',
|
|
||||||
key: 'listModels',
|
|
||||||
|
|
||||||
async run($: IGlobalVariable) {
|
|
||||||
const response = await $.http.get('/v1/models');
|
|
||||||
|
|
||||||
const models = response.data.data.map((model: { id: string }) => {
|
|
||||||
return {
|
|
||||||
value: model.id,
|
|
||||||
name: model.id,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return { data: models };
|
|
||||||
},
|
|
||||||
};
|
|
@@ -1,20 +0,0 @@
|
|||||||
import defineApp from '../../helpers/define-app';
|
|
||||||
import addAuthHeader from './common/add-auth-header';
|
|
||||||
import auth from './auth';
|
|
||||||
import actions from './actions';
|
|
||||||
import dynamicData from './dynamic-data';
|
|
||||||
|
|
||||||
export default defineApp({
|
|
||||||
name: 'OpenAI',
|
|
||||||
key: 'openai',
|
|
||||||
baseUrl: 'https://openai.com',
|
|
||||||
apiBaseUrl: 'https://api.openai.com',
|
|
||||||
iconUrl: '{BASE_URL}/apps/openai/assets/favicon.svg',
|
|
||||||
authDocUrl: 'https://automatisch.io/docs/apps/openai/connection',
|
|
||||||
primaryColor: '000000',
|
|
||||||
supportsConnections: true,
|
|
||||||
beforeRequest: [addAuthHeader],
|
|
||||||
auth,
|
|
||||||
actions,
|
|
||||||
dynamicData,
|
|
||||||
});
|
|
@@ -1,52 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Create attachment',
|
|
||||||
key: 'createAttachment',
|
|
||||||
description:
|
|
||||||
'Creates an attachment of a specified object by given parent ID.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Parent ID',
|
|
||||||
key: 'parentId',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
description:
|
|
||||||
'ID of the parent object of the attachment. The following objects are supported as parents of attachments: Account, Asset, Campaign, Case, Contact, Contract, Custom objects, EmailMessage, EmailTemplate, Event, Lead, Opportunity, Product2, Solution, Task',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Name',
|
|
||||||
key: 'name',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
description: 'Name of the attached file. Maximum size is 255 characters.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Body',
|
|
||||||
key: 'body',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
description: 'File data. (Max size is 25MB)',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const { parentId, name, body } = $.step.parameters;
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
ParentId: parentId,
|
|
||||||
Name: name,
|
|
||||||
Body: body,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { data } = await $.http.post(
|
|
||||||
'/services/data/v56.0/sobjects/Attachment/',
|
|
||||||
options
|
|
||||||
);
|
|
||||||
|
|
||||||
$.setActionItem({ raw: data });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,79 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Find record',
|
|
||||||
key: 'findRecord',
|
|
||||||
description: 'Finds a record of a specified object by a field and value.',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'Object',
|
|
||||||
key: 'object',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'Pick which type of object you want to search for.',
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listObjects',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Field',
|
|
||||||
key: 'field',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
description: 'Pick which field to search by',
|
|
||||||
required: true,
|
|
||||||
variables: false,
|
|
||||||
dependsOn: ['parameters.object'],
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listFields',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'parameters.object',
|
|
||||||
value: '{parameters.object}',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Search value',
|
|
||||||
key: 'searchValue',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const query = `
|
|
||||||
SELECT
|
|
||||||
FIELDS(ALL)
|
|
||||||
FROM
|
|
||||||
${$.step.parameters.object}
|
|
||||||
WHERE
|
|
||||||
${$.step.parameters.field} = '${$.step.parameters.searchValue}'
|
|
||||||
LIMIT 1
|
|
||||||
`;
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
params: {
|
|
||||||
q: query,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const { data } = await $.http.get('/services/data/v56.0/query', options);
|
|
||||||
const record = data.records[0];
|
|
||||||
|
|
||||||
$.setActionItem({ raw: record });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,4 +0,0 @@
|
|||||||
import findRecord from './find-record';
|
|
||||||
import createAttachment from './create-attachment';
|
|
||||||
|
|
||||||
export default [findRecord, createAttachment];
|
|
@@ -2,7 +2,6 @@ import defineApp from '../../helpers/define-app';
|
|||||||
import addAuthHeader from './common/add-auth-header';
|
import addAuthHeader from './common/add-auth-header';
|
||||||
import auth from './auth';
|
import auth from './auth';
|
||||||
import triggers from './triggers';
|
import triggers from './triggers';
|
||||||
import actions from './actions';
|
|
||||||
import dynamicData from './dynamic-data';
|
import dynamicData from './dynamic-data';
|
||||||
|
|
||||||
export default defineApp({
|
export default defineApp({
|
||||||
@@ -17,6 +16,5 @@ export default defineApp({
|
|||||||
beforeRequest: [addAuthHeader],
|
beforeRequest: [addAuthHeader],
|
||||||
auth,
|
auth,
|
||||||
triggers,
|
triggers,
|
||||||
actions,
|
|
||||||
dynamicData,
|
dynamicData,
|
||||||
});
|
});
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
import sendSms from './send-sms';
|
|
||||||
|
|
||||||
export default [sendSms];
|
|
@@ -1,63 +0,0 @@
|
|||||||
import defineAction from '../../../../helpers/define-action';
|
|
||||||
|
|
||||||
export default defineAction({
|
|
||||||
name: 'Send an SMS',
|
|
||||||
key: 'sendSms',
|
|
||||||
description: 'Sends an SMS',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
label: 'From Number',
|
|
||||||
key: 'fromNumber',
|
|
||||||
type: 'dropdown' as const,
|
|
||||||
required: true,
|
|
||||||
description:
|
|
||||||
'The number to send the SMS from. Include only country code. Example: 491234567890',
|
|
||||||
variables: true,
|
|
||||||
source: {
|
|
||||||
type: 'query',
|
|
||||||
name: 'getDynamicData',
|
|
||||||
arguments: [
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
value: 'listIncomingPhoneNumbers',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'To Number',
|
|
||||||
key: 'toNumber',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description:
|
|
||||||
'The number to send the SMS to. Include only country code. Example: 491234567890',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Message',
|
|
||||||
key: 'message',
|
|
||||||
type: 'string' as const,
|
|
||||||
required: true,
|
|
||||||
description: 'The content of the message.',
|
|
||||||
variables: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
async run($) {
|
|
||||||
const requestPath = `/api/laml/2010-04-01/Accounts/${$.auth.data.accountSid}/Messages`;
|
|
||||||
|
|
||||||
const Body = $.step.parameters.message;
|
|
||||||
const From = $.step.parameters.fromNumber;
|
|
||||||
const To = '+' + ($.step.parameters.toNumber as string).trim();
|
|
||||||
|
|
||||||
const response = await $.http.post(requestPath, null, {
|
|
||||||
params: {
|
|
||||||
Body,
|
|
||||||
From,
|
|
||||||
To,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$.setActionItem({ raw: response.data });
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1 +0,0 @@
|
|||||||
<svg id="a1100050-5390-497e-a7fa-2bb69ec95c7c" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 318.33 362.7"><defs><style>.a463a3b0-e95c-44d7-b809-5997966784eb{fill:#044ef4;}.b59fade4-5c2c-49f1-a6bf-917d1f195a19{fill:#f72a72;}</style></defs><path class="a463a3b0-e95c-44d7-b809-5997966784eb" d="M389.17,278c0,10.31-2.8,17.06-8.37,22.62q-50.07,49.95-100.19,99.85C269,412,252.06,412.54,240.55,402c-12.12-11.13-12.6-29.39-.75-41.47,15-15.34,30.32-30.47,45.56-45.63q27.47-27.3,55.06-54.45c8.91-8.75,20.84-11.07,31.77-6.1C383.3,259.36,388.79,268.25,389.17,278Z" transform="translate(-70.83 -46.81)"/><path class="a463a3b0-e95c-44d7-b809-5997966784eb" d="M70.84,172.94c.16-5.21,2.93-11.81,8.36-17.24q49.89-49.77,99.8-99.53c6.92-6.91,15.08-10.45,24.83-9.06,11.55,1.65,19.62,8.12,23.38,19.22s1.16,21.14-7,29.43q-23.87,24.21-48,48.1-26.22,26.07-52.58,52c-8.93,8.76-20.84,10.92-31.8,6.13C77.17,197.35,70.65,187.14,70.84,172.94Z" transform="translate(-70.83 -46.81)"/><path class="b59fade4-5c2c-49f1-a6bf-917d1f195a19" d="M93.68,210.69c3.79-.17,6.91-.08,10-.49a34.39,34.39,0,0,0,20.56-10.34c6.38-6.52,12.79-13,19.33-19.66,1.23,1.09,2,1.7,2.66,2.38q36.92,36.9,73.81,73.83c8.07,8.1,10.9,17.87,7.66,28.86-3.12,10.58-10.39,17.35-21.17,19.77-9.33,2.1-18.23.31-25.07-6.47C152.25,269.64,123.32,240.42,93.68,210.69Z" transform="translate(-70.83 -46.81)"/><path class="b59fade4-5c2c-49f1-a6bf-917d1f195a19" d="M366.57,246c-15-1.53-25.7,4.26-34.72,14.22-4.89,5.4-10.23,10.39-15.51,15.69-1.1-1-1.86-1.59-2.56-2.28q-36.94-36.93-73.86-73.89c-8.07-8.1-10.89-17.89-7.56-28.89,3.19-10.56,10.47-17.31,21.28-19.68,9.56-2.1,18.45,0,25.44,6.92q43,42.57,85.61,85.47C365.12,244,365.44,244.54,366.57,246Z" transform="translate(-70.83 -46.81)"/></svg>
|
|
Before Width: | Height: | Size: 1.7 KiB |