From 9613e142c9ef030d5f5a6714d31f499c8fd9db94 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Thu, 1 Sep 2022 13:54:28 +0300 Subject: [PATCH] feat: Implement new follower of me trigger for twitter --- .../client/endpoints/get-user-followers.ts | 70 +++++++++++++++++++ .../backend/src/apps/twitter/client/index.ts | 3 + packages/backend/src/apps/twitter/info.json | 15 ++++ packages/backend/src/apps/twitter/triggers.ts | 3 + .../src/apps/twitter/triggers/my-followers.ts | 28 ++++++++ 5 files changed, 119 insertions(+) create mode 100644 packages/backend/src/apps/twitter/client/endpoints/get-user-followers.ts create mode 100644 packages/backend/src/apps/twitter/triggers/my-followers.ts diff --git a/packages/backend/src/apps/twitter/client/endpoints/get-user-followers.ts b/packages/backend/src/apps/twitter/client/endpoints/get-user-followers.ts new file mode 100644 index 00000000..543a007f --- /dev/null +++ b/packages/backend/src/apps/twitter/client/endpoints/get-user-followers.ts @@ -0,0 +1,70 @@ +import { IJSONObject } from '@automatisch/types'; +import { URLSearchParams } from 'url'; +import TwitterClient from '../index'; +import omitBy from 'lodash/omitBy'; +import isEmpty from 'lodash/isEmpty'; + +export default class GetUserFollowers { + client: TwitterClient; + + constructor(client: TwitterClient) { + this.client = client; + } + + async run(userId: string, lastInternalId?: string) { + const token = { + key: this.client.connection.formattedData.accessToken as string, + secret: this.client.connection.formattedData.accessSecret as string, + }; + + 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/${userId}/followers${ + queryParams.toString() ? `?${queryParams.toString()}` : '' + }`; + + const requestData = { + url: `${TwitterClient.baseUrl}${requestPath}`, + method: 'GET', + }; + + const authHeader = this.client.oauthClient.toHeader( + this.client.oauthClient.authorize(requestData, token) + ); + + response = await this.client.httpClient.get(requestPath, { + headers: { ...authHeader }, + }); + + if (response.data.meta.result_count > 0) { + response.data.data.forEach((tweet: IJSONObject) => { + if (!lastInternalId || Number(tweet.id) > Number(lastInternalId)) { + followers.push(tweet); + } else { + return; + } + }); + } + } while (response.data.meta.next_token && 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; + } +} diff --git a/packages/backend/src/apps/twitter/client/index.ts b/packages/backend/src/apps/twitter/client/index.ts index f27e3f44..3cc3a72e 100644 --- a/packages/backend/src/apps/twitter/client/index.ts +++ b/packages/backend/src/apps/twitter/client/index.ts @@ -9,6 +9,7 @@ import GetUserByUsername from './endpoints/get-user-by-username'; import GetUserTweets from './endpoints/get-user-tweets'; import CreateTweet from './endpoints/create-tweet'; import SearchTweets from './endpoints/search-tweets'; +import GetUserFollowers from './endpoints/get-user-followers'; export default class TwitterClient { flow: IFlow; @@ -24,6 +25,7 @@ export default class TwitterClient { getUserTweets: GetUserTweets; createTweet: CreateTweet; searchTweets: SearchTweets; + getUserFollowers: GetUserFollowers; static baseUrl = 'https://api.twitter.com'; @@ -57,5 +59,6 @@ export default class TwitterClient { this.getUserTweets = new GetUserTweets(this); this.createTweet = new CreateTweet(this); this.searchTweets = new SearchTweets(this); + this.getUserFollowers = new GetUserFollowers(this); } } diff --git a/packages/backend/src/apps/twitter/info.json b/packages/backend/src/apps/twitter/info.json index 829c59ae..da657121 100644 --- a/packages/backend/src/apps/twitter/info.json +++ b/packages/backend/src/apps/twitter/info.json @@ -285,6 +285,21 @@ "name": "Test trigger" } ] + }, + { + "name": "New follower of me", + "key": "myFollowers", + "description": "Will be triggered when you have a new follower.", + "substeps": [ + { + "key": "chooseConnection", + "name": "Choose connection" + }, + { + "key": "testStep", + "name": "Test trigger" + } + ] } ], "actions": [ diff --git a/packages/backend/src/apps/twitter/triggers.ts b/packages/backend/src/apps/twitter/triggers.ts index 1575d012..2d611581 100644 --- a/packages/backend/src/apps/twitter/triggers.ts +++ b/packages/backend/src/apps/twitter/triggers.ts @@ -2,17 +2,20 @@ import TwitterClient from './client'; import UserTweets from './triggers/user-tweets'; import SearchTweets from './triggers/search-tweets'; import MyTweets from './triggers/my-tweets'; +import MyFollowers from './triggers/my-followers'; export default class Triggers { client: TwitterClient; userTweets: UserTweets; searchTweets: SearchTweets; myTweets: MyTweets; + myFollowers: MyFollowers; constructor(client: TwitterClient) { this.client = client; this.userTweets = new UserTweets(client); this.searchTweets = new SearchTweets(client); this.myTweets = new MyTweets(client); + this.myFollowers = new MyFollowers(client); } } diff --git a/packages/backend/src/apps/twitter/triggers/my-followers.ts b/packages/backend/src/apps/twitter/triggers/my-followers.ts new file mode 100644 index 00000000..8aaaba51 --- /dev/null +++ b/packages/backend/src/apps/twitter/triggers/my-followers.ts @@ -0,0 +1,28 @@ +import TwitterClient from '../client'; + +export default class MyFollowers { + client: TwitterClient; + + constructor(client: TwitterClient) { + this.client = client; + } + + async run(lastInternalId: string) { + return this.getFollowers(lastInternalId); + } + + async testRun() { + return this.getFollowers(); + } + + async getFollowers(lastInternalId?: string) { + const { username } = await this.client.getCurrentUser.run(); + const user = await this.client.getUserByUsername.run(username as string); + + const tweets = await this.client.getUserFollowers.run( + user.id, + lastInternalId + ); + return tweets; + } +}