diff --git a/packages/backend/src/apps/twitter/actions/create-tweet.ts b/packages/backend/src/apps/twitter/actions/create-tweet.ts index 76a1560d..92dbc019 100644 --- a/packages/backend/src/apps/twitter/actions/create-tweet.ts +++ b/packages/backend/src/apps/twitter/actions/create-tweet.ts @@ -9,7 +9,7 @@ export default class CreateTweet { async run() { const response = await this.client.createTweet.run( - this.client.parameters.tweet as string + this.client.step.parameters.tweet as string ); return response.data.data; diff --git a/packages/backend/src/apps/twitter/authentication.ts b/packages/backend/src/apps/twitter/authentication.ts index 5beb7fb4..54551e85 100644 --- a/packages/backend/src/apps/twitter/authentication.ts +++ b/packages/backend/src/apps/twitter/authentication.ts @@ -1,4 +1,4 @@ -import type { IAuthentication, IField } from '@automatisch/types'; +import type { IAuthentication, IField, IApp } from '@automatisch/types'; import { URLSearchParams } from 'url'; import TwitterClient from './client'; @@ -10,7 +10,7 @@ export default class Authentication implements IAuthentication { } async createAuthData() { - const appFields = this.client.appData.fields.find( + const appFields = this.client.connection.appData.fields.find( (field: IField) => field.key == 'oAuthRedirectUrl' ); const callbackUrl = appFields.value; @@ -30,8 +30,9 @@ export default class Authentication implements IAuthentication { const responseData = Object.fromEntries(new URLSearchParams(response.data)); return { - consumerKey: this.client.connectionData.consumerKey, - consumerSecret: this.client.connectionData.consumerSecret, + consumerKey: this.client.connection.formattedData.consumerKey as string, + consumerSecret: this.client.connection.formattedData + .consumerSecret as string, accessToken: responseData.oauth_token, accessSecret: responseData.oauth_token_secret, userId: responseData.user_id, diff --git a/packages/backend/src/apps/twitter/client/endpoints/create-tweet.ts b/packages/backend/src/apps/twitter/client/endpoints/create-tweet.ts index 130732ee..d8980159 100644 --- a/packages/backend/src/apps/twitter/client/endpoints/create-tweet.ts +++ b/packages/backend/src/apps/twitter/client/endpoints/create-tweet.ts @@ -10,8 +10,8 @@ export default class CreateTweet { async run(text: string) { try { const token = { - key: this.client.connectionData.accessToken as string, - secret: this.client.connectionData.accessSecret as string, + key: this.client.connection.formattedData.accessToken as string, + secret: this.client.connection.formattedData.accessSecret as string, }; const requestData = { diff --git a/packages/backend/src/apps/twitter/client/endpoints/get-current-user.ts b/packages/backend/src/apps/twitter/client/endpoints/get-current-user.ts index 893a8fa5..f8cc3531 100644 --- a/packages/backend/src/apps/twitter/client/endpoints/get-current-user.ts +++ b/packages/backend/src/apps/twitter/client/endpoints/get-current-user.ts @@ -9,8 +9,8 @@ export default class GetCurrentUser { async run() { const token = { - key: this.client.connectionData.accessToken as string, - secret: this.client.connectionData.accessSecret as string, + key: this.client.connection.formattedData.accessToken as string, + secret: this.client.connection.formattedData.accessSecret as string, }; const requestPath = '/2/users/me'; diff --git a/packages/backend/src/apps/twitter/client/endpoints/get-user-by-username.ts b/packages/backend/src/apps/twitter/client/endpoints/get-user-by-username.ts index 173699c1..e21e2fda 100644 --- a/packages/backend/src/apps/twitter/client/endpoints/get-user-by-username.ts +++ b/packages/backend/src/apps/twitter/client/endpoints/get-user-by-username.ts @@ -10,8 +10,8 @@ export default class GetUserByUsername { async run(username: string) { const token = { - key: this.client.connectionData.accessToken as string, - secret: this.client.connectionData.accessSecret as string, + key: this.client.connection.formattedData.accessToken as string, + secret: this.client.connection.formattedData.accessSecret as string, }; const requestPath = `/2/users/by/username/${username}`; diff --git a/packages/backend/src/apps/twitter/client/endpoints/get-user-tweets.ts b/packages/backend/src/apps/twitter/client/endpoints/get-user-tweets.ts index da2bf3cc..7bde7466 100644 --- a/packages/backend/src/apps/twitter/client/endpoints/get-user-tweets.ts +++ b/packages/backend/src/apps/twitter/client/endpoints/get-user-tweets.ts @@ -10,8 +10,8 @@ export default class GetUserTweets { async run(userId: string) { const token = { - key: this.client.connectionData.accessToken as string, - secret: this.client.connectionData.accessSecret as string, + key: this.client.connection.formattedData.accessToken as string, + secret: this.client.connection.formattedData.accessSecret as string, }; const requestPath = `/2/users/${userId}/tweets`; diff --git a/packages/backend/src/apps/twitter/client/endpoints/verify-access-token.ts b/packages/backend/src/apps/twitter/client/endpoints/verify-access-token.ts index 2bd7e470..7c51a52f 100644 --- a/packages/backend/src/apps/twitter/client/endpoints/verify-access-token.ts +++ b/packages/backend/src/apps/twitter/client/endpoints/verify-access-token.ts @@ -10,7 +10,7 @@ export default class VerifyAccessToken { async run() { try { return await this.client.httpClient.post( - `/oauth/access_token?oauth_verifier=${this.client.connectionData.oauthVerifier}&oauth_token=${this.client.connectionData.accessToken}`, + `/oauth/access_token?oauth_verifier=${this.client.connection.formattedData.oauthVerifier}&oauth_token=${this.client.connection.formattedData.accessToken}`, null ); } catch (error) { diff --git a/packages/backend/src/apps/twitter/client/index.ts b/packages/backend/src/apps/twitter/client/index.ts index 2a384d7a..c3544d9f 100644 --- a/packages/backend/src/apps/twitter/client/index.ts +++ b/packages/backend/src/apps/twitter/client/index.ts @@ -1,4 +1,4 @@ -import { IJSONObject, IApp } from '@automatisch/types'; +import { IFlow, IStep, IConnection } from '@automatisch/types'; import OAuth from 'oauth-1.0a'; import crypto from 'crypto'; import HttpClient from '../../../helpers/http-client'; @@ -10,9 +10,9 @@ import GetUserTweets from './endpoints/get-user-tweets'; import CreateTweet from './endpoints/create-tweet'; export default class TwitterClient { - appData: IApp; - connectionData: IJSONObject; - parameters: IJSONObject; + flow: IFlow; + step: IStep; + connection: IConnection; oauthClient: OAuth; httpClient: HttpClient; @@ -25,20 +25,16 @@ export default class TwitterClient { static baseUrl = 'https://api.twitter.com'; - constructor( - appData: IApp, - connectionData: IJSONObject, - parameters: IJSONObject - ) { - this.connectionData = connectionData; - this.appData = appData; - this.parameters = parameters; + constructor(connection: IConnection, flow?: IFlow, step?: IStep) { + this.connection = connection; + this.flow = flow; + this.step = step; this.httpClient = new HttpClient({ baseURL: TwitterClient.baseUrl }); const consumerData = { - key: this.connectionData.consumerKey as string, - secret: this.connectionData.consumerSecret as string, + key: this.connection.formattedData.consumerKey as string, + secret: this.connection.formattedData.consumerSecret as string, }; this.oauthClient = new OAuth({ diff --git a/packages/backend/src/apps/twitter/index.ts b/packages/backend/src/apps/twitter/index.ts index e2f1d5c8..ee8e1005 100644 --- a/packages/backend/src/apps/twitter/index.ts +++ b/packages/backend/src/apps/twitter/index.ts @@ -1,8 +1,9 @@ import { IService, IAuthentication, - IApp, - IJSONObject, + IFlow, + IStep, + IConnection, } from '@automatisch/types'; import Authentication from './authentication'; import Triggers from './triggers'; @@ -16,12 +17,8 @@ export default class Twitter implements IService { triggers: Triggers; actions: Actions; - constructor( - appData: IApp, - connectionData: IJSONObject, - parameters: IJSONObject - ) { - this.client = new TwitterClient(appData, connectionData, parameters); + constructor(connection: IConnection, flow?: IFlow, step?: IStep) { + this.client = new TwitterClient(connection, flow, step); this.authenticationClient = new Authentication(this.client); this.triggers = new Triggers(this.client); diff --git a/packages/backend/src/apps/twitter/triggers/user-tweet.ts b/packages/backend/src/apps/twitter/triggers/user-tweet.ts index a4d42b94..44fcf058 100644 --- a/packages/backend/src/apps/twitter/triggers/user-tweet.ts +++ b/packages/backend/src/apps/twitter/triggers/user-tweet.ts @@ -17,7 +17,7 @@ export default class UserTweet { async getTweets() { const userResponse = await this.client.getUserByUsername.run( - this.client.parameters.username as string + this.client.step.parameters.username as string ); const userId = userResponse.data.data.id; diff --git a/packages/backend/src/graphql/mutations/create-auth-data.ts b/packages/backend/src/graphql/mutations/create-auth-data.ts index 8721e24f..8a4b8886 100644 --- a/packages/backend/src/graphql/mutations/create-auth-data.ts +++ b/packages/backend/src/graphql/mutations/create-auth-data.ts @@ -1,5 +1,4 @@ import Context from '../../types/express/context'; -import App from '../../models/app'; import axios from 'axios'; type Params = { @@ -21,13 +20,12 @@ const createAuthData = async ( .throwIfNotFound(); const appClass = (await import(`../../apps/${connection.key}`)).default; - const appData = App.findOneByKey(connection.key); if (!connection.formattedData) { return null; } - const appInstance = new appClass(appData, connection.formattedData); + const appInstance = new appClass(connection); const authLink = await appInstance.authenticationClient.createAuthData(); try { diff --git a/packages/backend/src/graphql/mutations/verify-connection.ts b/packages/backend/src/graphql/mutations/verify-connection.ts index ee117262..b0863aa5 100644 --- a/packages/backend/src/graphql/mutations/verify-connection.ts +++ b/packages/backend/src/graphql/mutations/verify-connection.ts @@ -22,7 +22,7 @@ const verifyConnection = async ( const appClass = (await import(`../../apps/${connection.key}`)).default; const app = App.findOneByKey(connection.key); - const appInstance = new appClass(app, connection.formattedData); + const appInstance = new appClass(connection); const verifiedCredentials = await appInstance.authenticationClient.verifyCredentials(); diff --git a/packages/backend/src/graphql/queries/get-data.ts b/packages/backend/src/graphql/queries/get-data.ts index 938fb639..5b8dff1a 100644 --- a/packages/backend/src/graphql/queries/get-data.ts +++ b/packages/backend/src/graphql/queries/get-data.ts @@ -1,5 +1,4 @@ import { IJSONObject } from '@automatisch/types'; -import App from '../../models/app'; import Context from '../../types/express/context'; type Params = { @@ -11,7 +10,7 @@ type Params = { const getData = async (_parent: unknown, params: Params, context: Context) => { const step = await context.currentUser .$relatedQuery('steps') - .withGraphFetched('connection') + .withGraphFetched('connection, flow') .findById(params.stepId); if (!step) return null; @@ -20,10 +19,9 @@ const getData = async (_parent: unknown, params: Params, context: Context) => { if (!connection || !step.appKey) return null; - const appData = App.findOneByKey(step.appKey); const AppClass = (await import(`../../apps/${step.appKey}`)).default; + const appInstance = new AppClass(connection, step.flow, step); - const appInstance = new AppClass(appData, connection.formattedData, params.parameters); const command = appInstance.data[params.key]; const fetchedData = await command.run(); diff --git a/packages/backend/src/graphql/queries/test-connection.ts b/packages/backend/src/graphql/queries/test-connection.ts index efa69792..1b9a01f5 100644 --- a/packages/backend/src/graphql/queries/test-connection.ts +++ b/packages/backend/src/graphql/queries/test-connection.ts @@ -1,5 +1,4 @@ import Context from '../../types/express/context'; -import App from '../../models/app'; type Params = { id: string; @@ -19,9 +18,8 @@ const testConnection = async ( .throwIfNotFound(); const appClass = (await import(`../../apps/${connection.key}`)).default; - const appData = App.findOneByKey(connection.key); + const appInstance = new appClass(connection); - const appInstance = new appClass(appData, connection.formattedData); const isStillVerified = await appInstance.authenticationClient.isStillVerified(); diff --git a/packages/backend/src/models/connection.ts b/packages/backend/src/models/connection.ts index 5a1460eb..8d44fd07 100644 --- a/packages/backend/src/models/connection.ts +++ b/packages/backend/src/models/connection.ts @@ -4,6 +4,7 @@ import { AES, enc } from 'crypto-js'; import Base from './base'; import User from './user'; import Step from './step'; +import App from './app'; import appConfig from '../config/app'; import { IJSONObject } from '@automatisch/types'; import Telemetry from '../helpers/telemetry'; @@ -55,6 +56,10 @@ class Connection extends Base { }, }); + get appData() { + return App.findOneByKey(this.key); + } + encryptData(): void { if (!this.eligibleForEncryption()) return; diff --git a/packages/backend/src/models/step.ts b/packages/backend/src/models/step.ts index a231066e..61579f40 100644 --- a/packages/backend/src/models/step.ts +++ b/packages/backend/src/models/step.ts @@ -78,6 +78,10 @@ class Step extends Base { return `${appConfig.baseUrl}/apps/${this.appKey}/assets/favicon.svg`; } + get appData() { + return App.findOneByKey(this.appKey); + } + async $afterInsert(queryContext: QueryContext) { await super.$afterInsert(queryContext); Telemetry.stepCreated(this); @@ -95,17 +99,13 @@ class Step extends Base { async getTrigger() { if (!this.isTrigger) return null; - const { appKey, key, parameters = {} } = this; + const { appKey, key } = this; const connection = await this.$relatedQuery('connection'); + const flow = await this.$relatedQuery('flow'); - const appData = App.findOneByKey(appKey); const AppClass = (await import(`../apps/${appKey}`)).default; - const appInstance = new AppClass( - appData, - connection?.formattedData, - parameters - ); + const appInstance = new AppClass(connection, flow, this); const command = appInstance.triggers[key]; return command; diff --git a/packages/backend/src/services/processor.ts b/packages/backend/src/services/processor.ts index 570a3cf6..f5c85554 100644 --- a/packages/backend/src/services/processor.ts +++ b/packages/backend/src/services/processor.ts @@ -1,5 +1,4 @@ import get from 'lodash.get'; -import App from '../models/app'; import Flow from '../models/flow'; import Step from '../models/step'; import Execution from '../models/execution'; @@ -56,16 +55,7 @@ class Processor { for await (const step of steps) { if (!step.appKey) continue; - const appData = App.findOneByKey(step.appKey); - - const { - appKey, - connection, - key, - type, - parameters: rawParameters = {}, - id, - } = step; + const { appKey, key, type, parameters: rawParameters = {}, id } = step; const isTrigger = type === 'trigger'; const AppClass = (await import(`../apps/${appKey}`)).default; @@ -75,11 +65,7 @@ class Processor { priorExecutionSteps ); - const appInstance = new AppClass( - appData, - connection?.formattedData, - computedParameters - ); + const appInstance = new AppClass(step.connection, this.flow, step); if (!isTrigger && key) { const command = appInstance.actions[key]; @@ -114,19 +100,10 @@ class Processor { } async getInitialTriggerData(step: Step) { - if (!step.appKey) return null; + if (!step.appKey || !step.key) return null; - const appData = App.findOneByKey(step.appKey); - const { appKey, connection, key, parameters: rawParameters = {} } = step; - - if (!key) return null; - - const AppClass = (await import(`../apps/${appKey}`)).default; - const appInstance = new AppClass( - appData, - connection?.formattedData, - rawParameters - ); + const AppClass = (await import(`../apps/${step.appKey}`)).default; + const appInstance = new AppClass(step.connection, this.flow, step); const lastExecutionStep = await step .$relatedQuery('executionSteps') @@ -136,7 +113,7 @@ class Processor { const lastExecutionStepCreatedAt = lastExecutionStep?.createdAt as string; const flow = (await step.$relatedQuery('flow')) as Flow; - const command = appInstance.triggers[key]; + const command = appInstance.triggers[step.key]; const startTime = new Date(lastExecutionStepCreatedAt || flow.updatedAt); let fetchedData; @@ -163,7 +140,10 @@ class Processor { .map((part: string) => { const isVariable = part.match(Processor.variableRegExp); if (isVariable) { - const stepIdAndKeyPath = part.replace(/{{step.|}}/g, '') as string; + const stepIdAndKeyPath = part.replace( + /{{step.|}}/g, + '' + ) as string; const [stepId, ...keyPaths] = stepIdAndKeyPath.split('.'); const keyPath = keyPaths.join('.'); const executionStep = executionSteps[stepId.toString() as string]; diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index a2a067a4..6f06513e 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -15,6 +15,7 @@ export interface IConnection { verified: boolean; count: number; flowCount: number; + appData?: IApp; createdAt: string; } @@ -57,6 +58,7 @@ export interface IStep { executionSteps: IExecutionStep[]; // FIXME: remove this property once execution steps are properly exposed via queries output: IJSONObject; + appData?: IApp; } export interface IFlow {