feat: plugs

This commit is contained in:
Nevo David 2024-11-07 20:04:48 +07:00
parent 74ad1410c7
commit d87d83d89b
5 changed files with 157 additions and 23 deletions

View File

@ -12,7 +12,7 @@ export function Plug(params: {
validation?: RegExp;
}[];
}) {
return function (target: Object, propertyKey: string | symbol) {
return function (target: Object, propertyKey: string | symbol, descriptor: any) {
// Retrieve existing metadata or initialize an empty array
const existingMetadata = Reflect.getMetadata('custom:plug', target) || [];

View File

@ -13,7 +13,8 @@ export class IntegrationRepository {
constructor(
private _integration: PrismaRepository<'integration'>,
private _posts: PrismaRepository<'post'>,
private _plugs: PrismaRepository<'plugs'>
private _plugs: PrismaRepository<'plugs'>,
private _exisingPlugData: PrismaRepository<'exisingPlugData'>
) {}
async setTimes(org: string, id: string, times: IntegrationTimeDto) {
@ -342,8 +343,8 @@ export class IntegrationRepository {
data: JSON.stringify(body.fields),
},
select: {
activated: true
}
activated: true,
},
});
}
@ -358,4 +359,34 @@ export class IntegrationRepository {
},
});
}
async loadExisingData(
methodName: string,
integrationId: string,
id: string[]
) {
return this._exisingPlugData.model.exisingPlugData.findMany({
where: {
integrationId,
methodName,
value: {
in: id,
},
},
});
}
async saveExisingData(
methodName: string,
integrationId: string,
value: string[]
) {
return this._exisingPlugData.model.exisingPlugData.createMany({
data: value.map((p) => ({
integrationId,
methodName,
value: p,
})),
});
}
}

View File

@ -18,6 +18,7 @@ import { IntegrationTimeDto } from '@gitroom/nestjs-libraries/dtos/integrations/
import { UploadFactory } from '@gitroom/nestjs-libraries/upload/upload.factory';
import { PlugDto } from '@gitroom/nestjs-libraries/dtos/plugs/plug.dto';
import { BullMqClient } from '@gitroom/nestjs-libraries/bull-mq-transport-new/client';
import { difference } from 'lodash';
@Injectable()
export class IntegrationService {
@ -467,6 +468,12 @@ export class IntegrationService {
return { id };
}
async loadExisingData (methodName: string, integrationId: string, id: string[]) {
const exisingData = await this._integrationRepository.loadExisingData(methodName, integrationId, id);
const loadOnlyIds = exisingData.map(p => p.value);
return difference(id, loadOnlyIds);
}
async startPlug(data: {
orgId: string;
integrationId: string;
@ -503,6 +510,7 @@ export class IntegrationService {
);
// @ts-ignore
return integrationInstance[data.funcName](integration, plugData);
const ids = await integrationInstance[data.funcName](integration, plugData, this.loadExisingData.bind(this));
return this._integrationRepository.saveExisingData(data.funcName, data.integrationId, ids);
}
}

View File

@ -266,6 +266,7 @@ model Integration {
postingTimes String @default("[{\"time\":120}, {\"time\":400}, {\"time\":700}]")
customInstanceDetails String?
plugs Plugs[]
exisingPlugData ExisingPlugData[]
@@index([updatedAt])
@@index([deletedAt])
@ -455,6 +456,16 @@ model Plugs {
@@index([organizationId])
}
model ExisingPlugData {
id String @id @default(uuid())
integrationId String
integration Integration @relation(fields: [integrationId], references: [id])
methodName String
value String
@@unique([integrationId, methodName, value])
}
enum OrderStatus {
PENDING
ACCEPTED

View File

@ -111,7 +111,6 @@ export class LinkedinPageProvider
)
).json();
console.log(all);
return (elements || []).map((e: any) => ({
id: e.organizationalTarget.split(':').pop(),
page: e.organizationalTarget.split(':').pop(),
@ -366,7 +365,7 @@ export class LinkedinPageProvider
@Plug({
title: 'Auto Repost Posts',
description:
'When a post reached a certain number of likes, repost it to increase engagement',
'When a post reached a certain number of likes, repost it to increase engagement (1 week old posts)',
runEveryMilliseconds: 7200000,
fields: [
{
@ -378,24 +377,109 @@ export class LinkedinPageProvider
},
],
})
async autoAddPost(integration: Integration, fields: { likesAmount: number }) {
const a = await fetch(
`https://api.linkedin.com/rest/posts?author=${encodeURIComponent(
`urn:li:organization:${integration.internalId}`
)}&q=author&count=10&sortBy=LAST_MODIFIED`,
{
method: 'GET',
headers: {
'X-Restli-Protocol-Version': '2.0.0',
'Content-Type': 'application/json',
'LinkedIn-Version': '202402',
Authorization: `Bearer ${integration.token}`,
},
}
async autoRepostPost(
integration: Integration,
fields: { likesAmount: number },
loadExisingData: (
methodName: string,
integrationId: string,
id: string[]
) => Promise<string[]>
) {
const all = await // const { elements } = await (
(
await this.fetch(
`https://api.linkedin.com/rest/posts?author=${encodeURIComponent(
`urn:li:organization:${integration.internalId}`
)}&q=author&count=10&sortBy=LAST_MODIFIED`,
{
method: 'GET',
headers: {
'X-Restli-Protocol-Version': '2.0.0',
'Content-Type': 'application/json',
'LinkedIn-Version': '202402',
Authorization: `Bearer ${integration.token}`,
},
}
)
).json();
// only post published in the last week
const lastWeekPosts = all.elements.filter((element: any) => {
const postDate = new Date(element.publishedAt).getTime();
const weekAgo = new Date().getTime() - 604800000;
return postDate > weekAgo;
});
const getLastFiveLikes = await Promise.all(
lastWeekPosts.map(async (element: any) => {
const {
likesSummary: { totalLikes },
} = await (
await this.fetch(
`https://api.linkedin.com/v2/socialActions/${encodeURIComponent(
element.id
)}`,
{
method: 'GET',
headers: {
'X-Restli-Protocol-Version': '2.0.0',
'Content-Type': 'application/json',
'LinkedIn-Version': '202402',
Authorization: `Bearer ${integration.token}`,
},
}
)
).json();
return { id: element.id, totalLikes };
})
);
console.log(await a.json());
return;
const findLikes = getLastFiveLikes.filter(
(element) => element.totalLikes >= fields.likesAmount
);
if (findLikes.length === 0) {
return [];
}
const checkIfAlreadyPosted = await loadExisingData(
'autoRepostPost',
integration.id,
findLikes.map((p) => p.id)
);
if (checkIfAlreadyPosted.length === 0) {
return [];
}
await this.fetch(`https://api.linkedin.com/rest/posts`, {
body: JSON.stringify({
author: `urn:li:organization:${integration.internalId}`,
commentary: '',
visibility: 'PUBLIC',
distribution: {
feedDistribution: 'MAIN_FEED',
targetEntities: [],
thirdPartyDistributionChannels: [],
},
lifecycleState: 'PUBLISHED',
isReshareDisabledByAuthor: false,
reshareContext: {
parent: checkIfAlreadyPosted[0],
},
}),
method: 'POST',
headers: {
'X-Restli-Protocol-Version': '2.0.0',
'Content-Type': 'application/json',
'LinkedIn-Version': '202402',
Authorization: `Bearer ${integration.token}`,
},
});
return [checkIfAlreadyPosted[0]];
}
}