223 lines
6.1 KiB
TypeScript
223 lines
6.1 KiB
TypeScript
import {
|
|
AuthTokenDetails,
|
|
PostDetails,
|
|
PostResponse,
|
|
SocialProvider,
|
|
} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
|
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
|
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
|
|
|
|
export class DiscordProvider extends SocialAbstract implements SocialProvider {
|
|
identifier = 'discord';
|
|
name = 'Discord';
|
|
isBetweenSteps = false;
|
|
scopes = ['identify', 'guilds'];
|
|
async refreshToken(refreshToken: string): Promise<AuthTokenDetails> {
|
|
const { access_token, expires_in, refresh_token } = await (
|
|
await this.fetch('https://discord.com/api/oauth2/token', {
|
|
method: 'POST',
|
|
body: new URLSearchParams({
|
|
refresh_token: refreshToken,
|
|
grant_type: 'refresh_token',
|
|
}),
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Authorization: `Basic ${Buffer.from(
|
|
process.env.DISCORD_CLIENT_ID +
|
|
':' +
|
|
process.env.DISCORD_CLIENT_SECRET
|
|
).toString('base64')}`,
|
|
},
|
|
})
|
|
).json();
|
|
|
|
const { application } = await (
|
|
await fetch('https://discord.com/api/oauth2/@me', {
|
|
headers: {
|
|
Authorization: `Bearer ${access_token}`,
|
|
},
|
|
})
|
|
).json();
|
|
|
|
return {
|
|
refreshToken: refresh_token,
|
|
expiresIn: expires_in,
|
|
accessToken: access_token,
|
|
id: '',
|
|
name: application.name,
|
|
picture: '',
|
|
username: '',
|
|
};
|
|
}
|
|
async generateAuthUrl() {
|
|
const state = makeId(6);
|
|
return {
|
|
url: `https://discord.com/oauth2/authorize?client_id=${
|
|
process.env.DISCORD_CLIENT_ID
|
|
}&permissions=377957124096&response_type=code&redirect_uri=${encodeURIComponent(
|
|
`${process.env.FRONTEND_URL}/integrations/social/discord`
|
|
)}&integration_type=0&scope=bot+identify+guilds&state=${state}`,
|
|
codeVerifier: makeId(10),
|
|
state,
|
|
};
|
|
}
|
|
|
|
async authenticate(params: {
|
|
code: string;
|
|
codeVerifier: string;
|
|
refresh?: string;
|
|
}) {
|
|
const { access_token, expires_in, refresh_token, scope, guild } = await (
|
|
await this.fetch('https://discord.com/api/oauth2/token', {
|
|
method: 'POST',
|
|
body: new URLSearchParams({
|
|
code: params.code,
|
|
grant_type: 'authorization_code',
|
|
redirect_uri: `${process.env.FRONTEND_URL}/integrations/social/discord`,
|
|
}),
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Authorization: `Basic ${Buffer.from(
|
|
process.env.DISCORD_CLIENT_ID +
|
|
':' +
|
|
process.env.DISCORD_CLIENT_SECRET
|
|
).toString('base64')}`,
|
|
},
|
|
})
|
|
).json();
|
|
|
|
this.checkScopes(this.scopes, scope.split(' '));
|
|
|
|
const { application } = await (
|
|
await fetch('https://discord.com/api/oauth2/@me', {
|
|
headers: {
|
|
Authorization: `Bearer ${access_token}`,
|
|
},
|
|
})
|
|
).json();
|
|
|
|
return {
|
|
id: guild.id,
|
|
name: application.name,
|
|
accessToken: access_token,
|
|
refreshToken: refresh_token,
|
|
expiresIn: expires_in,
|
|
picture: `https://cdn.discordapp.com/avatars/${application.bot.id}/${application.bot.avatar}.png`,
|
|
username: application.bot.username,
|
|
};
|
|
}
|
|
|
|
async channels(accessToken: string, params: any, id: string) {
|
|
const list = await (
|
|
await fetch(`https://discord.com/api/guilds/${id}/channels`, {
|
|
headers: {
|
|
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`,
|
|
},
|
|
})
|
|
).json();
|
|
|
|
return list
|
|
.filter((p: any) => p.type === 0 || p.type === 5 || p.type === 15)
|
|
.map((p: any) => ({
|
|
id: String(p.id),
|
|
name: p.name,
|
|
}));
|
|
}
|
|
|
|
async post(
|
|
id: string,
|
|
accessToken: string,
|
|
postDetails: PostDetails[]
|
|
): Promise<PostResponse[]> {
|
|
let channel = postDetails[0].settings.channel;
|
|
if (postDetails.length > 1) {
|
|
const { id: threadId } = await (
|
|
await fetch(
|
|
`https://discord.com/api/channels/${postDetails[0].settings.channel}/threads`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
name: postDetails[0].message,
|
|
auto_archive_duration: 1440,
|
|
type: 11, // Public thread type
|
|
}),
|
|
}
|
|
)
|
|
).json();
|
|
channel = threadId;
|
|
}
|
|
|
|
const finalData = [];
|
|
for (const post of postDetails) {
|
|
const form = new FormData();
|
|
form.append(
|
|
'payload_json',
|
|
JSON.stringify({
|
|
content: post.message,
|
|
attachments: post.media?.map((p, index) => ({
|
|
id: index,
|
|
description: `Picture ${index}`,
|
|
filename: p.url.split('/').pop(),
|
|
})),
|
|
})
|
|
);
|
|
|
|
let index = 0;
|
|
for (const media of post.media || []) {
|
|
const loadMedia = await fetch(media.url);
|
|
|
|
form.append(
|
|
`files[${index}]`,
|
|
await loadMedia.blob(),
|
|
media.url.split('/').pop()
|
|
);
|
|
index++;
|
|
}
|
|
|
|
const data = await (
|
|
await fetch(`https://discord.com/api/channels/${channel}/messages`, {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`,
|
|
},
|
|
body: form,
|
|
})
|
|
).json();
|
|
|
|
finalData.push({
|
|
id: post.id,
|
|
releaseURL: `https://discord.com/channels/${id}/${channel}/${data.id}`,
|
|
postId: data.id,
|
|
status: 'success',
|
|
});
|
|
}
|
|
|
|
return finalData;
|
|
}
|
|
|
|
async changeNickname(
|
|
id: string,
|
|
accessToken: string,
|
|
name: string,
|
|
) {
|
|
await (await fetch(`https://discord.com/api/guilds/${id}/members/@me`, {
|
|
method: 'PATCH',
|
|
headers: {
|
|
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
nick: name,
|
|
})
|
|
})).json();
|
|
|
|
return {
|
|
name,
|
|
}
|
|
}
|
|
}
|