Skip to content

Commit

Permalink
Merge branch 'develop' into rewrite/marketplace-page
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagoevanp committed Jan 19, 2024
2 parents 44b22c0 + fdd9852 commit 80bc503
Show file tree
Hide file tree
Showing 25 changed files with 306 additions and 104 deletions.
7 changes: 7 additions & 0 deletions .changeset/lucky-bikes-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/core-typings": patch
"@rocket.chat/rest-typings": patch
---

Added `chat.getURLPreview` endpoint to enable users to retrieve previews for URL (ready to be provided in message send/update)
22 changes: 21 additions & 1 deletion apps/meteor/app/api/server/v1/chat.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message } from '@rocket.chat/core-services';
import type { IMessage } from '@rocket.chat/core-typings';
import { Messages, Users, Rooms, Subscriptions } from '@rocket.chat/models';
import { isChatReportMessageProps } from '@rocket.chat/rest-typings';
import { isChatReportMessageProps, isChatGetURLPreviewProps } from '@rocket.chat/rest-typings';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { Match, check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
Expand All @@ -15,6 +15,7 @@ import { deleteMessageValidatingPermission } from '../../../lib/server/functions
import { processWebhookMessage } from '../../../lib/server/functions/processWebhookMessage';
import { executeSendMessage } from '../../../lib/server/methods/sendMessage';
import { executeUpdateMessage } from '../../../lib/server/methods/updateMessage';
import { OEmbed } from '../../../oembed/server/server';
import { executeSetReaction } from '../../../reactions/server/setReaction';
import { settings } from '../../../settings/server';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
Expand Down Expand Up @@ -822,3 +823,22 @@ API.v1.addRoute(
},
},
);

