feat: finalized plugs

This commit is contained in:
Nevo David 2024-12-09 16:42:00 +07:00
parent 7ca7a14294
commit f8703e0199
4 changed files with 151 additions and 9 deletions

View File

@ -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,
},

View File

@ -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 {

View File

@ -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<AuthTokenDetails> {
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)
},
}),
}
)

View File

@ -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;
}
}