UNPKG

@memberjunction/actions-bizapps-social

Version:

Social Media Actions for MemberJunction - Twitter, LinkedIn, Facebook, Instagram, TikTok, YouTube, HootSuite, Buffer

293 lines 11.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LinkedInSearchPostsAction = void 0; const global_1 = require("@memberjunction/global"); const linkedin_base_action_1 = require("../linkedin-base.action"); const core_1 = require("@memberjunction/core"); const actions_1 = require("@memberjunction/actions"); /** * Action to search for historical posts on LinkedIn */ let LinkedInSearchPostsAction = class LinkedInSearchPostsAction extends linkedin_base_action_1.LinkedInBaseAction { /** * Search for posts on LinkedIn with various filters */ async InternalRunAction(params) { const { Params, ContextUser } = params; try { // Initialize OAuth const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID'); if (!await this.initializeOAuth(companyIntegrationId)) { throw new Error('Failed to initialize OAuth connection'); } // Extract parameters const query = this.getParamValue(Params, 'Query'); const hashtags = this.getParamValue(Params, 'Hashtags'); const startDate = this.getParamValue(Params, 'StartDate'); const endDate = this.getParamValue(Params, 'EndDate'); const authorType = this.getParamValue(Params, 'AuthorType') || 'all'; // 'personal', 'organization', 'all' const organizationId = this.getParamValue(Params, 'OrganizationID'); const limit = this.getParamValue(Params, 'Limit') || 100; const offset = this.getParamValue(Params, 'Offset') || 0; const includeAnalytics = this.getParamValue(Params, 'IncludeAnalytics') === true; // Build search parameters const searchParams = { query: query, hashtags: hashtags, startDate: startDate ? new Date(startDate) : undefined, endDate: endDate ? new Date(endDate) : undefined, limit: limit, offset: offset }; // Perform the search const posts = await this.searchPostsImplementation(searchParams, authorType, organizationId, includeAnalytics); (0, core_1.LogStatus)(`Found ${posts.length} posts matching search criteria`); // Update output parameters const outputParams = [...Params]; const postsParam = outputParams.find(p => p.Name === 'Posts'); if (postsParam) postsParam.Value = posts; const totalCountParam = outputParams.find(p => p.Name === 'TotalCount'); if (totalCountParam) totalCountParam.Value = posts.length; return { Success: true, ResultCode: 'SUCCESS', Message: `Successfully found ${posts.length} posts`, Params: outputParams }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { Success: false, ResultCode: 'ERROR', Message: `Failed to search posts: ${errorMessage}`, Params }; } } /** * Implementation of post search */ async searchPostsImplementation(params, authorType, organizationId, includeAnalytics = false) { const allPosts = []; const authorsToSearch = []; // Determine which authors to search if (authorType === 'personal' || authorType === 'all') { const userUrn = await this.getCurrentUserUrn(); authorsToSearch.push(userUrn); } if (authorType === 'organization' || authorType === 'all') { if (organizationId) { authorsToSearch.push(`urn:li:organization:${organizationId}`); } else { // Get all admin organizations const orgs = await this.getAdminOrganizations(); authorsToSearch.push(...orgs.map(org => org.urn)); } } // Search posts for each author for (const authorUrn of authorsToSearch) { (0, core_1.LogStatus)(`Searching posts for author: ${authorUrn}`); // Get all posts for the author (LinkedIn doesn't support direct content search) const shares = await this.getAllSharesForAuthor(authorUrn, params.limit || 100); // Filter posts based on search criteria for (const share of shares) { if (this.matchesSearchCriteria(share, params)) { const post = this.normalizePost(share); // Optionally fetch analytics if (includeAnalytics && authorUrn.includes('organization')) { try { const analytics = await this.getPostAnalyticsForSearch(share.id, authorUrn); if (analytics) { post.analytics = this.normalizeAnalytics(analytics); } } catch (error) { (0, core_1.LogError)(`Failed to get analytics for post ${share.id}: ${error instanceof Error ? error.message : 'Unknown error'}`); } } allPosts.push(post); } } } // Sort by date (newest first) allPosts.sort((a, b) => b.publishedAt.getTime() - a.publishedAt.getTime()); // Apply offset and limit const startIndex = params.offset || 0; const endIndex = startIndex + (params.limit || 100); return allPosts.slice(startIndex, endIndex); } /** * Get all shares for an author with pagination */ async getAllSharesForAuthor(authorUrn, maxResults) { const allShares = []; let start = 0; const count = 50; // LinkedIn's typical page size while (allShares.length < maxResults) { try { const shares = await this.getShares(authorUrn, count, start); if (shares.length === 0) { break; // No more results } allShares.push(...shares); start += count; // Check if we've hit the API limit if (shares.length < count) { break; // Last page } } catch (error) { (0, core_1.LogError)(`Error fetching shares at offset ${start}: ${error instanceof Error ? error.message : 'Unknown error'}`); break; } } return allShares.slice(0, maxResults); } /** * Check if a share matches the search criteria */ matchesSearchCriteria(share, params) { const content = share.specificContent?.['com.linkedin.ugc.ShareContent']?.shareCommentary?.text || ''; const publishedDate = new Date(share.firstPublishedAt || share.created.time); // Check date range if (params.startDate && publishedDate < params.startDate) { return false; } if (params.endDate && publishedDate > params.endDate) { return false; } // Check query (case-insensitive) if (params.query) { const query = params.query.toLowerCase(); if (!content.toLowerCase().includes(query)) { return false; } } // Check hashtags if (params.hashtags && params.hashtags.length > 0) { const contentLower = content.toLowerCase(); const hasAllHashtags = params.hashtags.every(hashtag => { const normalizedHashtag = hashtag.toLowerCase().startsWith('#') ? hashtag.toLowerCase() : `#${hashtag.toLowerCase()}`; return contentLower.includes(normalizedHashtag); }); if (!hasAllHashtags) { return false; } } return true; } /** * Get analytics for a post during search */ async getPostAnalyticsForSearch(shareId, organizationUrn) { try { const response = await this.axiosInstance.get('/organizationalEntityShareStatistics', { params: { q: 'organizationalEntity', organizationalEntity: organizationUrn, shares: `List(${shareId})` } }); if (response.data.elements && response.data.elements.length > 0) { return response.data.elements[0]; } return null; } catch (error) { // Silently fail for individual analytics requests during search return null; } } /** * Override base searchPosts method */ async searchPosts(params) { return this.searchPostsImplementation(params, 'all'); } /** * Define the parameters this action expects */ get Params() { return [ ...this.commonSocialParams, { Name: 'Query', Type: 'Input', Value: null }, { Name: 'Hashtags', Type: 'Input', Value: null // Array of hashtags }, { Name: 'StartDate', Type: 'Input', Value: null }, { Name: 'EndDate', Type: 'Input', Value: null }, { Name: 'AuthorType', Type: 'Input', Value: 'all' // 'personal', 'organization', 'all' }, { Name: 'OrganizationID', Type: 'Input', Value: null }, { Name: 'Limit', Type: 'Input', Value: 100 }, { Name: 'Offset', Type: 'Input', Value: 0 }, { Name: 'IncludeAnalytics', Type: 'Input', Value: false }, { Name: 'Posts', Type: 'Output', Value: null }, { Name: 'TotalCount', Type: 'Output', Value: null } ]; } /** * Get action description */ get Description() { return 'Searches for historical LinkedIn posts with support for content search, hashtags, date ranges, and author filtering. Retrieves posts from personal profiles and organization pages.'; } }; exports.LinkedInSearchPostsAction = LinkedInSearchPostsAction; exports.LinkedInSearchPostsAction = LinkedInSearchPostsAction = __decorate([ (0, global_1.RegisterClass)(actions_1.BaseAction, 'LinkedInSearchPostsAction') ], LinkedInSearchPostsAction); //# sourceMappingURL=search-posts.action.js.map