API.v1.addRoute(
'chat.getURLPreview',
{ authRequired: true, validateParams: isChatGetURLPreviewProps },
{
async get() {
const { roomId, url } = this.queryParams;

if (!(await canAccessRoomIdAsync(roomId, this.userId))) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}

const { urlPreview } = await OEmbed.parseUrl(url);
urlPreview.ignoreParse = true;

return API.v1.success({ urlPreview });
},
},
);
22 changes: 8 additions & 14 deletions apps/meteor/app/livechat/imports/server/rest/departments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,23 +117,17 @@ API.v1.addRoute(
const { _id } = this.urlParams;
const { department, agents } = this.bodyParams;

let success;
if (permissionToSave) {
success = await LivechatEnterprise.saveDepartment(_id, department);
if (!permissionToSave) {
throw new Error('error-not-allowed');
}

if (success && agents && permissionToAddAgents) {
success = await LivechatTs.saveDepartmentAgents(_id, { upsert: agents });
}
const agentParam = permissionToAddAgents && agents ? { upsert: agents } : {};
await LivechatEnterprise.saveDepartment(_id, department, agentParam);

if (success) {
return API.v1.success({
department: await LivechatDepartment.findOneById(_id),
agents: await LivechatDepartmentAgents.findByDepartmentId(_id).toArray(),
});
}

return API.v1.failure();
return API.v1.success({
department: await LivechatDepartment.findOneById(_id),
agents: await LivechatDepartmentAgents.findByDepartmentId(_id).toArray(),
});
},
async delete() {
check(this.urlParams, {
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/livechat/imports/server/rest/inquiries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ API.v1.addRoute(
const { department } = this.queryParams;
const ourQuery: { status: string; department?: string } = { status: 'queued' };
if (department) {
const departmentFromDB = await LivechatDepartment.findOneByIdOrName(department);
const departmentFromDB = await LivechatDepartment.findOneByIdOrName(department, { projection: { _id: 1 } });
if (departmentFromDB) {
ourQuery.department = departmentFromDB._id;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ILivechatAgentStatus, ILivechatBusinessHour, ILivechatDepartment } from '@rocket.chat/core-typings';
import type { AtLeast, ILivechatAgentStatus, ILivechatBusinessHour, ILivechatDepartment } from '@rocket.chat/core-typings';
import type { ILivechatBusinessHoursModel, IUsersModel } from '@rocket.chat/model-typings';
import { LivechatBusinessHours, Users } from '@rocket.chat/models';
import moment from 'moment-timezone';
Expand All @@ -14,8 +14,8 @@ export interface IBusinessHourBehavior {
onAddAgentToDepartment(options?: { departmentId: string; agentsId: string[] }): Promise<any>;
onRemoveAgentFromDepartment(options?: Record<string, any>): Promise<any>;
onRemoveDepartment(options: { department: ILivechatDepartment; agentsIds: string[] }): Promise<any>;
onDepartmentDisabled(department?: ILivechatDepartment): Promise<any>;
onDepartmentArchived(department: Pick<ILivechatDepartment, '_id'>): Promise<void>;
onDepartmentDisabled(department?: AtLeast<ILivechatDepartment, '_id' | 'businessHourId'>): Promise<void>;
onDepartmentArchived(department: Pick<ILivechatDepartment, '_id' | 'businessHourId'>): Promise<void>;
onStartBusinessHours(): Promise<void>;
afterSaveBusinessHours(businessHourData: ILivechatBusinessHour): Promise<void>;
allowAgentChangeServiceStatus(agentId: string): Promise<boolean>;
Expand Down
6 changes: 4 additions & 2 deletions apps/meteor/app/livechat/server/lib/Departments.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ILivechatDepartmentAgents } from '@rocket.chat/core-typings';
import type { ILivechatDepartment, ILivechatDepartmentAgents } from '@rocket.chat/core-typings';
import { Logger } from '@rocket.chat/logger';
import { LivechatDepartment, LivechatDepartmentAgents, LivechatRooms } from '@rocket.chat/models';

Expand All @@ -10,7 +10,9 @@ class DepartmentHelperClass {
async removeDepartment(departmentId: string) {
this.logger.debug(`Removing department: ${departmentId}`);

const department = await LivechatDepartment.findOneById(departmentId);
const department = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id' | 'businessHourId'>>(departmentId, {
projection: { _id: 1, businessHourId: 1 },
});
if (!department) {
throw new Error('error-department-not-found');
}
Expand Down
25 changes: 18 additions & 7 deletions apps/meteor/app/livechat/server/lib/Helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,13 +648,24 @@ export const updateDepartmentAgents = async (
departmentEnabled: boolean,
) => {
check(departmentId, String);
check(
agents,
Match.ObjectIncluding({
upsert: Match.Maybe(Array),
remove: Match.Maybe(Array),
}),
);
check(agents, {
upsert: Match.Maybe([
Match.ObjectIncluding({
agentId: String,
username: Match.Maybe(String),
count: Match.Maybe(Match.Integer),
order: Match.Maybe(Match.Integer),
}),
]),
remove: Match.Maybe([
Match.ObjectIncluding({
agentId: String,
username: Match.Maybe(String),
count: Match.Maybe(Match.Integer),
order: Match.Maybe(Match.Integer),
}),
]),
});

const { upsert = [], remove = [] } = agents;
const agentsRemoved = [];
Expand Down
8 changes: 5 additions & 3 deletions apps/meteor/app/livechat/server/lib/LivechatTyped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ class LivechatClass {
},
};

const dep = await LivechatDepartment.findOneById(department);
const dep = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id'>>(department, { projection: { _id: 1 } });
if (!dep) {
throw new Meteor.Error('invalid-department', 'Provided department does not exists');
}
Expand Down Expand Up @@ -987,7 +987,9 @@ class LivechatClass {
}

async archiveDepartment(_id: string) {
const department = await LivechatDepartment.findOneById(_id, { projection: { _id: 1 } });
const department = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, '_id' | 'businessHourId'>>(_id, {
projection: { _id: 1, businessHourId: 1 },
});

if (!department) {
throw new Error('department-not-found');
Expand Down Expand Up @@ -1053,7 +1055,7 @@ class LivechatClass {
}

if (transferData.departmentId) {
const department = await LivechatDepartment.findOneById(transferData.departmentId, {
const department = await LivechatDepartment.findOneById<Pick<ILivechatDepartment, 'name' | '_id'>>(transferData.departmentId, {
projection: { name: 1 },
});
if (!department) {
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/livechat/server/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Meteor.startup(async () => {
await createDefaultBusinessHourIfNotExists();

settings.watch<boolean>('Livechat_enable_business_hours', async (value) => {
logger.info(`Changing business hour type to ${value}`);
logger.debug(`Starting business hour manager ${value}`);
if (value) {
await businessHourManager.startManager();
return;
Expand Down
85 changes: 49 additions & 36 deletions apps/meteor/app/oembed/server/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import type { OEmbedUrlContentResult, OEmbedUrlWithMetadata, IMessage, MessageAttachment, OEmbedMeta } from '@rocket.chat/core-typings';
import { isOEmbedUrlContentResult, isOEmbedUrlWithMetadata } from '@rocket.chat/core-typings';
import type {
OEmbedUrlContentResult,
OEmbedUrlWithMetadata,
IMessage,
MessageAttachment,
OEmbedMeta,
MessageUrl,
} from '@rocket.chat/core-typings';
import { isOEmbedUrlWithMetadata } from '@rocket.chat/core-typings';
import { Logger } from '@rocket.chat/logger';
import { Messages, OEmbedCache } from '@rocket.chat/models';
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
Expand Down Expand Up @@ -128,6 +135,41 @@ const getUrlContent = async (urlObj: URL, redirectCount = 5): Promise<OEmbedUrlC
};
};

const parseUrl = async function (url: string): Promise<{ urlPreview: MessageUrl; foundMeta: boolean }> {
const parsedUrlObject: MessageUrl = { url, meta: {} };
let foundMeta = false;
if (!isURL(url)) {
return { urlPreview: parsedUrlObject, foundMeta };
}

const data = await getUrlMetaWithCache(url);
if (!data) {
return { urlPreview: parsedUrlObject, foundMeta };
}

if (isOEmbedUrlWithMetadata(data) && data.meta) {
parsedUrlObject.meta = getRelevantMetaTags(data.meta) || {};
if (parsedUrlObject.meta?.oembedHtml) {
parsedUrlObject.meta.oembedHtml = insertMaxWidthInOembedHtml(parsedUrlObject.meta.oembedHtml) || '';
}
}

foundMeta = true;
return {
urlPreview: {
...parsedUrlObject,
...((parsedUrlObject.headers || data.headers) && {
headers: {
...parsedUrlObject.headers,
...(data.headers?.contentLength && { contentLength: data.headers.contentLength }),
...(data.headers?.contentType && { contentType: data.headers.contentType }),
},
}),
},
foundMeta,
};
};

const getUrlMeta = async function (
url: string,
withFragment?: boolean,
Expand All @@ -151,10 +193,6 @@ const getUrlMeta = async function (
return;
}

if (content.attachments) {
return content;
}

log.debug('Parsing metadata for URL', url);
const metas: { [k: string]: string } = {};

Expand Down Expand Up @@ -273,37 +311,10 @@ const rocketUrlParser = async function (message: IMessage): Promise<IMessage> {
continue;
}

if (!isURL(item.url)) {
continue;
}

const data = await getUrlMetaWithCache(item.url);

if (!data) {
continue;
}

if (isOEmbedUrlContentResult(data) && data.attachments) {
attachments.push(...data.attachments);
break;
}

if (isOEmbedUrlWithMetadata(data) && data.meta) {
item.meta = getRelevantMetaTags(data.meta) || {};
if (item.meta?.oembedHtml) {
item.meta.oembedHtml = insertMaxWidthInOembedHtml(item.meta.oembedHtml) || '';
}
}

if (data.headers?.contentLength) {
item.headers = { ...item.headers, contentLength: data.headers.contentLength };
}

if (data.headers?.contentType) {
item.headers = { ...item.headers, contentType: data.headers.contentType };
}
const { urlPreview, foundMeta } = await parseUrl(item.url);

changed = true;
Object.assign(item, foundMeta ? urlPreview : {});
changed = changed || foundMeta;
}

if (attachments.length) {
Expand All @@ -321,10 +332,12 @@ const OEmbed: {
getUrlMeta: (url: string, withFragment?: boolean) => Promise<OEmbedUrlWithMetadata | undefined | OEmbedUrlContentResult>;
getUrlMetaWithCache: (url: string, withFragment?: boolean) => Promise<OEmbedUrlWithMetadata | OEmbedUrlContentResult | undefined>;
rocketUrlParser: (message: IMessage) => Promise<IMessage>;
parseUrl: (url: string) => Promise<{ urlPreview: MessageUrl; foundMeta: boolean }>;
} = {
rocketUrlParser,
getUrlMetaWithCache,
getUrlMeta,
parseUrl,
};

settings.watch('API_Embed', (value) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ export const openBusinessHour = async (
totalAgents: agentIds.length,
top10AgentIds: agentIds.slice(0, 10),
});

await Users.addBusinessHourByAgentIds(agentIds, businessHour._id);
await Users.makeAgentsWithinBusinessHourAvailable(agentIds);

if (updateLivechatStatus) {
await Users.updateLivechatStatusBasedOnBusinessHours();
}
Expand Down
Loading

0 comments on commit 80bc503

Please sign in to comment.