From f8703e01999faf6297e6e00df30d7b3a82bc73c2 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 9 Dec 2024 16:42:00 +0700 Subject: [PATCH] feat: finalized plugs --- .../database/prisma/posts/posts.service.ts | 4 +- .../social/linkedin.page.provider.ts | 73 +++++++++++++++++++ .../integrations/social/linkedin.provider.ts | 11 ++- .../integrations/social/threads.provider.ts | 72 +++++++++++++++++- 4 files changed, 151 insertions(+), 9 deletions(-) diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 791b2743..ddced9b2 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -342,12 +342,12 @@ export class PostsService { this._workerServiceProducer.emit('plugs', { id: 'plug_' + postId + '_' + runPlug.identifier, options: { - delay: 0, // runPlug.runEveryMilliseconds, + delay: runPlug.runEveryMilliseconds, }, payload: { plugId: plug.id, postId, - delay: 0, // runPlug.runEveryMilliseconds, + delay: runPlug.runEveryMilliseconds, totalRuns: runPlug.totalRuns, currentRun: 1, }, diff --git a/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts b/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts index 9c1aacce..8a8192be 100644 --- a/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts @@ -433,6 +433,79 @@ export class LinkedinPageProvider return false; } + + @Plug({ + identifier: 'linkedin-page-autoPlugPost', + title: 'Auto plug post', + description: + 'When a post reached a certain number of likes, add another post to it so you followers get a notification about your promotion', + runEveryMilliseconds: 21600000, + totalRuns: 3, + fields: [ + { + name: 'likesAmount', + type: 'number', + placeholder: 'Amount of likes', + description: 'The amount of likes to trigger the repost', + validation: /^\d+$/, + }, + { + name: 'post', + type: 'richtext', + placeholder: 'Post to plug', + description: 'Message content to plug', + validation: /^[\s\S]{3,}$/g, + }, + ], + }) + async autoPlugPost( + integration: Integration, + id: string, + fields: { likesAmount: string; post: string } + ) { + const { + likesSummary: { totalLikes }, + } = await ( + await this.fetch( + `https://api.linkedin.com/v2/socialActions/${encodeURIComponent(id)}`, + { + method: 'GET', + headers: { + 'X-Restli-Protocol-Version': '2.0.0', + 'Content-Type': 'application/json', + 'LinkedIn-Version': '202402', + Authorization: `Bearer ${integration.token}`, + }, + } + ) + ).json(); + + if (totalLikes >= fields.likesAmount) { + await timer(2000); + await this.fetch( + `https://api.linkedin.com/v2/socialActions/${decodeURIComponent( + id + )}/comments`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${integration.token}`, + }, + body: JSON.stringify({ + actor: `urn:li:organization:${integration.internalId}`, + object: id, + message: { + text: this.fixText(fields.post) + }, + }), + } + ); + return true; + } + + return false; + } } export interface Root { diff --git a/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts b/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts index 00fcd76a..a5566266 100644 --- a/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts @@ -14,10 +14,6 @@ import { SocialAbstract, } from '@gitroom/nestjs-libraries/integrations/social.abstract'; import { Integration } from '@prisma/client'; -import { Plug } from '@gitroom/helpers/decorators/plug.decorator'; -import { string } from 'yup'; -import { timer } from '@gitroom/helpers/utils/timer'; - export class LinkedinProvider extends SocialAbstract implements SocialProvider { identifier = 'linkedin'; name = 'LinkedIn'; @@ -25,6 +21,7 @@ export class LinkedinProvider extends SocialAbstract implements SocialProvider { scopes = ['openid', 'profile', 'w_member_social', 'r_basicprofile']; refreshWait = true; + async refreshToken(refresh_token: string): Promise { const { access_token: accessToken, @@ -285,7 +282,7 @@ export class LinkedinProvider extends SocialAbstract implements SocialProvider { } } - private fixText(text: string) { + protected fixText(text: string) { const pattern = /@\[.+?]\(urn:li:organization.+?\)/g; const matches = text.match(pattern) || []; const splitAll = text.split(pattern); @@ -434,7 +431,9 @@ export class LinkedinProvider extends SocialAbstract implements SocialProvider { ? `urn:li:person:${id}` : `urn:li:organization:${id}`, object: topPostId, - message: this.fixText(post.message), + message: { + text: this.fixText(post.message) + }, }), } ) diff --git a/libraries/nestjs-libraries/src/integrations/social/threads.provider.ts b/libraries/nestjs-libraries/src/integrations/social/threads.provider.ts index 58fbf69c..7542bffa 100644 --- a/libraries/nestjs-libraries/src/integrations/social/threads.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/threads.provider.ts @@ -10,6 +10,8 @@ import { timer } from '@gitroom/helpers/utils/timer'; import dayjs from 'dayjs'; import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract'; import { capitalize, chunk } from 'lodash'; +import { Plug } from '@gitroom/helpers/decorators/plug.decorator'; +import { Integration } from '@prisma/client'; export class ThreadsProvider extends SocialAbstract implements SocialProvider { identifier = 'threads'; @@ -152,7 +154,6 @@ export class ThreadsProvider extends SocialAbstract implements SocialProvider { let globalThread = ''; let link = ''; - if (firstPost?.media?.length! <= 1) { const type = !firstPost?.media?.[0]?.url ? undefined @@ -345,4 +346,73 @@ export class ThreadsProvider extends SocialAbstract implements SocialProvider { })) || [] ); } + + @Plug({ + identifier: 'threads-autoPlugPost', + title: 'Auto plug post', + description: + 'When a post reached a certain number of likes, add another post to it so you followers get a notification about your promotion', + runEveryMilliseconds: 21600000, + totalRuns: 3, + fields: [ + { + name: 'likesAmount', + type: 'number', + placeholder: 'Amount of likes', + description: 'The amount of likes to trigger the repost', + validation: /^\d+$/, + }, + { + name: 'post', + type: 'richtext', + placeholder: 'Post to plug', + description: 'Message content to plug', + validation: /^[\s\S]{3,}$/g, + }, + ], + }) + async autoPlugPost( + integration: Integration, + id: string, + fields: { likesAmount: string; post: string } + ) { + const { data } = await ( + await fetch( + `https://graph.threads.net/v1.0/${id}/insights?metric=likes&access_token=${integration.token}` + ) + ).json(); + + const { + values: [value], + } = data.find((p: any) => p.name === 'likes'); + + if (value.value >= fields.likesAmount) { + await timer(2000); + + const form = new FormData(); + form.append('media_type', 'TEXT'); + form.append('text', fields.post); + form.append('reply_to_id', id); + form.append('access_token', integration.token); + + const { id: replyId } = await ( + await this.fetch('https://graph.threads.net/v1.0/me/threads', { + method: 'POST', + body: form, + }) + ).json(); + + await ( + await this.fetch( + `https://graph.threads.net/v1.0/${integration.internalId}/threads_publish?creation_id=${replyId}&access_token=${integration.token}`, + { + method: 'POST', + } + ) + ).json(); + return true; + } + + return false; + } }