@memberjunction/actions-bizapps-social 2.111.0 → 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 { HootSuiteBaseAction, HootSuitePost } from '../hootsuite-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
|
|
|
@@ -9,12 +9,12 @@ import { BaseAction } from '@memberjunction/actions';
|
|
|
9
9
|
* Interface for bulk post data
|
|
10
10
|
*/
|
|
11
11
|
interface BulkPostData {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
content: string;
|
|
13
|
+
scheduledTime?: string;
|
|
14
|
+
profileIds?: string[];
|
|
15
|
+
mediaFiles?: MediaFile[];
|
|
16
|
+
tags?: string[];
|
|
17
|
+
location?: { latitude: number; longitude: number };
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -22,273 +22,273 @@ interface BulkPostData {
|
|
|
22
22
|
*/
|
|
23
23
|
@RegisterClass(BaseAction, 'HootSuiteBulkSchedulePostsAction')
|
|
24
24
|
export class HootSuiteBulkSchedulePostsAction extends HootSuiteBaseAction {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Bulk schedule posts in HootSuite
|
|
27
|
+
*/
|
|
28
|
+
protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
|
|
29
|
+
const { Params, ContextUser } = params;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Initialize OAuth
|
|
33
|
+
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
|
|
34
|
+
if (!(await this.initializeOAuth(companyIntegrationId))) {
|
|
35
|
+
throw new Error('Failed to initialize OAuth connection');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Extract parameters
|
|
39
|
+
const posts = this.getParamValue(Params, 'Posts') as BulkPostData[];
|
|
40
|
+
const defaultProfileIds = this.getParamValue(Params, 'DefaultProfileIDs');
|
|
41
|
+
const scheduleInterval = this.getParamValue(Params, 'ScheduleInterval');
|
|
42
|
+
const startTime = this.getParamValue(Params, 'StartTime');
|
|
43
|
+
const skipOnError = this.getParamValue(Params, 'SkipOnError') || true;
|
|
44
|
+
const validateOnly = this.getParamValue(Params, 'ValidateOnly') || false;
|
|
45
|
+
|
|
46
|
+
// Validate required parameters
|
|
47
|
+
if (!posts || !Array.isArray(posts) || posts.length === 0) {
|
|
48
|
+
throw new Error('Posts array is required and must not be empty');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get default profiles if not specified
|
|
52
|
+
let defaultProfiles: string[] = [];
|
|
53
|
+
if (defaultProfileIds && Array.isArray(defaultProfileIds)) {
|
|
54
|
+
defaultProfiles = defaultProfileIds;
|
|
55
|
+
} else if (defaultProfileIds && typeof defaultProfileIds === 'string') {
|
|
56
|
+
defaultProfiles = [defaultProfileIds];
|
|
57
|
+
} else {
|
|
58
|
+
// Get all available profiles as default
|
|
59
|
+
const profiles = await this.getSocialProfiles();
|
|
60
|
+
if (profiles.length === 0) {
|
|
61
|
+
throw new Error('No social profiles found. Please specify DefaultProfileIDs.');
|
|
62
|
+
}
|
|
63
|
+
defaultProfiles = profiles.map((p) => p.id);
|
|
64
|
+
LogStatus(`Using ${defaultProfiles.length} default profiles`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Calculate schedule times if interval is specified
|
|
68
|
+
let baseScheduleTime: Date | null = null;
|
|
69
|
+
if (scheduleInterval && startTime) {
|
|
70
|
+
baseScheduleTime = new Date(startTime);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Process posts
|
|
74
|
+
const results: any[] = [];
|
|
75
|
+
const errors: any[] = [];
|
|
76
|
+
let successCount = 0;
|
|
77
|
+
let failureCount = 0;
|
|
78
|
+
|
|
79
|
+
LogStatus(`Processing ${posts.length} posts for bulk scheduling...`);
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < posts.length; i++) {
|
|
82
|
+
const post = posts[i];
|
|
83
|
+
const postIndex = i + 1;
|
|
84
|
+
|
|
31
85
|
try {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (!await this.initializeOAuth(companyIntegrationId)) {
|
|
35
|
-
throw new Error('Failed to initialize OAuth connection');
|
|
36
|
-
}
|
|
86
|
+
// Validate post data
|
|
87
|
+
this.validateBulkPost(post, postIndex);
|
|
37
88
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// Validate required parameters
|
|
47
|
-
if (!posts || !Array.isArray(posts) || posts.length === 0) {
|
|
48
|
-
throw new Error('Posts array is required and must not be empty');
|
|
49
|
-
}
|
|
89
|
+
// Calculate scheduled time for this post
|
|
90
|
+
let scheduledTime = post.scheduledTime;
|
|
91
|
+
if (!scheduledTime && baseScheduleTime && scheduleInterval) {
|
|
92
|
+
const offsetMinutes = i * scheduleInterval;
|
|
93
|
+
const postScheduleTime = new Date(baseScheduleTime);
|
|
94
|
+
postScheduleTime.setMinutes(postScheduleTime.getMinutes() + offsetMinutes);
|
|
95
|
+
scheduledTime = postScheduleTime.toISOString();
|
|
96
|
+
}
|
|
50
97
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (defaultProfileIds && Array.isArray(defaultProfileIds)) {
|
|
54
|
-
defaultProfiles = defaultProfileIds;
|
|
55
|
-
} else if (defaultProfileIds && typeof defaultProfileIds === 'string') {
|
|
56
|
-
defaultProfiles = [defaultProfileIds];
|
|
57
|
-
} else {
|
|
58
|
-
// Get all available profiles as default
|
|
59
|
-
const profiles = await this.getSocialProfiles();
|
|
60
|
-
if (profiles.length === 0) {
|
|
61
|
-
throw new Error('No social profiles found. Please specify DefaultProfileIDs.');
|
|
62
|
-
}
|
|
63
|
-
defaultProfiles = profiles.map(p => p.id);
|
|
64
|
-
LogStatus(`Using ${defaultProfiles.length} default profiles`);
|
|
65
|
-
}
|
|
98
|
+
// Prepare profile IDs
|
|
99
|
+
const profileIds = post.profileIds || defaultProfiles;
|
|
66
100
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
101
|
+
// If validate only, just check the data
|
|
102
|
+
if (validateOnly) {
|
|
103
|
+
results.push({
|
|
104
|
+
index: postIndex,
|
|
105
|
+
status: 'VALIDATED',
|
|
106
|
+
content: post.content.substring(0, 50) + '...',
|
|
107
|
+
scheduledTime: scheduledTime,
|
|
108
|
+
profileCount: profileIds.length,
|
|
109
|
+
});
|
|
110
|
+
successCount++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
72
113
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Calculate scheduled time for this post
|
|
90
|
-
let scheduledTime = post.scheduledTime;
|
|
91
|
-
if (!scheduledTime && baseScheduleTime && scheduleInterval) {
|
|
92
|
-
const offsetMinutes = i * scheduleInterval;
|
|
93
|
-
const postScheduleTime = new Date(baseScheduleTime);
|
|
94
|
-
postScheduleTime.setMinutes(postScheduleTime.getMinutes() + offsetMinutes);
|
|
95
|
-
scheduledTime = postScheduleTime.toISOString();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Prepare profile IDs
|
|
99
|
-
const profileIds = post.profileIds || defaultProfiles;
|
|
100
|
-
|
|
101
|
-
// If validate only, just check the data
|
|
102
|
-
if (validateOnly) {
|
|
103
|
-
results.push({
|
|
104
|
-
index: postIndex,
|
|
105
|
-
status: 'VALIDATED',
|
|
106
|
-
content: post.content.substring(0, 50) + '...',
|
|
107
|
-
scheduledTime: scheduledTime,
|
|
108
|
-
profileCount: profileIds.length
|
|
109
|
-
});
|
|
110
|
-
successCount++;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Upload media if provided
|
|
115
|
-
let mediaIds: string[] = [];
|
|
116
|
-
if (post.mediaFiles && Array.isArray(post.mediaFiles)) {
|
|
117
|
-
LogStatus(`Uploading ${post.mediaFiles.length} media files for post ${postIndex}...`);
|
|
118
|
-
mediaIds = await this.uploadMedia(post.mediaFiles);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Create the post
|
|
122
|
-
const postData: any = {
|
|
123
|
-
text: post.content,
|
|
124
|
-
socialProfileIds: profileIds,
|
|
125
|
-
scheduledTime: scheduledTime ? this.formatHootSuiteDate(scheduledTime) : undefined,
|
|
126
|
-
mediaIds: mediaIds.length > 0 ? mediaIds : undefined,
|
|
127
|
-
tags: post.tags,
|
|
128
|
-
location: post.location
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const response = await this.axiosInstance.post('/messages', postData);
|
|
132
|
-
const createdPost = response.data;
|
|
133
|
-
|
|
134
|
-
results.push({
|
|
135
|
-
index: postIndex,
|
|
136
|
-
status: 'SUCCESS',
|
|
137
|
-
postId: createdPost.id,
|
|
138
|
-
content: post.content.substring(0, 50) + '...',
|
|
139
|
-
scheduledTime: createdPost.scheduledTime,
|
|
140
|
-
profileCount: profileIds.length
|
|
141
|
-
});
|
|
142
|
-
successCount++;
|
|
143
|
-
|
|
144
|
-
} catch (error) {
|
|
145
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
146
|
-
|
|
147
|
-
errors.push({
|
|
148
|
-
index: postIndex,
|
|
149
|
-
content: post.content.substring(0, 50) + '...',
|
|
150
|
-
error: errorMessage
|
|
151
|
-
});
|
|
152
|
-
failureCount++;
|
|
153
|
-
|
|
154
|
-
if (!skipOnError) {
|
|
155
|
-
throw new Error(`Failed at post ${postIndex}: ${errorMessage}`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Log progress every 10 posts
|
|
160
|
-
if (i > 0 && (i + 1) % 10 === 0) {
|
|
161
|
-
LogStatus(`Processed ${i + 1}/${posts.length} posts...`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
114
|
+
// Upload media if provided
|
|
115
|
+
let mediaIds: string[] = [];
|
|
116
|
+
if (post.mediaFiles && Array.isArray(post.mediaFiles)) {
|
|
117
|
+
LogStatus(`Uploading ${post.mediaFiles.length} media files for post ${postIndex}...`);
|
|
118
|
+
mediaIds = await this.uploadMedia(post.mediaFiles);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Create the post
|
|
122
|
+
const postData: any = {
|
|
123
|
+
text: post.content,
|
|
124
|
+
socialProfileIds: profileIds,
|
|
125
|
+
scheduledTime: scheduledTime ? this.formatHootSuiteDate(scheduledTime) : undefined,
|
|
126
|
+
mediaIds: mediaIds.length > 0 ? mediaIds : undefined,
|
|
127
|
+
tags: post.tags,
|
|
128
|
+
location: post.location,
|
|
129
|
+
};
|
|
164
130
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
totalPosts: posts.length,
|
|
168
|
-
successCount: successCount,
|
|
169
|
-
failureCount: failureCount,
|
|
170
|
-
validationOnly: validateOnly,
|
|
171
|
-
processingTime: new Date().toISOString(),
|
|
172
|
-
scheduleRange: baseScheduleTime ? {
|
|
173
|
-
start: baseScheduleTime.toISOString(),
|
|
174
|
-
end: new Date(baseScheduleTime.getTime() + (posts.length - 1) * (scheduleInterval || 0) * 60000).toISOString()
|
|
175
|
-
} : null
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
// Update output parameters
|
|
179
|
-
const outputParams = [...Params];
|
|
180
|
-
const resultsParam = outputParams.find(p => p.Name === 'Results');
|
|
181
|
-
if (resultsParam) resultsParam.Value = results;
|
|
182
|
-
const errorsParam = outputParams.find(p => p.Name === 'Errors');
|
|
183
|
-
if (errorsParam) errorsParam.Value = errors;
|
|
184
|
-
const summaryParam = outputParams.find(p => p.Name === 'Summary');
|
|
185
|
-
if (summaryParam) summaryParam.Value = summary;
|
|
186
|
-
|
|
187
|
-
const resultCode = failureCount === 0 ? 'SUCCESS' : (successCount > 0 ? 'PARTIAL_SUCCESS' : 'FAILED');
|
|
188
|
-
const message = validateOnly
|
|
189
|
-
? `Validated ${successCount} posts, ${failureCount} failed validation`
|
|
190
|
-
: `Successfully scheduled ${successCount} posts, ${failureCount} failed`;
|
|
191
|
-
|
|
192
|
-
return {
|
|
193
|
-
Success: failureCount === 0 || (skipOnError && successCount > 0),
|
|
194
|
-
ResultCode: resultCode,
|
|
195
|
-
Message: message,
|
|
196
|
-
Params: outputParams
|
|
197
|
-
};
|
|
131
|
+
const response = await this.axiosInstance.post('/messages', postData);
|
|
132
|
+
const createdPost = response.data;
|
|
198
133
|
|
|
134
|
+
results.push({
|
|
135
|
+
index: postIndex,
|
|
136
|
+
status: 'SUCCESS',
|
|
137
|
+
postId: createdPost.id,
|
|
138
|
+
content: post.content.substring(0, 50) + '...',
|
|
139
|
+
scheduledTime: createdPost.scheduledTime,
|
|
140
|
+
profileCount: profileIds.length,
|
|
141
|
+
});
|
|
142
|
+
successCount++;
|
|
199
143
|
} catch (error) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
Success: false,
|
|
204
|
-
ResultCode: 'ERROR',
|
|
205
|
-
Message: `Failed to bulk schedule posts: ${errorMessage}`,
|
|
206
|
-
Params
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
}
|
|
144
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
210
145
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
146
|
+
errors.push({
|
|
147
|
+
index: postIndex,
|
|
148
|
+
content: post.content.substring(0, 50) + '...',
|
|
149
|
+
error: errorMessage,
|
|
150
|
+
});
|
|
151
|
+
failureCount++;
|
|
218
152
|
|
|
219
|
-
|
|
220
|
-
throw new Error(`
|
|
153
|
+
if (!skipOnError) {
|
|
154
|
+
throw new Error(`Failed at post ${postIndex}: ${errorMessage}`);
|
|
155
|
+
}
|
|
221
156
|
}
|
|
222
157
|
|
|
223
|
-
|
|
224
|
-
|
|
158
|
+
// Log progress every 10 posts
|
|
159
|
+
if (i > 0 && (i + 1) % 10 === 0) {
|
|
160
|
+
LogStatus(`Processed ${i + 1}/${posts.length} posts...`);
|
|
225
161
|
}
|
|
162
|
+
}
|
|
226
163
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
164
|
+
// Create summary
|
|
165
|
+
const summary = {
|
|
166
|
+
totalPosts: posts.length,
|
|
167
|
+
successCount: successCount,
|
|
168
|
+
failureCount: failureCount,
|
|
169
|
+
validationOnly: validateOnly,
|
|
170
|
+
processingTime: new Date().toISOString(),
|
|
171
|
+
scheduleRange: baseScheduleTime
|
|
172
|
+
? {
|
|
173
|
+
start: baseScheduleTime.toISOString(),
|
|
174
|
+
end: new Date(baseScheduleTime.getTime() + (posts.length - 1) * (scheduleInterval || 0) * 60000).toISOString(),
|
|
230
175
|
}
|
|
231
|
-
|
|
176
|
+
: null,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Update output parameters
|
|
180
|
+
const outputParams = [...Params];
|
|
181
|
+
const resultsParam = outputParams.find((p) => p.Name === 'Results');
|
|
182
|
+
if (resultsParam) resultsParam.Value = results;
|
|
183
|
+
const errorsParam = outputParams.find((p) => p.Name === 'Errors');
|
|
184
|
+
if (errorsParam) errorsParam.Value = errors;
|
|
185
|
+
const summaryParam = outputParams.find((p) => p.Name === 'Summary');
|
|
186
|
+
if (summaryParam) summaryParam.Value = summary;
|
|
187
|
+
|
|
188
|
+
const resultCode = failureCount === 0 ? 'SUCCESS' : successCount > 0 ? 'PARTIAL_SUCCESS' : 'FAILED';
|
|
189
|
+
const message = validateOnly
|
|
190
|
+
? `Validated ${successCount} posts, ${failureCount} failed validation`
|
|
191
|
+
: `Successfully scheduled ${successCount} posts, ${failureCount} failed`;
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
Success: failureCount === 0 || (skipOnError && successCount > 0),
|
|
195
|
+
ResultCode: resultCode,
|
|
196
|
+
Message: message,
|
|
197
|
+
Params: outputParams,
|
|
198
|
+
};
|
|
199
|
+
} catch (error) {
|
|
200
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
Success: false,
|
|
204
|
+
ResultCode: 'ERROR',
|
|
205
|
+
Message: `Failed to bulk schedule posts: ${errorMessage}`,
|
|
206
|
+
Params,
|
|
207
|
+
};
|
|
232
208
|
}
|
|
209
|
+
}
|
|
233
210
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
Value: null
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
Name: 'ScheduleInterval',
|
|
252
|
-
Type: 'Input',
|
|
253
|
-
Value: null
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
Name: 'StartTime',
|
|
257
|
-
Type: 'Input',
|
|
258
|
-
Value: null
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
Name: 'SkipOnError',
|
|
262
|
-
Type: 'Input',
|
|
263
|
-
Value: null
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
Name: 'ValidateOnly',
|
|
267
|
-
Type: 'Input',
|
|
268
|
-
Value: null
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
Name: 'Results',
|
|
272
|
-
Type: 'Output',
|
|
273
|
-
Value: null
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
Name: 'Errors',
|
|
277
|
-
Type: 'Output',
|
|
278
|
-
Value: null
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
Name: 'Summary',
|
|
282
|
-
Type: 'Output',
|
|
283
|
-
Value: null
|
|
284
|
-
}
|
|
285
|
-
];
|
|
211
|
+
/**
|
|
212
|
+
* Validate bulk post data
|
|
213
|
+
*/
|
|
214
|
+
private validateBulkPost(post: BulkPostData, index: number): void {
|
|
215
|
+
if (!post.content || typeof post.content !== 'string' || post.content.trim().length === 0) {
|
|
216
|
+
throw new Error(`Post ${index}: Content is required and must not be empty`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (post.content.length > 10000) {
|
|
220
|
+
throw new Error(`Post ${index}: Content exceeds maximum length of 10000 characters`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (post.scheduledTime && isNaN(Date.parse(post.scheduledTime))) {
|
|
224
|
+
throw new Error(`Post ${index}: Invalid scheduled time format`);
|
|
286
225
|
}
|
|
287
226
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
return 'Bulk schedules multiple posts to HootSuite with support for auto-scheduling intervals and validation';
|
|
227
|
+
if (post.location) {
|
|
228
|
+
if (typeof post.location.latitude !== 'number' || typeof post.location.longitude !== 'number') {
|
|
229
|
+
throw new Error(`Post ${index}: Location must have numeric latitude and longitude`);
|
|
230
|
+
}
|
|
293
231
|
}
|
|
294
|
-
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Define the parameters this action expects
|
|
236
|
+
*/
|
|
237
|
+
public get Params(): ActionParam[] {
|
|
238
|
+
return [
|
|
239
|
+
...this.oauthParams,
|
|
240
|
+
{
|
|
241
|
+
Name: 'Posts',
|
|
242
|
+
Type: 'Input',
|
|
243
|
+
Value: null,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
Name: 'DefaultProfileIDs',
|
|
247
|
+
Type: 'Input',
|
|
248
|
+
Value: null,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
Name: 'ScheduleInterval',
|
|
252
|
+
Type: 'Input',
|
|
253
|
+
Value: null,
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
Name: 'StartTime',
|
|
257
|
+
Type: 'Input',
|
|
258
|
+
Value: null,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
Name: 'SkipOnError',
|
|
262
|
+
Type: 'Input',
|
|
263
|
+
Value: null,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
Name: 'ValidateOnly',
|
|
267
|
+
Type: 'Input',
|
|
268
|
+
Value: null,
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
Name: 'Results',
|
|
272
|
+
Type: 'Output',
|
|
273
|
+
Value: null,
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
Name: 'Errors',
|
|
277
|
+
Type: 'Output',
|
|
278
|
+
Value: null,
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
Name: 'Summary',
|
|
282
|
+
Type: 'Output',
|
|
283
|
+
Value: null,
|
|
284
|
+
},
|
|
285
|
+
];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get action description
|
|
290
|
+
*/
|
|
291
|
+
public get Description(): string {
|
|
292
|
+
return 'Bulk schedules multiple posts to HootSuite with support for auto-scheduling intervals and validation';
|
|
293
|
+
}
|
|
294
|
+
}
|