refactor: Redesign twitter trigger and actions
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import qs from 'qs';
|
||||
import { IGlobalVariableForConnection } from '@automatisch/types';
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariableForConnection) => {
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
const headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
};
|
||||
|
@@ -1,12 +1,8 @@
|
||||
import generateRequest from '../common/generate-request';
|
||||
import {
|
||||
IJSONObject,
|
||||
IField,
|
||||
IGlobalVariableForConnection,
|
||||
} from '@automatisch/types';
|
||||
import { IJSONObject, IField, IGlobalVariable } from '@automatisch/types';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
export default async function createAuthData($: IGlobalVariableForConnection) {
|
||||
export default async function createAuthData($: IGlobalVariable) {
|
||||
try {
|
||||
const oauthRedirectUrlField = $.app.fields.find(
|
||||
(field: IField) => field.key == 'oAuthRedirectUrl'
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { IGlobalVariableForConnection } from '@automatisch/types';
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getCurrentUser from '../common/get-current-user';
|
||||
|
||||
const isStillVerified = async ($: IGlobalVariableForConnection) => {
|
||||
const isStillVerified = async ($: IGlobalVariable) => {
|
||||
try {
|
||||
await getCurrentUser($);
|
||||
return true;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { IGlobalVariableForConnection } from '@automatisch/types';
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
const verifyCredentials = async ($: IGlobalVariableForConnection) => {
|
||||
const verifyCredentials = async ($: IGlobalVariable) => {
|
||||
try {
|
||||
const response = await $.http.post(
|
||||
`/oauth/access_token?oauth_verifier=${$.auth.data.oauthVerifier}&oauth_token=${$.auth.data.accessToken}`,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { IGlobalVariableForConnection, IJSONObject } from '@automatisch/types';
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import oauthClient from './oauth-client';
|
||||
import { Token } from 'oauth-1.0a';
|
||||
|
||||
@@ -9,7 +9,7 @@ type IGenereateRequestOptons = {
|
||||
};
|
||||
|
||||
const generateRequest = async (
|
||||
$: IGlobalVariableForConnection,
|
||||
$: IGlobalVariable,
|
||||
options: IGenereateRequestOptons
|
||||
) => {
|
||||
const { requestPath, method, data } = options;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { IGlobalVariableForConnection } from '@automatisch/types';
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import generateRequest from './generate-request';
|
||||
|
||||
const getCurrentUser = async ($: IGlobalVariableForConnection) => {
|
||||
const getCurrentUser = async ($: IGlobalVariable): Promise<IJSONObject> => {
|
||||
const response = await generateRequest($, {
|
||||
requestPath: '/2/users/me',
|
||||
method: 'GET',
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import { IGlobalVariableForConnection, IJSONObject } from '@automatisch/types';
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import generateRequest from './generate-request';
|
||||
|
||||
const getUserByUsername = async (
|
||||
$: IGlobalVariableForConnection,
|
||||
username: string
|
||||
) => {
|
||||
const getUserByUsername = async ($: IGlobalVariable, username: string) => {
|
||||
const response = await generateRequest($, {
|
||||
requestPath: `/2/users/by/username/${username}`,
|
||||
method: 'GET',
|
||||
|
@@ -0,0 +1,59 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import { URLSearchParams } from 'url';
|
||||
import { omitBy, isEmpty } from 'lodash';
|
||||
import generateRequest from './generate-request';
|
||||
|
||||
type GetUserFollowersOptions = {
|
||||
userId: string;
|
||||
lastInternalId?: string;
|
||||
};
|
||||
|
||||
const getUserFollowers = async (
|
||||
$: IGlobalVariable,
|
||||
options: GetUserFollowersOptions
|
||||
) => {
|
||||
let response;
|
||||
const followers: IJSONObject[] = [];
|
||||
|
||||
do {
|
||||
const params: IJSONObject = {
|
||||
pagination_token: response?.data?.meta?.next_token,
|
||||
};
|
||||
|
||||
const queryParams = new URLSearchParams(omitBy(params, isEmpty));
|
||||
|
||||
const requestPath = `/2/users/${options.userId}/followers${
|
||||
queryParams.toString() ? `?${queryParams.toString()}` : ''
|
||||
}`;
|
||||
|
||||
response = await generateRequest($, {
|
||||
requestPath,
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
if (response.data.meta.result_count > 0) {
|
||||
response.data.data.forEach((tweet: IJSONObject) => {
|
||||
if (
|
||||
!options.lastInternalId ||
|
||||
Number(tweet.id) > Number(options.lastInternalId)
|
||||
) {
|
||||
followers.push(tweet);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
} while (response.data.meta.next_token && options.lastInternalId);
|
||||
|
||||
if (response.data?.errors) {
|
||||
const errorMessages = response.data.errors
|
||||
.map((error: IJSONObject) => error.detail)
|
||||
.join(' ');
|
||||
|
||||
throw new Error(`Error occured while fetching user data: ${errorMessages}`);
|
||||
}
|
||||
|
||||
return followers;
|
||||
};
|
||||
|
||||
export default getUserFollowers;
|
@@ -1,26 +1,44 @@
|
||||
import { IGlobalVariableForConnection, IJSONObject } from '@automatisch/types';
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import { URLSearchParams } from 'url';
|
||||
import omitBy from 'lodash/omitBy';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import generateRequest from './generate-request';
|
||||
import getCurrentUser from './get-current-user';
|
||||
import getUserByUsername from './get-user-by-username';
|
||||
|
||||
type IGetUserTweetsOptions = {
|
||||
currentUser: boolean;
|
||||
userId?: string;
|
||||
lastInternalId?: string;
|
||||
};
|
||||
|
||||
const getUserTweets = async (
|
||||
$: IGlobalVariableForConnection,
|
||||
userId: string,
|
||||
lastInternalId?: string
|
||||
$: IGlobalVariable,
|
||||
options: IGetUserTweetsOptions
|
||||
) => {
|
||||
let username: string;
|
||||
|
||||
if (options.currentUser) {
|
||||
const currentUser = await getCurrentUser($);
|
||||
username = currentUser.username as string;
|
||||
} else {
|
||||
username = $.db.step.parameters.username as string;
|
||||
}
|
||||
|
||||
const user = await getUserByUsername($, username);
|
||||
|
||||
let response;
|
||||
const tweets: IJSONObject[] = [];
|
||||
|
||||
do {
|
||||
const params: IJSONObject = {
|
||||
since_id: lastInternalId,
|
||||
since_id: options.lastInternalId,
|
||||
pagination_token: response?.data?.meta?.next_token,
|
||||
};
|
||||
|
||||
const queryParams = new URLSearchParams(omitBy(params, isEmpty));
|
||||
|
||||
const requestPath = `/2/users/${userId}/tweets${
|
||||
const requestPath = `/2/users/${user.id}/tweets${
|
||||
queryParams.toString() ? `?${queryParams.toString()}` : ''
|
||||
}`;
|
||||
|
||||
@@ -31,14 +49,17 @@ const getUserTweets = async (
|
||||
|
||||
if (response.data.meta.result_count > 0) {
|
||||
response.data.data.forEach((tweet: IJSONObject) => {
|
||||
if (!lastInternalId || Number(tweet.id) > Number(lastInternalId)) {
|
||||
if (
|
||||
!options.lastInternalId ||
|
||||
Number(tweet.id) > Number(options.lastInternalId)
|
||||
) {
|
||||
tweets.push(tweet);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
} while (response.data.meta.next_token && lastInternalId);
|
||||
} while (response.data.meta.next_token && options.lastInternalId);
|
||||
|
||||
if (response.data.errors) {
|
||||
const errorMessages = response.data.errors
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { IGlobalVariableForConnection } from '@automatisch/types';
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import crypto from 'crypto';
|
||||
import OAuth from 'oauth-1.0a';
|
||||
|
||||
const oauthClient = ($: IGlobalVariableForConnection) => {
|
||||
const oauthClient = ($: IGlobalVariable) => {
|
||||
const consumerData = {
|
||||
key: $.auth.data.consumerKey as string,
|
||||
secret: $.auth.data.consumerSecret as string,
|
||||
|
@@ -1,6 +1,4 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getCurrentUser from '../../common/get-current-user';
|
||||
import getUserByUsername from '../../common/get-user-by-username';
|
||||
import getUserTweets from '../../common/get-user-tweets';
|
||||
|
||||
export default {
|
||||
@@ -20,18 +18,13 @@ export default {
|
||||
],
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
return this.getTweets($, await $.db.flow.lastInternalId());
|
||||
return await getUserTweets($, {
|
||||
currentUser: true,
|
||||
lastInternalId: $.db.flow.lastInternalId,
|
||||
});
|
||||
},
|
||||
|
||||
async testRun($: IGlobalVariable) {
|
||||
return this.getTweets($);
|
||||
},
|
||||
|
||||
async getTweets($: IGlobalVariable, lastInternalId?: string) {
|
||||
const { username } = await getCurrentUser($);
|
||||
const user = await getUserByUsername($, username);
|
||||
|
||||
const tweets = await getUserTweets($, user.id, lastInternalId);
|
||||
return tweets;
|
||||
return await getUserTweets($, { currentUser: true });
|
||||
},
|
||||
};
|
||||
|
@@ -0,0 +1,27 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import myFollowers from './my-followers';
|
||||
|
||||
export default {
|
||||
name: 'New follower of me',
|
||||
key: 'myFollowers',
|
||||
pollInterval: 15,
|
||||
description: 'Will be triggered when you have a new follower.',
|
||||
substeps: [
|
||||
{
|
||||
key: 'chooseConnection',
|
||||
name: 'Choose connection',
|
||||
},
|
||||
{
|
||||
key: 'testStep',
|
||||
name: 'Test trigger',
|
||||
},
|
||||
],
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
return await myFollowers($, $.db.flow.lastInternalId);
|
||||
},
|
||||
|
||||
async testRun($: IGlobalVariable) {
|
||||
return await myFollowers($);
|
||||
},
|
||||
};
|
@@ -0,0 +1,17 @@
|
||||
import { IGlobalVariable } from "@automatisch/types";
|
||||
import getCurrentUser from "../../common/get-current-user";
|
||||
import getUserByUsername from "../../common/get-user-by-username";
|
||||
import getUserFollowers from "../../common/get-user-followers";
|
||||
|
||||
const myFollowers = async( $: IGlobalVariable, lastInternalId?: string) => {
|
||||
const { username } = await getCurrentUser($);
|
||||
const user = await getUserByUsername($, username as string);
|
||||
|
||||
const tweets = await getUserFollowers($, {
|
||||
userId: user.id,
|
||||
lastInternalId
|
||||
});
|
||||
return tweets;
|
||||
});
|
||||
|
||||
export default myFollowers;
|
@@ -0,0 +1,45 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import searchTweets from './search-tweets';
|
||||
|
||||
export default {
|
||||
name: 'Search Tweets',
|
||||
key: 'searchTweets',
|
||||
pollInterval: 15,
|
||||
description:
|
||||
'Will be triggered when any user tweet something containing a specific keyword, phrase, username or hashtag.',
|
||||
substeps: [
|
||||
{
|
||||
key: 'chooseConnection',
|
||||
name: 'Choose connection',
|
||||
},
|
||||
{
|
||||
key: 'chooseTrigger',
|
||||
name: 'Set up a trigger',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Search Term',
|
||||
key: 'searchTerm',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'testStep',
|
||||
name: 'Test trigger',
|
||||
},
|
||||
],
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
return await searchTweets($, {
|
||||
searchTerm: $.db.step.parameters.searchTerm as string,
|
||||
lastInternalId: $.db.flow.lastInternalId,
|
||||
});
|
||||
},
|
||||
|
||||
async testRun($: IGlobalVariable) {
|
||||
return await searchTweets($, {
|
||||
searchTerm: $.db.step.parameters.searchTerm as string,
|
||||
});
|
||||
},
|
||||
};
|
@@ -0,0 +1,65 @@
|
||||
import { IGlobalVariable, IJSONObject } from '@automatisch/types';
|
||||
import qs from 'qs';
|
||||
import generateRequest from '../../common/generate-request';
|
||||
import { omitBy, isEmpty } from 'lodash';
|
||||
|
||||
type ISearchTweetsOptions = {
|
||||
searchTerm: string;
|
||||
lastInternalId?: string;
|
||||
};
|
||||
|
||||
const searchTweets = async (
|
||||
$: IGlobalVariable,
|
||||
options: ISearchTweetsOptions
|
||||
) => {
|
||||
let response;
|
||||
|
||||
const tweets: {
|
||||
data: IJSONObject[];
|
||||
error: IJSONObject | null;
|
||||
} = {
|
||||
data: [],
|
||||
error: null,
|
||||
};
|
||||
|
||||
do {
|
||||
const params: IJSONObject = {
|
||||
query: options.searchTerm,
|
||||
since_id: options.lastInternalId,
|
||||
pagination_token: response?.data?.meta?.next_token,
|
||||
};
|
||||
|
||||
const queryParams = qs.stringify(omitBy(params, isEmpty));
|
||||
|
||||
const requestPath = `/2/tweets/search/recent${
|
||||
queryParams.toString() ? `?${queryParams.toString()}` : ''
|
||||
}`;
|
||||
|
||||
response = await generateRequest($, {
|
||||
requestPath,
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
if (response.integrationError) {
|
||||
tweets.error = response.integrationError;
|
||||
return tweets;
|
||||
}
|
||||
|
||||
if (response.data.meta.result_count > 0) {
|
||||
response.data.data.forEach((tweet: IJSONObject) => {
|
||||
if (
|
||||
!options.lastInternalId ||
|
||||
Number(tweet.id) > Number(options.lastInternalId)
|
||||
) {
|
||||
tweets.data.push(tweet);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
} while (response.data.meta.next_token && options.lastInternalId);
|
||||
|
||||
return tweets;
|
||||
};
|
||||
|
||||
export default searchTweets;
|
@@ -0,0 +1,46 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
import getUserTweets from '../../common/get-user-tweets';
|
||||
|
||||
export default {
|
||||
name: 'User Tweets',
|
||||
key: 'userTweets',
|
||||
pollInterval: 15,
|
||||
description: 'Will be triggered when a specific user tweet something new.',
|
||||
substeps: [
|
||||
{
|
||||
key: 'chooseConnection',
|
||||
name: 'Choose connection',
|
||||
},
|
||||
{
|
||||
key: 'chooseTrigger',
|
||||
name: 'Set up a trigger',
|
||||
arguments: [
|
||||
{
|
||||
label: 'Username',
|
||||
key: 'username',
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'testStep',
|
||||
name: 'Test trigger',
|
||||
},
|
||||
],
|
||||
|
||||
async run($: IGlobalVariable) {
|
||||
return await getUserTweets($, {
|
||||
currentUser: false,
|
||||
userId: $.db.step.parameters.username as string,
|
||||
lastInternalId: $.db.flow.lastInternalId,
|
||||
});
|
||||
},
|
||||
|
||||
async testRun($: IGlobalVariable) {
|
||||
return await getUserTweets($, {
|
||||
currentUser: false,
|
||||
userId: $.db.step.parameters.username as string,
|
||||
});
|
||||
},
|
||||
};
|
@@ -1,29 +1,40 @@
|
||||
import createHttpClient from './http-client';
|
||||
import Connection from '../models/connection';
|
||||
import Flow from '../models/flow';
|
||||
import Step from '../models/step';
|
||||
import { IJSONObject, IApp, IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const globalVariable = (
|
||||
const globalVariable = async (
|
||||
connection: Connection,
|
||||
appData: IApp,
|
||||
flow?: Flow
|
||||
): IGlobalVariable => {
|
||||
flow?: Flow,
|
||||
currentStep?: Step
|
||||
): Promise<IGlobalVariable> => {
|
||||
const lastInternalId = await flow?.lastInternalId();
|
||||
|
||||
return {
|
||||
auth: {
|
||||
set: async (args: IJSONObject) => {
|
||||
return await connection.$query().patchAndFetch({
|
||||
await connection.$query().patchAndFetch({
|
||||
formattedData: {
|
||||
...connection.formattedData,
|
||||
...args,
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
},
|
||||
data: connection.formattedData,
|
||||
},
|
||||
app: appData,
|
||||
http: createHttpClient({ baseURL: appData.baseUrl }),
|
||||
db: {
|
||||
flow: flow,
|
||||
flow: {
|
||||
lastInternalId,
|
||||
},
|
||||
step: {
|
||||
parameters: currentStep?.parameters || {},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
9
packages/types/index.d.ts
vendored
9
packages/types/index.d.ts
vendored
@@ -197,13 +197,18 @@ export type IHttpClientParams = {
|
||||
|
||||
export type IGlobalVariable = {
|
||||
auth: {
|
||||
set: (args: IJSONObject) => Promise<IConnection>;
|
||||
set: (args: IJSONObject) => Promise<null>;
|
||||
data: IJSONObject;
|
||||
};
|
||||
app: IApp;
|
||||
http: IHttpClient;
|
||||
db: {
|
||||
flow: IFlow;
|
||||
flow: {
|
||||
lastInternalId: string;
|
||||
};
|
||||
step: {
|
||||
parameters: IJSONObject;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user