commit
3e74b5244f
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -22,6 +22,14 @@ export default async function Page({
|
|||
};
|
||||
}
|
||||
|
||||
if (provider === 'vk') {
|
||||
searchParams = {
|
||||
...searchParams,
|
||||
state: searchParams.state || '',
|
||||
code: searchParams.code + '&&&&' + searchParams.device_id
|
||||
};
|
||||
}
|
||||
|
||||
const data = await internalFetch(`/integrations/social/${provider}/connect`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(searchParams),
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import LemmyProvider from '@gitroom/frontend/components/launches/providers/lemmy
|
|||
import WarpcastProvider from '@gitroom/frontend/components/launches/providers/warpcast/warpcast.provider';
|
||||
import TelegramProvider from '@gitroom/frontend/components/launches/providers/telegram/telegram.provider';
|
||||
import NostrProvider from '@gitroom/frontend/components/launches/providers/nostr/nostr.provider';
|
||||
import VkProvider from '@gitroom/frontend/components/launches/providers/vk/vk.provider';
|
||||
|
||||
export const Providers = [
|
||||
{identifier: 'devto', component: DevtoProvider},
|
||||
|
|
@ -46,6 +47,7 @@ export const Providers = [
|
|||
{identifier: 'wrapcast', component: WarpcastProvider},
|
||||
{identifier: 'telegram', component: TelegramProvider},
|
||||
{identifier: 'nostr', component: NostrProvider},
|
||||
{identifier: 'vk', component: VkProvider},
|
||||
];
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
import { withProvider } from '@gitroom/frontend/components/launches/providers/high.order.provider';
|
||||
|
||||
export default withProvider(
|
||||
null,
|
||||
undefined,
|
||||
undefined,
|
||||
async (posts) => {
|
||||
return true;
|
||||
},
|
||||
2048
|
||||
);
|
||||
|
|
@ -26,6 +26,7 @@ import { InstagramStandaloneProvider } from '@gitroom/nestjs-libraries/integrati
|
|||
import { FarcasterProvider } from '@gitroom/nestjs-libraries/integrations/social/farcaster.provider';
|
||||
import { TelegramProvider } from '@gitroom/nestjs-libraries/integrations/social/telegram.provider';
|
||||
import { NostrProvider } from '@gitroom/nestjs-libraries/integrations/social/nostr.provider';
|
||||
import { VkProvider } from '@gitroom/nestjs-libraries/integrations/social/vk.provider';
|
||||
|
||||
export const socialIntegrationList: SocialProvider[] = [
|
||||
new XProvider(),
|
||||
|
|
@ -48,6 +49,7 @@ export const socialIntegrationList: SocialProvider[] = [
|
|||
new FarcasterProvider(),
|
||||
new TelegramProvider(),
|
||||
new NostrProvider(),
|
||||
new VkProvider(),
|
||||
// new MastodonCustomProvider(),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,246 @@
|
|||
import {
|
||||
AuthTokenDetails,
|
||||
PostDetails,
|
||||
PostResponse,
|
||||
SocialProvider,
|
||||
} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
||||
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
||||
import dayjs from 'dayjs';
|
||||
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
||||
import { createHash, randomBytes } from 'crypto';
|
||||
import axios from 'axios';
|
||||
import FormDataNew from 'form-data';
|
||||
import mime from 'mime-types';
|
||||
|
||||
export class VkProvider extends SocialAbstract implements SocialProvider {
|
||||
identifier = 'vk';
|
||||
name = 'VK';
|
||||
isBetweenSteps = false;
|
||||
scopes = [
|
||||
'vkid.personal_info',
|
||||
'email',
|
||||
'wall',
|
||||
'status',
|
||||
'docs',
|
||||
'photos',
|
||||
'video',
|
||||
];
|
||||
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
return {
|
||||
refreshToken: '',
|
||||
expiresIn: 0,
|
||||
accessToken: '',
|
||||
id: '',
|
||||
name: '',
|
||||
picture: '',
|
||||
username: '',
|
||||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(32);
|
||||
const codeVerifier = randomBytes(64).toString('base64url');
|
||||
const challenge = Buffer.from(
|
||||
createHash('sha256').update(codeVerifier).digest()
|
||||
)
|
||||
.toString('base64')
|
||||
.replace(/=*$/g, '')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_');
|
||||
|
||||
return {
|
||||
url:
|
||||
'https://id.vk.com/authorize' +
|
||||
`?response_type=code` +
|
||||
`&client_id=${process.env.VK_ID}` +
|
||||
`&code_challenge_method=S256` +
|
||||
`&code_challenge=${challenge}` +
|
||||
`&redirect_uri=${encodeURIComponent(
|
||||
`${
|
||||
process?.env.FRONTEND_URL?.indexOf('https') == -1
|
||||
? `https://redirectmeto.com/${process?.env.FRONTEND_URL}`
|
||||
: `${process?.env.FRONTEND_URL}`
|
||||
}/integrations/social/vk`
|
||||
)}` +
|
||||
`&state=${state}` +
|
||||
`&scope=${encodeURIComponent(this.scopes.join(' '))}`,
|
||||
codeVerifier,
|
||||
state,
|
||||
};
|
||||
}
|
||||
|
||||
async authenticate(params: {
|
||||
code: string;
|
||||
codeVerifier: string;
|
||||
refresh?: string;
|
||||
}) {
|
||||
const [code, device_id] = params.code.split('&&&&');
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('client_id', process.env.VK_ID!);
|
||||
formData.append('grant_type', 'authorization_code');
|
||||
formData.append('code_verifier', params.codeVerifier);
|
||||
formData.append('device_id', device_id);
|
||||
formData.append('code', code);
|
||||
formData.append(
|
||||
'redirect_uri',
|
||||
`${
|
||||
process?.env.FRONTEND_URL?.indexOf('https') == -1
|
||||
? `https://redirectmeto.com/${process?.env.FRONTEND_URL}`
|
||||
: `${process?.env.FRONTEND_URL}`
|
||||
}/integrations/social/vk`
|
||||
);
|
||||
|
||||
const { access_token, scope, refresh_token } = await (
|
||||
await this.fetch('https://id.vk.com/oauth2/auth', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
).json();
|
||||
|
||||
const newFormData = new FormData();
|
||||
newFormData.append('client_id', process.env.VK_ID!);
|
||||
newFormData.append('access_token', access_token);
|
||||
|
||||
const {
|
||||
user: { user_id, first_name, last_name, avatar },
|
||||
} = await (
|
||||
await this.fetch('https://id.vk.com/oauth2/user_info', {
|
||||
method: 'POST',
|
||||
body: newFormData,
|
||||
})
|
||||
).json();
|
||||
|
||||
return {
|
||||
id: user_id,
|
||||
name: first_name + ' ' + last_name,
|
||||
accessToken: access_token,
|
||||
refreshToken: access_token,
|
||||
expiresIn: dayjs().add(59, 'days').unix() - dayjs().unix(),
|
||||
picture: avatar,
|
||||
username: first_name.toLowerCase(),
|
||||
};
|
||||
}
|
||||
|
||||
async post(
|
||||
userId: string,
|
||||
accessToken: string,
|
||||
postDetails: PostDetails[]
|
||||
): Promise<PostResponse[]> {
|
||||
let replyTo = '';
|
||||
const values: PostResponse[] = [];
|
||||
|
||||
const uploading = await Promise.all(
|
||||
postDetails.map(async (post) => {
|
||||
return await Promise.all(
|
||||
(post?.media || []).map(async (media) => {
|
||||
const all = await (
|
||||
await this.fetch(
|
||||
media.url.indexOf('mp4') > -1
|
||||
? `https://api.vk.com/method/video.save?access_token=${accessToken}&v=5.251`
|
||||
: `https://api.vk.com/method/photos.getWallUploadServer?owner_id=${userId}&access_token=${accessToken}&v=5.251`
|
||||
)
|
||||
).json();
|
||||
|
||||
const { data } = await axios.get(media.url!, {
|
||||
responseType: 'stream',
|
||||
});
|
||||
|
||||
const slash = media.url.split('/').at(-1);
|
||||
|
||||
const formData = new FormDataNew();
|
||||
formData.append('photo', data, {
|
||||
filename: slash,
|
||||
contentType: mime.lookup(slash!) || '',
|
||||
});
|
||||
const value = (
|
||||
await axios.post(all.response.upload_url, formData, {
|
||||
headers: {
|
||||
...formData.getHeaders(),
|
||||
},
|
||||
})
|
||||
).data;
|
||||
|
||||
if (media.url.indexOf('mp4') > -1) {
|
||||
return {
|
||||
id: all.response.video_id,
|
||||
type: 'video',
|
||||
};
|
||||
}
|
||||
|
||||
const formSend = new FormData();
|
||||
formSend.append('photo', value.photo);
|
||||
formSend.append('server', value.server);
|
||||
formSend.append('hash', value.hash);
|
||||
|
||||
const { id } = (
|
||||
await (
|
||||
await fetch(
|
||||
`https://api.vk.com/method/photos.saveWallPhoto?access_token=${accessToken}&v=5.251`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: formSend,
|
||||
}
|
||||
)
|
||||
).json()
|
||||
).response[0];
|
||||
|
||||
return {
|
||||
id,
|
||||
type: 'photo',
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
let i = 0;
|
||||
for (const post of postDetails) {
|
||||
const list = (uploading?.[i] || []);
|
||||
|
||||
const body = new FormData();
|
||||
body.append('message', post.message);
|
||||
if (replyTo) {
|
||||
body.append('post_id', replyTo);
|
||||
}
|
||||
|
||||
if (list.length) {
|
||||
body.append(
|
||||
'attachments',
|
||||
list.map((p) => `${p.type}${userId}_${p.id}`).join(',')
|
||||
);
|
||||
}
|
||||
|
||||
const { response, ...all } = await (
|
||||
await this.fetch(
|
||||
`https://api.vk.com/method/${
|
||||
replyTo ? 'wall.createComment' : 'wall.post'
|
||||
}?v=5.251&access_token=${accessToken}&client_id=${process.env.VK_ID}`,
|
||||
{
|
||||
method: 'POST',
|
||||
body,
|
||||
}
|
||||
)
|
||||
).json();
|
||||
|
||||
|
||||
values.push({
|
||||
id: post.id,
|
||||
postId: String(response?.post_id || response?.comment_id),
|
||||
releaseURL: `https://vk.com/feed?w=wall${userId}_${
|
||||
response?.post_id || replyTo
|
||||
}`,
|
||||
status: 'completed',
|
||||
});
|
||||
|
||||
if (!replyTo) {
|
||||
replyTo = response.post_id;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue