@memberjunction/actions-bizapps-social 2.111.1 → 2.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +6 -6
- package/dist/base/base-social.action.d.ts.map +1 -1
- package/dist/base/base-social.action.js +18 -24
- package/dist/base/base-social.action.js.map +1 -1
- package/dist/providers/buffer/buffer-base.action.d.ts.map +1 -1
- package/dist/providers/buffer/buffer-base.action.js +35 -34
- package/dist/providers/buffer/buffer-base.action.js.map +1 -1
- package/dist/providers/facebook/actions/boost-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/boost-post.action.js +33 -33
- package/dist/providers/facebook/actions/boost-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/create-album.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/create-album.action.js +34 -36
- package/dist/providers/facebook/actions/create-album.action.js.map +1 -1
- package/dist/providers/facebook/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/create-post.action.js +20 -20
- package/dist/providers/facebook/actions/create-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-page-insights.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-page-insights.action.js +25 -27
- package/dist/providers/facebook/actions/get-page-insights.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-page-posts.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-page-posts.action.js +19 -23
- package/dist/providers/facebook/actions/get-page-posts.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-post-insights.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-post-insights.action.js +28 -32
- package/dist/providers/facebook/actions/get-post-insights.action.js.map +1 -1
- package/dist/providers/facebook/actions/respond-to-comments.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/respond-to-comments.action.js +42 -44
- package/dist/providers/facebook/actions/respond-to-comments.action.js.map +1 -1
- package/dist/providers/facebook/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/schedule-post.action.js +29 -29
- package/dist/providers/facebook/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/search-posts.action.js +37 -39
- package/dist/providers/facebook/actions/search-posts.action.js.map +1 -1
- package/dist/providers/facebook/facebook-base.action.d.ts.map +1 -1
- package/dist/providers/facebook/facebook-base.action.js +44 -59
- package/dist/providers/facebook/facebook-base.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js +33 -31
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.js +28 -32
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js +19 -19
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-analytics.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-analytics.action.js +24 -26
- package/dist/providers/hootsuite/actions/get-analytics.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js +22 -22
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-social-profiles.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-social-profiles.action.js +32 -34
- package/dist/providers/hootsuite/actions/get-social-profiles.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/search-posts.action.js +43 -52
- package/dist/providers/hootsuite/actions/search-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.js +30 -28
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/hootsuite-base.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/hootsuite-base.action.js +18 -20
- package/dist/providers/hootsuite/hootsuite-base.action.js.map +1 -1
- package/dist/providers/instagram/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/create-post.action.js +27 -26
- package/dist/providers/instagram/actions/create-post.action.js.map +1 -1
- package/dist/providers/instagram/actions/create-story.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/create-story.action.js +35 -35
- package/dist/providers/instagram/actions/create-story.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-account-insights.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-account-insights.action.js +38 -59
- package/dist/providers/instagram/actions/get-account-insights.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-business-posts.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-business-posts.action.js +29 -29
- package/dist/providers/instagram/actions/get-business-posts.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-comments.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-comments.action.js +36 -36
- package/dist/providers/instagram/actions/get-comments.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-post-insights.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-post-insights.action.js +23 -25
- package/dist/providers/instagram/actions/get-post-insights.action.js.map +1 -1
- package/dist/providers/instagram/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/schedule-post.action.js +25 -25
- package/dist/providers/instagram/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/instagram/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/search-posts.action.js +56 -60
- package/dist/providers/instagram/actions/search-posts.action.js.map +1 -1
- package/dist/providers/instagram/instagram-base.action.d.ts.map +1 -1
- package/dist/providers/instagram/instagram-base.action.js +25 -27
- package/dist/providers/instagram/instagram-base.action.js.map +1 -1
- package/dist/providers/linkedin/actions/create-article.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/create-article.action.js +55 -45
- package/dist/providers/linkedin/actions/create-article.action.js.map +1 -1
- package/dist/providers/linkedin/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/create-post.action.js +31 -29
- package/dist/providers/linkedin/actions/create-post.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-followers.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-followers.action.js +28 -28
- package/dist/providers/linkedin/actions/get-followers.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-organization-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-organization-posts.action.js +20 -20
- package/dist/providers/linkedin/actions/get-organization-posts.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-personal-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-personal-posts.action.js +19 -19
- package/dist/providers/linkedin/actions/get-personal-posts.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-post-analytics.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-post-analytics.action.js +25 -23
- package/dist/providers/linkedin/actions/get-post-analytics.action.js.map +1 -1
- package/dist/providers/linkedin/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/schedule-post.action.js +32 -30
- package/dist/providers/linkedin/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/linkedin/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/search-posts.action.js +28 -30
- package/dist/providers/linkedin/actions/search-posts.action.js.map +1 -1
- package/dist/providers/linkedin/linkedin-base.action.d.ts.map +1 -1
- package/dist/providers/linkedin/linkedin-base.action.js +33 -38
- package/dist/providers/linkedin/linkedin-base.action.js.map +1 -1
- package/dist/providers/tiktok/tiktok-base.action.d.ts.map +1 -1
- package/dist/providers/tiktok/tiktok-base.action.js +25 -26
- package/dist/providers/tiktok/tiktok-base.action.js.map +1 -1
- package/dist/providers/twitter/actions/create-thread.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/create-thread.action.js +25 -29
- package/dist/providers/twitter/actions/create-thread.action.js.map +1 -1
- package/dist/providers/twitter/actions/create-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/create-tweet.action.js +23 -23
- package/dist/providers/twitter/actions/create-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/delete-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/delete-tweet.action.js +19 -19
- package/dist/providers/twitter/actions/delete-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-analytics.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-analytics.action.js +40 -47
- package/dist/providers/twitter/actions/get-analytics.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-mentions.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-mentions.action.js +30 -31
- package/dist/providers/twitter/actions/get-mentions.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-timeline.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-timeline.action.js +29 -29
- package/dist/providers/twitter/actions/get-timeline.action.js.map +1 -1
- package/dist/providers/twitter/actions/schedule-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/schedule-tweet.action.js +26 -26
- package/dist/providers/twitter/actions/schedule-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/search-tweets.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/search-tweets.action.js +56 -58
- package/dist/providers/twitter/actions/search-tweets.action.js.map +1 -1
- package/dist/providers/twitter/twitter-base.action.d.ts.map +1 -1
- package/dist/providers/twitter/twitter-base.action.js +58 -68
- package/dist/providers/twitter/twitter-base.action.js.map +1 -1
- package/dist/providers/youtube/youtube-base.action.d.ts +1 -1
- package/dist/providers/youtube/youtube-base.action.d.ts.map +1 -1
- package/dist/providers/youtube/youtube-base.action.js +22 -25
- package/dist/providers/youtube/youtube-base.action.js.map +1 -1
- package/package.json +5 -6
- package/src/base/base-social.action.ts +217 -224
- package/src/providers/buffer/buffer-base.action.ts +435 -441
- package/src/providers/facebook/actions/boost-post.action.ts +350 -386
- package/src/providers/facebook/actions/create-album.action.ts +291 -307
- package/src/providers/facebook/actions/create-post.action.ts +224 -227
- package/src/providers/facebook/actions/get-page-insights.action.ts +383 -403
- package/src/providers/facebook/actions/get-page-posts.action.ts +214 -225
- package/src/providers/facebook/actions/get-post-insights.action.ts +300 -316
- package/src/providers/facebook/actions/respond-to-comments.action.ts +319 -336
- package/src/providers/facebook/actions/schedule-post.action.ts +289 -292
- package/src/providers/facebook/actions/search-posts.action.ts +399 -413
- package/src/providers/facebook/facebook-base.action.ts +653 -670
- package/src/providers/hootsuite/actions/bulk-schedule-posts.action.ts +257 -257
- package/src/providers/hootsuite/actions/create-scheduled-post.action.ts +184 -189
- package/src/providers/hootsuite/actions/delete-scheduled-post.action.ts +160 -161
- package/src/providers/hootsuite/actions/get-analytics.action.ts +249 -254
- package/src/providers/hootsuite/actions/get-scheduled-posts.action.ts +206 -207
- package/src/providers/hootsuite/actions/get-social-profiles.action.ts +206 -205
- package/src/providers/hootsuite/actions/search-posts.action.ts +351 -369
- package/src/providers/hootsuite/actions/update-scheduled-post.action.ts +211 -209
- package/src/providers/hootsuite/hootsuite-base.action.ts +301 -307
- package/src/providers/instagram/actions/create-post.action.ts +276 -296
- package/src/providers/instagram/actions/create-story.action.ts +378 -394
- package/src/providers/instagram/actions/get-account-insights.action.ts +384 -420
- package/src/providers/instagram/actions/get-business-posts.action.ts +233 -242
- package/src/providers/instagram/actions/get-comments.action.ts +365 -377
- package/src/providers/instagram/actions/get-post-insights.action.ts +265 -273
- package/src/providers/instagram/actions/schedule-post.action.ts +233 -235
- package/src/providers/instagram/actions/search-posts.action.ts +512 -538
- package/src/providers/instagram/instagram-base.action.ts +368 -393
- package/src/providers/linkedin/actions/create-article.action.ts +275 -266
- package/src/providers/linkedin/actions/create-post.action.ts +179 -177
- package/src/providers/linkedin/actions/get-followers.action.ts +211 -211
- package/src/providers/linkedin/actions/get-organization-posts.action.ts +146 -147
- package/src/providers/linkedin/actions/get-personal-posts.action.ts +138 -139
- package/src/providers/linkedin/actions/get-post-analytics.action.ts +190 -189
- package/src/providers/linkedin/actions/schedule-post.action.ts +191 -189
- package/src/providers/linkedin/actions/search-posts.action.ts +275 -283
- package/src/providers/linkedin/linkedin-base.action.ts +407 -421
- package/src/providers/tiktok/tiktok-base.action.ts +305 -320
- package/src/providers/twitter/actions/create-thread.action.ts +203 -207
- package/src/providers/twitter/actions/create-tweet.action.ts +187 -188
- package/src/providers/twitter/actions/delete-tweet.action.ts +128 -129
- package/src/providers/twitter/actions/get-analytics.action.ts +402 -411
- package/src/providers/twitter/actions/get-mentions.action.ts +218 -219
- package/src/providers/twitter/actions/get-timeline.action.ts +232 -233
- package/src/providers/twitter/actions/schedule-tweet.action.ts +221 -222
- package/src/providers/twitter/actions/search-tweets.action.ts +540 -543
- package/src/providers/twitter/twitter-base.action.ts +541 -560
- package/src/providers/youtube/youtube-base.action.ts +320 -333
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RegisterClass } from '@memberjunction/global';
|
|
2
2
|
import { TwitterBaseAction, CreateTweetData } from '../twitter-base.action';
|
|
3
3
|
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
|
|
4
|
-
import { LogStatus, LogError } from '@memberjunction/
|
|
4
|
+
import { LogStatus, LogError } from '@memberjunction/global';
|
|
5
5
|
import { MediaFile } from '../../../base/base-social.action';
|
|
6
6
|
import { BaseAction } from '@memberjunction/actions';
|
|
7
7
|
|
|
@@ -10,196 +10,195 @@ import { BaseAction } from '@memberjunction/actions';
|
|
|
10
10
|
*/
|
|
11
11
|
@RegisterClass(BaseAction, 'TwitterCreateTweetAction')
|
|
12
12
|
export class TwitterCreateTweetAction extends TwitterBaseAction {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Validate poll option lengths (max 25 characters each)
|
|
68
|
-
for (const option of pollOptions) {
|
|
69
|
-
if (option.length > 25) {
|
|
70
|
-
throw new Error(`Poll option "${option}" exceeds 25 character limit`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
tweetData.poll = {
|
|
75
|
-
options: pollOptions,
|
|
76
|
-
duration_minutes: Math.min(Math.max(pollDurationMinutes, 5), 10080) // Min 5 minutes, max 7 days
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Upload media if provided
|
|
81
|
-
if (mediaFiles && Array.isArray(mediaFiles) && mediaFiles.length > 0) {
|
|
82
|
-
if (mediaFiles.length > 4) {
|
|
83
|
-
throw new Error('Twitter supports a maximum of 4 media items per tweet');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
LogStatus(`Uploading ${mediaFiles.length} media files...`);
|
|
87
|
-
const mediaIds = await this.uploadMedia(mediaFiles as MediaFile[]);
|
|
88
|
-
|
|
89
|
-
tweetData.media = {
|
|
90
|
-
media_ids: mediaIds
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Create the tweet
|
|
95
|
-
LogStatus('Creating tweet...');
|
|
96
|
-
const tweet = await this.createTweet(tweetData);
|
|
97
|
-
|
|
98
|
-
// Normalize the created tweet
|
|
99
|
-
const normalizedPost = this.normalizePost(tweet);
|
|
100
|
-
|
|
101
|
-
// Get user info for additional context
|
|
102
|
-
const user = await this.getCurrentUser();
|
|
103
|
-
|
|
104
|
-
// Update output parameters
|
|
105
|
-
const outputParams = [...Params];
|
|
106
|
-
const postParam = outputParams.find(p => p.Name === 'CreatedPost');
|
|
107
|
-
if (postParam) postParam.Value = normalizedPost;
|
|
108
|
-
const tweetIdParam = outputParams.find(p => p.Name === 'TweetID');
|
|
109
|
-
if (tweetIdParam) tweetIdParam.Value = tweet.id;
|
|
110
|
-
const tweetUrlParam = outputParams.find(p => p.Name === 'TweetURL');
|
|
111
|
-
if (tweetUrlParam) tweetUrlParam.Value = `https://twitter.com/${user.username}/status/${tweet.id}`;
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
Success: true,
|
|
115
|
-
ResultCode: 'SUCCESS',
|
|
116
|
-
Message: `Successfully created tweet (ID: ${tweet.id})`,
|
|
117
|
-
Params: outputParams
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
} catch (error) {
|
|
121
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
Success: false,
|
|
125
|
-
ResultCode: this.getErrorCode(error),
|
|
126
|
-
Message: `Failed to create tweet: ${errorMessage}`,
|
|
127
|
-
Params
|
|
128
|
-
};
|
|
13
|
+
/**
|
|
14
|
+
* Create a tweet on Twitter
|
|
15
|
+
*/
|
|
16
|
+
protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
|
|
17
|
+
const { Params, ContextUser } = params;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Initialize OAuth
|
|
21
|
+
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
|
|
22
|
+
if (!(await this.initializeOAuth(companyIntegrationId))) {
|
|
23
|
+
throw new Error('Failed to initialize OAuth connection');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Extract parameters
|
|
27
|
+
const content = this.getParamValue(Params, 'Content');
|
|
28
|
+
const mediaFiles = this.getParamValue(Params, 'MediaFiles');
|
|
29
|
+
const replyToTweetId = this.getParamValue(Params, 'ReplyToTweetID');
|
|
30
|
+
const quoteTweetId = this.getParamValue(Params, 'QuoteTweetID');
|
|
31
|
+
const pollOptions = this.getParamValue(Params, 'PollOptions');
|
|
32
|
+
const pollDurationMinutes = this.getParamValue(Params, 'PollDurationMinutes') || 1440; // Default 24 hours
|
|
33
|
+
|
|
34
|
+
// Validate required parameters
|
|
35
|
+
if (!content) {
|
|
36
|
+
throw new Error('Content is required');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Validate content length (Twitter's limit is 280 characters)
|
|
40
|
+
if (content.length > 280) {
|
|
41
|
+
throw new Error(`Content exceeds Twitter's 280 character limit (current: ${content.length} characters)`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Build tweet data
|
|
45
|
+
const tweetData: CreateTweetData = {
|
|
46
|
+
text: content,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Add reply if specified
|
|
50
|
+
if (replyToTweetId) {
|
|
51
|
+
tweetData.reply = {
|
|
52
|
+
in_reply_to_tweet_id: replyToTweetId,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Add quote tweet if specified
|
|
57
|
+
if (quoteTweetId) {
|
|
58
|
+
tweetData.quote_tweet_id = quoteTweetId;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add poll if specified
|
|
62
|
+
if (pollOptions && Array.isArray(pollOptions) && pollOptions.length >= 2) {
|
|
63
|
+
if (pollOptions.length > 4) {
|
|
64
|
+
throw new Error('Twitter polls support a maximum of 4 options');
|
|
129
65
|
}
|
|
130
|
-
}
|
|
131
66
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (error.message.includes('Rate Limit')) return 'RATE_LIMIT';
|
|
138
|
-
if (error.message.includes('Unauthorized')) return 'INVALID_TOKEN';
|
|
139
|
-
if (error.message.includes('character limit')) return 'CONTENT_TOO_LONG';
|
|
140
|
-
if (error.message.includes('media')) return 'INVALID_MEDIA';
|
|
67
|
+
// Validate poll option lengths (max 25 characters each)
|
|
68
|
+
for (const option of pollOptions) {
|
|
69
|
+
if (option.length > 25) {
|
|
70
|
+
throw new Error(`Poll option "${option}" exceeds 25 character limit`);
|
|
71
|
+
}
|
|
141
72
|
}
|
|
142
|
-
return 'ERROR';
|
|
143
|
-
}
|
|
144
73
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
...this.commonSocialParams,
|
|
151
|
-
{
|
|
152
|
-
Name: 'Content',
|
|
153
|
-
Type: 'Input',
|
|
154
|
-
Value: null
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
Name: 'MediaFiles',
|
|
158
|
-
Type: 'Input',
|
|
159
|
-
Value: null
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
Name: 'ReplyToTweetID',
|
|
163
|
-
Type: 'Input',
|
|
164
|
-
Value: null
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
Name: 'QuoteTweetID',
|
|
168
|
-
Type: 'Input',
|
|
169
|
-
Value: null
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
Name: 'PollOptions',
|
|
173
|
-
Type: 'Input',
|
|
174
|
-
Value: null
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
Name: 'PollDurationMinutes',
|
|
178
|
-
Type: 'Input',
|
|
179
|
-
Value: 1440 // Default 24 hours
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
Name: 'CreatedPost',
|
|
183
|
-
Type: 'Output',
|
|
184
|
-
Value: null
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
Name: 'TweetID',
|
|
188
|
-
Type: 'Output',
|
|
189
|
-
Value: null
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
Name: 'TweetURL',
|
|
193
|
-
Type: 'Output',
|
|
194
|
-
Value: null
|
|
195
|
-
}
|
|
196
|
-
];
|
|
197
|
-
}
|
|
74
|
+
tweetData.poll = {
|
|
75
|
+
options: pollOptions,
|
|
76
|
+
duration_minutes: Math.min(Math.max(pollDurationMinutes, 5), 10080), // Min 5 minutes, max 7 days
|
|
77
|
+
};
|
|
78
|
+
}
|
|
198
79
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
80
|
+
// Upload media if provided
|
|
81
|
+
if (mediaFiles && Array.isArray(mediaFiles) && mediaFiles.length > 0) {
|
|
82
|
+
if (mediaFiles.length > 4) {
|
|
83
|
+
throw new Error('Twitter supports a maximum of 4 media items per tweet');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
LogStatus(`Uploading ${mediaFiles.length} media files...`);
|
|
87
|
+
const mediaIds = await this.uploadMedia(mediaFiles as MediaFile[]);
|
|
88
|
+
|
|
89
|
+
tweetData.media = {
|
|
90
|
+
media_ids: mediaIds,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Create the tweet
|
|
95
|
+
LogStatus('Creating tweet...');
|
|
96
|
+
const tweet = await this.createTweet(tweetData);
|
|
97
|
+
|
|
98
|
+
// Normalize the created tweet
|
|
99
|
+
const normalizedPost = this.normalizePost(tweet);
|
|
100
|
+
|
|
101
|
+
// Get user info for additional context
|
|
102
|
+
const user = await this.getCurrentUser();
|
|
103
|
+
|
|
104
|
+
// Update output parameters
|
|
105
|
+
const outputParams = [...Params];
|
|
106
|
+
const postParam = outputParams.find((p) => p.Name === 'CreatedPost');
|
|
107
|
+
if (postParam) postParam.Value = normalizedPost;
|
|
108
|
+
const tweetIdParam = outputParams.find((p) => p.Name === 'TweetID');
|
|
109
|
+
if (tweetIdParam) tweetIdParam.Value = tweet.id;
|
|
110
|
+
const tweetUrlParam = outputParams.find((p) => p.Name === 'TweetURL');
|
|
111
|
+
if (tweetUrlParam) tweetUrlParam.Value = `https://twitter.com/${user.username}/status/${tweet.id}`;
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
Success: true,
|
|
115
|
+
ResultCode: 'SUCCESS',
|
|
116
|
+
Message: `Successfully created tweet (ID: ${tweet.id})`,
|
|
117
|
+
Params: outputParams,
|
|
118
|
+
};
|
|
119
|
+
} catch (error) {
|
|
120
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
Success: false,
|
|
124
|
+
ResultCode: this.getErrorCode(error),
|
|
125
|
+
Message: `Failed to create tweet: ${errorMessage}`,
|
|
126
|
+
Params,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get error code based on error type
|
|
133
|
+
*/
|
|
134
|
+
private getErrorCode(error: any): string {
|
|
135
|
+
if (error instanceof Error) {
|
|
136
|
+
if (error.message.includes('Rate Limit')) return 'RATE_LIMIT';
|
|
137
|
+
if (error.message.includes('Unauthorized')) return 'INVALID_TOKEN';
|
|
138
|
+
if (error.message.includes('character limit')) return 'CONTENT_TOO_LONG';
|
|
139
|
+
if (error.message.includes('media')) return 'INVALID_MEDIA';
|
|
204
140
|
}
|
|
205
|
-
|
|
141
|
+
return 'ERROR';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Define the parameters this action expects
|
|
146
|
+
*/
|
|
147
|
+
public get Params(): ActionParam[] {
|
|
148
|
+
return [
|
|
149
|
+
...this.commonSocialParams,
|
|
150
|
+
{
|
|
151
|
+
Name: 'Content',
|
|
152
|
+
Type: 'Input',
|
|
153
|
+
Value: null,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
Name: 'MediaFiles',
|
|
157
|
+
Type: 'Input',
|
|
158
|
+
Value: null,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
Name: 'ReplyToTweetID',
|
|
162
|
+
Type: 'Input',
|
|
163
|
+
Value: null,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
Name: 'QuoteTweetID',
|
|
167
|
+
Type: 'Input',
|
|
168
|
+
Value: null,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
Name: 'PollOptions',
|
|
172
|
+
Type: 'Input',
|
|
173
|
+
Value: null,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
Name: 'PollDurationMinutes',
|
|
177
|
+
Type: 'Input',
|
|
178
|
+
Value: 1440, // Default 24 hours
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
Name: 'CreatedPost',
|
|
182
|
+
Type: 'Output',
|
|
183
|
+
Value: null,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
Name: 'TweetID',
|
|
187
|
+
Type: 'Output',
|
|
188
|
+
Value: null,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
Name: 'TweetURL',
|
|
192
|
+
Type: 'Output',
|
|
193
|
+
Value: null,
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get action description
|
|
200
|
+
*/
|
|
201
|
+
public get Description(): string {
|
|
202
|
+
return 'Creates a tweet on Twitter/X with optional media attachments, polls, replies, or quote tweets';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RegisterClass } from '@memberjunction/global';
|
|
2
2
|
import { TwitterBaseAction } from '../twitter-base.action';
|
|
3
3
|
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
|
|
4
|
-
import { LogStatus, LogError } from '@memberjunction/
|
|
4
|
+
import { LogStatus, LogError } from '@memberjunction/global';
|
|
5
5
|
import { BaseAction } from '@memberjunction/actions';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -9,146 +9,145 @@ import { BaseAction } from '@memberjunction/actions';
|
|
|
9
9
|
*/
|
|
10
10
|
@RegisterClass(BaseAction, 'TwitterDeleteTweetAction')
|
|
11
11
|
export class TwitterDeleteTweetAction extends TwitterBaseAction {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
// Initialize OAuth
|
|
20
|
-
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
|
|
21
|
-
if (!await this.initializeOAuth(companyIntegrationId)) {
|
|
22
|
-
throw new Error('Failed to initialize OAuth connection');
|
|
23
|
-
}
|
|
12
|
+
/**
|
|
13
|
+
* Delete a tweet from Twitter
|
|
14
|
+
*/
|
|
15
|
+
protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
|
|
16
|
+
const { Params, ContextUser } = params;
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
try {
|
|
19
|
+
// Initialize OAuth
|
|
20
|
+
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
|
|
21
|
+
if (!(await this.initializeOAuth(companyIntegrationId))) {
|
|
22
|
+
throw new Error('Failed to initialize OAuth connection');
|
|
23
|
+
}
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
25
|
+
// Extract parameters
|
|
26
|
+
const tweetId = this.getParamValue(Params, 'TweetID');
|
|
27
|
+
const confirmDeletion = this.getParamValue(Params, 'ConfirmDeletion') === true;
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ResultCode: 'CONFIRMATION_REQUIRED',
|
|
39
|
-
Message: 'Tweet deletion requires explicit confirmation. Set ConfirmDeletion to true.',
|
|
40
|
-
Params
|
|
41
|
-
};
|
|
42
|
-
}
|
|
29
|
+
// Validate required parameters
|
|
30
|
+
if (!tweetId) {
|
|
31
|
+
throw new Error('TweetID is required');
|
|
32
|
+
}
|
|
43
33
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
});
|
|
34
|
+
// Safety check - require explicit confirmation
|
|
35
|
+
if (!confirmDeletion) {
|
|
36
|
+
return {
|
|
37
|
+
Success: false,
|
|
38
|
+
ResultCode: 'CONFIRMATION_REQUIRED',
|
|
39
|
+
Message: 'Tweet deletion requires explicit confirmation. Set ConfirmDeletion to true.',
|
|
40
|
+
Params,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
55
43
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
44
|
+
// Get the tweet details before deletion (for output)
|
|
45
|
+
let tweetDetails: any = null;
|
|
46
|
+
try {
|
|
47
|
+
LogStatus(`Retrieving tweet details for ID: ${tweetId}...`);
|
|
48
|
+
const response = await this.axiosInstance.get(`/tweets/${tweetId}`, {
|
|
49
|
+
params: {
|
|
50
|
+
'tweet.fields': 'id,text,created_at,author_id,public_metrics',
|
|
51
|
+
expansions: 'author_id',
|
|
52
|
+
'user.fields': 'id,username',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
63
55
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// If we can't retrieve the tweet, it might already be deleted or we don't have access
|
|
72
|
-
LogStatus('Could not retrieve tweet details. It may already be deleted or inaccessible.');
|
|
73
|
-
}
|
|
56
|
+
if (response.data.data) {
|
|
57
|
+
tweetDetails = {
|
|
58
|
+
id: response.data.data.id,
|
|
59
|
+
text: response.data.data.text,
|
|
60
|
+
createdAt: response.data.data.created_at,
|
|
61
|
+
metrics: response.data.data.public_metrics,
|
|
62
|
+
};
|
|
74
63
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
// Verify ownership
|
|
65
|
+
const currentUser = await this.getCurrentUser();
|
|
66
|
+
if (response.data.data.author_id !== currentUser.id) {
|
|
67
|
+
throw new Error('You can only delete your own tweets');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// If we can't retrieve the tweet, it might already be deleted or we don't have access
|
|
72
|
+
LogStatus('Could not retrieve tweet details. It may already be deleted or inaccessible.');
|
|
73
|
+
}
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (deletedDetailsParam && tweetDetails) deletedDetailsParam.Value = tweetDetails;
|
|
83
|
-
const deletionTimeParam = outputParams.find(p => p.Name === 'DeletionTime');
|
|
84
|
-
if (deletionTimeParam) deletionTimeParam.Value = new Date().toISOString();
|
|
75
|
+
// Delete the tweet
|
|
76
|
+
LogStatus(`Deleting tweet ID: ${tweetId}...`);
|
|
77
|
+
await this.deleteTweet(tweetId);
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
79
|
+
// Update output parameters
|
|
80
|
+
const outputParams = [...Params];
|
|
81
|
+
const deletedDetailsParam = outputParams.find((p) => p.Name === 'DeletedTweetDetails');
|
|
82
|
+
if (deletedDetailsParam && tweetDetails) deletedDetailsParam.Value = tweetDetails;
|
|
83
|
+
const deletionTimeParam = outputParams.find((p) => p.Name === 'DeletionTime');
|
|
84
|
+
if (deletionTimeParam) deletionTimeParam.Value = new Date().toISOString();
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
86
|
+
return {
|
|
87
|
+
Success: true,
|
|
88
|
+
ResultCode: 'SUCCESS',
|
|
89
|
+
Message: `Successfully deleted tweet (ID: ${tweetId})`,
|
|
90
|
+
Params: outputParams,
|
|
91
|
+
};
|
|
92
|
+
} catch (error) {
|
|
93
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
104
94
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (error.message.includes('Unauthorized')) return 'INVALID_TOKEN';
|
|
112
|
-
if (error.message.includes('Not Found')) return 'TWEET_NOT_FOUND';
|
|
113
|
-
if (error.message.includes('Forbidden')) return 'INSUFFICIENT_PERMISSIONS';
|
|
114
|
-
if (error.message.includes('own tweets')) return 'NOT_OWNER';
|
|
115
|
-
}
|
|
116
|
-
return 'ERROR';
|
|
95
|
+
return {
|
|
96
|
+
Success: false,
|
|
97
|
+
ResultCode: this.getErrorCode(error),
|
|
98
|
+
Message: `Failed to delete tweet: ${errorMessage}`,
|
|
99
|
+
Params,
|
|
100
|
+
};
|
|
117
101
|
}
|
|
102
|
+
}
|
|
118
103
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
Name: 'ConfirmDeletion',
|
|
132
|
-
Type: 'Input',
|
|
133
|
-
Value: false
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
Name: 'DeletedTweetDetails',
|
|
137
|
-
Type: 'Output',
|
|
138
|
-
Value: null
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
Name: 'DeletionTime',
|
|
142
|
-
Type: 'Output',
|
|
143
|
-
Value: null
|
|
144
|
-
}
|
|
145
|
-
];
|
|
104
|
+
/**
|
|
105
|
+
* Get error code based on error type
|
|
106
|
+
*/
|
|
107
|
+
private getErrorCode(error: any): string {
|
|
108
|
+
if (error instanceof Error) {
|
|
109
|
+
if (error.message.includes('Rate Limit')) return 'RATE_LIMIT';
|
|
110
|
+
if (error.message.includes('Unauthorized')) return 'INVALID_TOKEN';
|
|
111
|
+
if (error.message.includes('Not Found')) return 'TWEET_NOT_FOUND';
|
|
112
|
+
if (error.message.includes('Forbidden')) return 'INSUFFICIENT_PERMISSIONS';
|
|
113
|
+
if (error.message.includes('own tweets')) return 'NOT_OWNER';
|
|
146
114
|
}
|
|
115
|
+
return 'ERROR';
|
|
116
|
+
}
|
|
147
117
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Define the parameters this action expects
|
|
120
|
+
*/
|
|
121
|
+
public get Params(): ActionParam[] {
|
|
122
|
+
return [
|
|
123
|
+
...this.commonSocialParams,
|
|
124
|
+
{
|
|
125
|
+
Name: 'TweetID',
|
|
126
|
+
Type: 'Input',
|
|
127
|
+
Value: null,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
Name: 'ConfirmDeletion',
|
|
131
|
+
Type: 'Input',
|
|
132
|
+
Value: false,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
Name: 'DeletedTweetDetails',
|
|
136
|
+
Type: 'Output',
|
|
137
|
+
Value: null,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
Name: 'DeletionTime',
|
|
141
|
+
Type: 'Output',
|
|
142
|
+
Value: null,
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get action description
|
|
149
|
+
*/
|
|
150
|
+
public get Description(): string {
|
|
151
|
+
return 'Deletes a tweet from Twitter/X. Requires explicit confirmation and ownership of the tweet.';
|
|
152
|
+
}
|
|
153
|
+
}
|