Passed
Push — main ( 4fdb7e...2b3a63 )
by Ehsan
04:33
created

Search.processTweets   B

Complexity

Conditions 5

Size

Total Lines 21
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 19
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 5
rs 8.9833
c 0
b 0
f 0
1
import Twit from 'twit';
2 3
import Helper from '../Helper';
3 3
import Tweet from '../entities/Tweet';
4 3
import {AbstractAction, runArgs} from './Action';
5
6
interface runSearchArgs extends runArgs {
7
    searchParams: Twit.Params
8
}
9
10 3
export default class Search extends AbstractAction {
11
    async run(args: runSearchArgs): Promise<void> {
12 9
        const tweets = await this.search(args.searchParams);
13
14 6
        if (!Helper.objectExists(tweets) || tweets.length === 0) {
15 1
            this.debug('Found no tweets.');
16 1
            return;
17
        }
18
19 5
        this.debug(`Found '${tweets.length}' tweet(s).`);
20
21 5
        await this.processTweets(args, tweets);
22
    }
23
24
    private async search(searchParams: Twit.Params): Promise<Tweet[]> {
25 9
        this.debug('Searching recent tweets with the following params ...');
26 9
        this.debug(searchParams);
27
28 9
        const result = await this.twit.get('search/tweets', searchParams);
29
30 8
        if (result.resp.statusCode === 200 && Helper.objectExists(result.data)) {
31 6
            this.debug('Search successfully completed!');
32
33 6
            const statuses = (result.data as Twit.Twitter.SearchResults).statuses;
34
35 6
            return this.toTweets(statuses);
36
        } else {
37 2
            this.debug('Cannot search recent tweets.');
38 2
            if (Helper.objectExists(result.resp.statusMessage)) {
39 1
                this.debug(result.resp.statusMessage);
40
            }
41
42 2
            throw new Error('Cannot search recent tweets');
43
        }
44
    }
45
46
    private async searchRetweetedTweets(): Promise<Tweet[]> {
47 5
        this.debug(`Searching recent retweets by user: '${this.config.screenName}' ...`);
48
49 5
        const result = await this.twit.get('statuses/user_timeline', {
50
            screen_name: this.config.screenName,
51
            // max allowed is 200
52
            count: 200,
53
            exclude_replies: true,
54
            include_rts: true
55
        });
56
57 5
        if (result.resp.statusCode === 200 && Helper.objectExists(result.data)) {
58 3
            const recentTweets = result.data as Twit.Twitter.Status[];
59
60 3
            const retweets = this.toTweets(recentTweets, true);
61 3
            this.debug(`Found '${retweets.length}' retweet(s).`);
62
63 3
            return retweets;
64
        } else {
65 2
            this.debug('Cannot search recent retweets.');
66 2
            if (Helper.objectExists(result.resp.statusMessage)) {
67 1
                this.debug(result.resp.statusMessage);
68
            }
69
70 2
            throw new Error('Cannot search recent retweets');
71
        }
72
    }
73
74
    private async processTweets(args: runSearchArgs, tweets: Tweet[]): Promise<void> {
75 5
        const retweetedTweets = await this.searchRetweetedTweets();
76
77 3
        let count = 0;
78 3
        for (const tweet of tweets) {
79 4
            count++;
80
81 4
            if (!tweet.isReTweetable()) {
82 1
                this.debug(`${count}. Tweet with id: '${tweet.rawTweet.id_str}' is not retweetable because: ${tweet.retweetError}.`);
83 1
                continue;
84
            }
85
86 3
            this.debug(`${count}. Tweet with id: '${tweet.rawTweet.id_str}' may be retweeted!`);
87
88 3
            if (this.hasAlreadyReTweeted(retweetedTweets, tweet)) {
89 1
                continue;
90
            }
91
92 2
            if (args.onSuccess) {
93 1
                await args.onSuccess(tweet);
94
            }
95
        }
96
    }
97
98
    private hasAlreadyReTweeted(retweetedTweets: Tweet[], tweet: Tweet): boolean {
99 3
        this.debug(`Checking to see if tweet with id: '${tweet.rawTweet.id_str}' has been already retweeted ...`);
100
101 3
        for (const recentTweet of retweetedTweets) {
102 4
            if (recentTweet.rawTweet.retweeted_status && recentTweet.rawTweet.retweeted_status.id_str === tweet.rawTweet.id_str) {
103 1
                this.debug(`Tweet with id: '${tweet.rawTweet.id_str}' has been already tweeted.`);
104 1
                return true;
105
            }
106
        }
107
108 2
        this.debug(`Tweet with id: '${tweet.rawTweet.id_str}' has NOT been tweeted.`);
109
110 2
        return false;
111
    }
112
113
    private toTweets(statuses: Twit.Twitter.Status[], onlyRetweets = false): Tweet[] {
114 9
        const tweets: Tweet[] = [];
115
116
        let tweet: Tweet;
117 9
        for (const status of statuses) {
118 9
            tweet = new Tweet(status, this.config.tweetConfig);
119
120 9
            if (onlyRetweets && !tweet.isRetweet()) {
121 1
                continue;
122
            }
123
124 8
            tweets.push(tweet);
125
        }
126
127 9
        return tweets;
128
    }
129
}