feat: tag people on discord

This commit is contained in:
Nevo David 2025-08-03 17:00:17 +07:00
parent 142239403c
commit 252287f246
3 changed files with 76 additions and 44 deletions

View File

@ -16,7 +16,16 @@ export const GeneralPreviewComponent: FC<{
const mediaDir = useMediaDirectory();
const renderContent = topValue.map((p) => {
const newContent = stripHtmlValidation('normal', p.content, true);
const newContent = stripHtmlValidation(
'normal',
p.content.replace(
/<span.*?data-mention-id="([.\s\S]*?)"[.\s\S]*?>([.\s\S]*?)<\/span>/gi,
(match, match1, match2) => {
return `[[[${match2}]]]`;
}
),
true
);
const { start, end } = textSlicer(
integration?.identifier || '',
@ -27,21 +36,13 @@ export const GeneralPreviewComponent: FC<{
const finalValue =
newContent
.slice(start, end)
.replace(/(@.+?)(\s)/gi, (match, match1, match2) => {
return `<span class="font-bold" style="color: #ae8afc">${match1.trim()}${match2}</span>`;
})
.replace(/@\[(.+?)]\((.+?)\)/gi, (match, name, id) => {
return `<span class="font-bold" style="color: #ae8afc">@${name}</span>`;
.replace(/\[\[\[([.\s\S]*?)]]]/, (match, match1) => {
return `<span class="font-bold font-[arial]" style="color: #ae8afc">${match1}</span>`;
}) +
`<mark class="bg-red-500" data-tooltip-id="tooltip" data-tooltip-content="This text will be cropped">` +
newContent
.slice(end)
.replace(/(@.+?)(\s)/gi, (match, match1, match2) => {
return `<span class="font-bold" style="color: #ae8afc">${match1.trim()}${match2}</span>`;
})
.replace(/@\[(.+?)]\((.+?)\)/gi, (match, name, id) => {
return `<span class="font-bold" style="color: #ae8afc">@${name}</span>`;
}) +
newContent.slice(end).replace(/\[\[\[([.\s\S]*?)]]]/, (match, match1) => {
return `<span class="font-bold font-[arial]" style="color: #ae8afc">${match1}</span>`;
}) +
`</mark>`;
return { text: finalValue, images: p.image };
@ -110,10 +111,7 @@ export const GeneralPreviewComponent: FC<{
</div>
</div>
<div
className={clsx(
'text-wrap whitespace-pre',
'preview'
)}
className={clsx('text-wrap whitespace-pre', 'preview')}
dangerouslySetInnerHTML={{
__html: value.text,
}}

View File

@ -138,7 +138,7 @@ export const stripHtmlValidation = (
convertMentionFunction?: (idOrHandle: string, name: string) => string
): string => {
if (type === 'html') {
return striptags(value, [
return striptags(convertMention(value, convertMentionFunction), [
'ul',
'ol',
'li',
@ -153,28 +153,31 @@ export const stripHtmlValidation = (
if (type === 'markdown') {
return striptags(
value
.replace(/<h1>([.\s\S]*?)<\/h1>/g, (match, p1) => {
return `<h1># ${p1}</h1>\n`;
})
.replace(/<h2>([.\s\S]*?)<\/h2>/g, (match, p1) => {
return `<h2>## ${p1}</h2>\n`;
})
.replace(/<h3>([.\s\S]*?)<\/h3>/g, (match, p1) => {
return `<h3>### ${p1}</h3>\n`;
})
.replace(/<u>([.\s\S]*?)<\/u>/g, (match, p1) => {
return `<u>__${p1}__</u>`;
})
.replace(/<strong>([.\s\S]*?)<\/strong>/g, (match, p1) => {
return `<strong>**${p1}**</strong>`;
})
.replace(/<li.*?>([.\s\S]*?)<\/li.*?>/gm, (match, p1) => {
return `<li>- ${p1.replace(/\n/gm, '')}</li>`;
})
.replace(/<p>([.\s\S]*?)<\/p>/g, (match, p1) => {
return `<p>${p1}</p>\n`;
})
convertMention(
value
.replace(/<h1>([.\s\S]*?)<\/h1>/g, (match, p1) => {
return `<h1># ${p1}</h1>\n`;
})
.replace(/<h2>([.\s\S]*?)<\/h2>/g, (match, p1) => {
return `<h2>## ${p1}</h2>\n`;
})
.replace(/<h3>([.\s\S]*?)<\/h3>/g, (match, p1) => {
return `<h3>### ${p1}</h3>\n`;
})
.replace(/<u>([.\s\S]*?)<\/u>/g, (match, p1) => {
return `<u>__${p1}__</u>`;
})
.replace(/<strong>([.\s\S]*?)<\/strong>/g, (match, p1) => {
return `<strong>**${p1}**</strong>`;
})
.replace(/<li.*?>([.\s\S]*?)<\/li.*?>/gm, (match, p1) => {
return `<li>- ${p1.replace(/\n/gm, '')}</li>`;
})
.replace(/<p>([.\s\S]*?)<\/p>/g, (match, p1) => {
return `<p>${p1}</p>\n`;
}),
convertMentionFunction
)
);
}
@ -222,7 +225,7 @@ export const convertMention = (
}
return value.replace(
/<span.*?data-mention-id="(.*?)".*?>(.*?)<\/span>/gi,
/<span.*?data-mention-id="([.\s\S]*?)"[.\s\S]*?>([.\s\S]*?)<\/span>/gi,
(match, id, name) => {
return `<span>` + process(id, name) + `</span>`;
}

View File

@ -6,6 +6,7 @@ import {
} 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';
import { Integration } from '@prisma/client';
export class DiscordProvider extends SocialAbstract implements SocialProvider {
identifier = 'discord';
@ -131,7 +132,6 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider {
postDetails: PostDetails[]
): Promise<PostResponse[]> {
let channel = postDetails[0].settings.channel;
console.log(postDetails[0].message);
if (postDetails.length > 1) {
const { id: threadId } = await (
await fetch(
@ -159,7 +159,9 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider {
form.append(
'payload_json',
JSON.stringify({
content: post.message,
content: post.message.replace(/\[\[\[(@\d.*?)]]]/g, (match, p1) => {
return `<${p1}>`;
}),
attachments: post.media?.map((p, index) => ({
id: index,
description: `Picture ${index}`,
@ -219,4 +221,33 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider {
name,
};
}
override async mention(
token: string,
data: { query: string },
id: string,
integration: Integration
) {
const list = await (
await fetch(
`https://discord.com/api/guilds/${id}/members/search?query=${data.query}`,
{
headers: {
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`,
'Content-Type': 'application/json',
},
}
)
).json();
return list.map((p: any) => ({
id: String(p.user.id),
label: p.user.global_name || p.user.username,
image: `https://cdn.discordapp.com/avatars/${p.user.id}/${p.user.avatar}.png`,
}));
}
mentionFormat(idOrHandle: string, name: string) {
return `[[[@${idOrHandle}]]]`;
}
}