diff --git a/.changeset/cold-vans-suffer.md b/.changeset/cold-vans-suffer.md new file mode 100644 index 0000000000000..3d195b9a22b21 --- /dev/null +++ b/.changeset/cold-vans-suffer.md @@ -0,0 +1,6 @@ +--- +'@rocket.chat/core-typings': patch +'@rocket.chat/meteor': patch +--- + +Added per-channel link preview setting diff --git a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts index 56dbef2d1cdb1..1f8c5bc312078 100644 --- a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts +++ b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.ts @@ -44,6 +44,7 @@ type RoomSettings = { retentionIgnoreThreads: boolean; retentionOverrideGlobal: boolean; encrypted: boolean; + linksEmbed: boolean; favorite: { favorite: boolean; defaultValue: boolean; @@ -265,6 +266,10 @@ const settingSavers: RoomSettingsSavers = { await saveRoomTopic(rid, value, user); } }, + async linksEmbed({ value, rid }) { + // This saves the value directly to the room document in MongoDB + await Rooms.updateOne({ _id: rid }, { $set: { linksEmbed: value } }); + }, async roomAnnouncement({ value, room, rid, user }) { if (!value && !room.announcement) { return; @@ -386,6 +391,8 @@ const fields: (keyof RoomSettings)[] = [ 'retentionIgnoreThreads', 'retentionOverrideGlobal', 'encrypted', + + 'linksEmbed', 'favorite', ]; diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx index 59c198f669c17..ddd953d0e2257 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx @@ -228,6 +228,7 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => const retentionExcludePinnedField = useId(); const retentionFilesOnlyField = useId(); const retentionIgnoreThreads = useId(); + const linksEmbedField = useId(); const showAdvancedSettings = canViewReadOnly || readOnly || canViewArchived || canViewJoinCode || canViewHideSysMes; const showRetentionPolicy = canEditRoomRetentionPolicy && retentionPolicy?.enabled; @@ -489,6 +490,26 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) => )} + + + + {t('Enable_Link_Previews' as any)} + ( + + )} + /> + + {t('Enable_Link_Previews_Description' as any)} + )} diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts index 5aeb06a3a2114..29589ec9c28dd 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomInitialValues.ts @@ -28,6 +28,7 @@ export type EditRoomInfoFormData = { showChannels: boolean; showDiscussions: boolean; joinCode: string; + linksEmbed: boolean; systemMessages: MessageTypesValues[]; }; @@ -52,6 +53,7 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy): Partia joinCodeRequired: !!joinCodeRequired, systemMessages: Array.isArray(sysMes) ? sysMes : [], hideSysMes: Array.isArray(sysMes) ? !!sysMes?.length : !!sysMes, + linksEmbed: room.linksEmbed !== false, encrypted, ...(canEditRoomRetentionPolicy && retentionPolicy?.enabled && { diff --git a/apps/meteor/server/services/messages/hooks/AfterSaveOEmbed.ts b/apps/meteor/server/services/messages/hooks/AfterSaveOEmbed.ts index 3623b3ddd90ae..9cc6c9a99cc66 100644 --- a/apps/meteor/server/services/messages/hooks/AfterSaveOEmbed.ts +++ b/apps/meteor/server/services/messages/hooks/AfterSaveOEmbed.ts @@ -8,7 +8,7 @@ import type { } from '@rocket.chat/core-typings'; import { isOEmbedUrlWithMetadata } from '@rocket.chat/core-typings'; import { Logger } from '@rocket.chat/logger'; -import { OEmbedCache, Messages } from '@rocket.chat/models'; +import { OEmbedCache, Messages, Rooms } from '@rocket.chat/models'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; import he from 'he'; import iconv from 'iconv-lite'; @@ -327,19 +327,21 @@ const getRelevantMetaTags = function (metaObj: OEmbedMeta): Record oembedHtml?.replace('iframe', 'iframe style="max-width: 100%;width:400px;height:225px"'); + + const rocketUrlParser = async function (message: IMessage): Promise { log.debug({ msg: 'Parsing message URLs' }); - if (!settings.get('API_Embed')) { return message; } - if (!Array.isArray(message.urls)) { return message; } - + const room = await Rooms.findOneById(message.rid, { projection: { linksEmbed: 1 } }); + if (room?.linksEmbed === false) { + return message; + } log.debug({ msg: 'URLs found in message', count: message.urls.length }); - if ( (message.attachments && message.attachments.length > 0) || message.urls.filter((item) => !item.url.includes(settings.get('Site_Url'))).length > MAX_EXTERNAL_URL_PREVIEWS @@ -347,24 +349,19 @@ const rocketUrlParser = async function (message: IMessage): Promise { log.debug({ msg: 'All URLs ignored for OEmbed' }); return message; } - let changed = false; for await (const item of message.urls) { if (item.ignoreParse === true) { log.debug({ msg: 'URL ignored for OEmbed', url: item.url }); continue; } - const { urlPreview, foundMeta } = await parseUrl(item.url); - Object.assign(item, foundMeta ? urlPreview : {}); changed = changed || foundMeta; } - if (changed === true) { await Messages.setUrlsById(message._id, message.urls); } - return message; }; diff --git a/packages/core-typings/src/IRoom.ts b/packages/core-typings/src/IRoom.ts index fb243a8f92e52..481eca77932d1 100644 --- a/packages/core-typings/src/IRoom.ts +++ b/packages/core-typings/src/IRoom.ts @@ -10,6 +10,10 @@ import type { RoomType } from './RoomType'; import type { Branded } from './utils'; export interface IRoom extends IRocketChatRecord { + /** + * Enable or disable link previews for this room. If undefined, falls back to global setting. + */ + linksEmbed?: boolean; t: RoomType; name?: string; fname?: string; @@ -361,6 +365,10 @@ export type RoomAdminFieldsType = | 'abacAttributes'; export interface IRoomWithRetentionPolicy extends IRoom { + /** + * Enable or disable link previews for this room. If undefined, falls back to global setting. + */ + linksEmbed?: boolean; retention: { enabled?: boolean; maxAge: number; diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index f5e7375bddce8..befdc432bd646 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -2062,6 +2062,7 @@ "Enterprise_capabilities": "Enterprise capabilities", "Enterprise_capability": "Enterprise capability", "Entertainment": "Entertainment", + "Enable_Link_Previews": "Enable Link Previews", "Error": "Error", "Error_404": "Error:404", "Error_RocketChat_requires_oplog_tailing_when_running_in_multiple_instances": "Error: Rocket.Chat requires oplog tailing when running in multiple instances",