diff --git a/.changeset/ddp-migrate-batch6-audit-callers.md b/.changeset/ddp-migrate-batch6-audit-callers.md
new file mode 100644
index 0000000000000..3b07e86cf51ec
--- /dev/null
+++ b/.changeset/ddp-migrate-batch6-audit-callers.md
@@ -0,0 +1,5 @@
+---
+'@rocket.chat/meteor': patch
+---
+
+Migrated the audit panel (`AuditLogTable`, `useAuditMutation`) from the three `auditGet*` DDP methods to the new `/v1/audit.*` REST endpoints. DDP methods stay registered with deprecation logs pointing at the new routes until 9.0.0.
diff --git a/.changeset/rest-audit-endpoints.md b/.changeset/rest-audit-endpoints.md
new file mode 100644
index 0000000000000..59f52db3453fd
--- /dev/null
+++ b/.changeset/rest-audit-endpoints.md
@@ -0,0 +1,11 @@
+---
+'@rocket.chat/meteor': minor
+---
+
+Added three new REST endpoints under `/v1/audit.*` (EE-only, requires the `auditing` license) covering the audit flows that previously only existed as DDP methods:
+
+- `GET /v1/audit.auditions?startDate=&endDate=` → `{ auditions: IAuditLog[] }` (replaces `auditGetAuditions`, `can-audit-log`)
+- `POST /v1/audit.messages` body `{ rid?, startDate, endDate, users, msg, type, visitor?, agent? }` → `{ messages: IMessage[] }` (replaces `auditGetMessages`, `can-audit`)
+- `POST /v1/audit.omnichannel.messages` body `{ startDate, endDate, users, msg, type, visitor?, agent? }` → `{ messages: IMessage[] }` (replaces `auditGetOmnichannelMessages`, `can-audit`)
+
+Each endpoint is rate-limited at 10 requests / 60s (matching the DDP `DDPRateLimiter` rules) and writes the same `AuditLog` entry the DDP methods produced. Dates are serialized as ISO strings on the wire. The DDP methods remain registered with deprecation logs pointing at the new routes until 9.0.0.
diff --git a/apps/meteor/client/views/audit/components/AuditLogTable.tsx b/apps/meteor/client/views/audit/components/AuditLogTable.tsx
index a61d52922f9a6..320dd1be77648 100644
--- a/apps/meteor/client/views/audit/components/AuditLogTable.tsx
+++ b/apps/meteor/client/views/audit/components/AuditLogTable.tsx
@@ -1,6 +1,7 @@
+import type { IAuditLog } from '@rocket.chat/core-typings';
import { Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
import { GenericTable, GenericTableHeaderCell, GenericTableBody, GenericTableLoadingRow, GenericTableHeader } from '@rocket.chat/ui-client';
-import { useTranslation, useMethod } from '@rocket.chat/ui-contexts';
+import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import { useState } from 'react';
@@ -18,14 +19,18 @@ const AuditLogTable = () => {
end: createEndOfToday(),
}));
- const getAudits = useMethod('auditGetAuditions');
+ const getAudits = useEndpoint('GET', '/v1/audit.auditions');
const { data, isLoading, isSuccess } = useQuery({
queryKey: ['audits', dateRange],
queryFn: async () => {
const { start, end } = dateRange;
- return getAudits({ startDate: start ?? new Date(0), endDate: end ?? new Date() });
+ const { auditions } = await getAudits({
+ startDate: (start ?? new Date(0)).toISOString(),
+ endDate: (end ?? new Date()).toISOString(),
+ });
+ return auditions;
},
meta: {
apiErrorToastMessage: true,
@@ -64,7 +69,7 @@ const AuditLogTable = () => {
{headers}
{data.map((auditLog) => (
-
+
))}
diff --git a/apps/meteor/client/views/audit/hooks/useAuditMutation.ts b/apps/meteor/client/views/audit/hooks/useAuditMutation.ts
index 68f7a27abf02b..5a6d001bbd987 100644
--- a/apps/meteor/client/views/audit/hooks/useAuditMutation.ts
+++ b/apps/meteor/client/views/audit/hooks/useAuditMutation.ts
@@ -1,39 +1,45 @@
-import type { IAuditLog } from '@rocket.chat/core-typings';
-import { useMethod } from '@rocket.chat/ui-contexts';
+import type { IAuditLog, IMessage } from '@rocket.chat/core-typings';
+import { useEndpoint } from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import type { AuditFields } from './useAuditForm';
+import { mapMessageFromApi } from '../../../lib/utils/mapMessageFromApi';
export const useAuditMutation = (type: IAuditLog['fields']['type']) => {
- const getAuditMessages = useMethod('auditGetMessages');
- const getOmnichannelAuditMessages = useMethod('auditGetOmnichannelMessages');
+ const getAuditMessages = useEndpoint('POST', '/v1/audit.messages');
+ const getOmnichannelAuditMessages = useEndpoint('POST', '/v1/audit.omnichannel.messages');
return useMutation({
mutationKey: ['audit'] as const,
- mutationFn: async ({ msg, dateRange, rid, users, visitor, agent }: AuditFields) => {
+ mutationFn: async ({ msg, dateRange, rid, users, visitor, agent }: AuditFields): Promise => {
+ const startDate = (dateRange.start ?? new Date(0)).toISOString();
+ const endDate = (dateRange.end ?? new Date()).toISOString();
+
if (type === 'l') {
- return getOmnichannelAuditMessages({
+ const { messages } = await getOmnichannelAuditMessages({
type,
msg,
- startDate: dateRange.start ?? new Date(0),
- endDate: dateRange.end ?? new Date(),
+ startDate,
+ endDate,
users,
visitor: '',
agent: '',
});
+ return messages.map((message) => mapMessageFromApi(message));
}
- return getAuditMessages({
+ const { messages } = await getAuditMessages({
type,
msg,
- startDate: dateRange.start ?? new Date(0),
- endDate: dateRange.end ?? new Date(),
+ startDate,
+ endDate,
rid,
users,
visitor,
agent,
});
+ return messages.map((message) => mapMessageFromApi(message));
},
});
};
diff --git a/apps/meteor/ee/server/api/audit.ts b/apps/meteor/ee/server/api/audit.ts
index 77d4ebf10cf7c..a233dabfb278b 100644
--- a/apps/meteor/ee/server/api/audit.ts
+++ b/apps/meteor/ee/server/api/audit.ts
@@ -1,4 +1,4 @@
-import type { IUser, IRoom } from '@rocket.chat/core-typings';
+import type { IAuditLog, IMessage, IUser, IRoom } from '@rocket.chat/core-typings';
import { Rooms, AuditLog, ServerEvents } from '@rocket.chat/models';
import { isServerEventsAuditSettingsProps, ajv, ajvQuery } from '@rocket.chat/rest-typings';
import type { PaginatedRequest, PaginatedResult } from '@rocket.chat/rest-typings';
@@ -7,6 +7,7 @@ import { convertSubObjectsIntoPaths } from '@rocket.chat/tools';
import { API } from '../../../app/api/server/api';
import { getPaginationItems } from '../../../app/api/server/helpers/getPaginationItems';
import { findUsersOfRoom } from '../../../server/lib/findUsersOfRoom';
+import { auditGetAuditionsMethod, auditGetMessagesMethod, auditGetOmnichannelMessagesMethod } from '../lib/audit/functions';
type AuditRoomMembersParams = PaginatedRequest<{
roomId: string;
@@ -28,6 +29,76 @@ const auditRoomMembersSchema = {
export const isAuditRoomMembersProps = ajvQuery.compile(auditRoomMembersSchema);
+type AuditAuditionsParams = { startDate: string; endDate: string };
+
+const auditAuditionsSchema = {
+ type: 'object',
+ properties: {
+ startDate: { type: 'string', minLength: 1 },
+ endDate: { type: 'string', minLength: 1 },
+ },
+ required: ['startDate', 'endDate'],
+ additionalProperties: false,
+};
+
+const isAuditAuditionsProps = ajvQuery.compile(auditAuditionsSchema);
+
+type AuditMessagesPayload = {
+ rid?: string;
+ startDate: string;
+ endDate: string;
+ users: string[];
+ msg: string;
+ type: string;
+ visitor?: string;
+ agent?: string;
+};
+
+const auditMessagesSchema = {
+ type: 'object',
+ properties: {
+ rid: { type: 'string' },
+ startDate: { type: 'string', minLength: 1 },
+ endDate: { type: 'string', minLength: 1 },
+ users: { type: 'array', items: { type: 'string' } },
+ msg: { type: 'string' },
+ type: { type: 'string' },
+ visitor: { type: 'string' },
+ agent: { type: 'string' },
+ },
+ required: ['startDate', 'endDate', 'users', 'msg', 'type'],
+ additionalProperties: false,
+};
+
+const isAuditMessagesProps = ajv.compile(auditMessagesSchema);
+
+type AuditOmnichannelMessagesPayload = {
+ startDate: string;
+ endDate: string;
+ users: string[];
+ msg: string;
+ type: string;
+ visitor?: string;
+ agent?: string;
+};
+
+const auditOmnichannelMessagesSchema = {
+ type: 'object',
+ properties: {
+ startDate: { type: 'string', minLength: 1 },
+ endDate: { type: 'string', minLength: 1 },
+ users: { type: 'array', items: { type: 'string' } },
+ msg: { type: 'string' },
+ type: { type: 'string' },
+ visitor: { type: 'string' },
+ agent: { type: 'string' },
+ },
+ required: ['startDate', 'endDate', 'users', 'msg', 'type'],
+ additionalProperties: false,
+};
+
+const isAuditOmnichannelMessagesProps = ajv.compile(auditOmnichannelMessagesSchema);
+
declare module '@rocket.chat/rest-typings' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface Endpoints {
@@ -36,9 +107,29 @@ declare module '@rocket.chat/rest-typings' {
params: AuditRoomMembersParams,
) => PaginatedResult<{ members: Pick[] }>;
};
+
+ '/v1/audit.auditions': {
+ GET: (params: AuditAuditionsParams) => { auditions: IAuditLog[] };
+ };
+
+ '/v1/audit.messages': {
+ POST: (params: AuditMessagesPayload) => { messages: IMessage[] };
+ };
+
+ '/v1/audit.omnichannel.messages': {
+ POST: (params: AuditOmnichannelMessagesPayload) => { messages: IMessage[] };
+ };
}
}
+const parseDateOrFail = (value: string, name: string): Date => {
+ const ts = Date.parse(value);
+ if (Number.isNaN(ts)) {
+ throw new Error(`The "${name}" parameter must be a valid date.`);
+ }
+ return new Date(ts);
+};
+
API.v1.addRoute(
'audit/rooms.members',
{
@@ -194,3 +285,120 @@ API.v1.get(
});
},
);
+
+const auditAuditionsResponseSchema = ajv.compile<{ auditions: IAuditLog[] }>({
+ type: 'object',
+ properties: {
+ auditions: { type: 'array', items: { type: 'object' } },
+ success: { type: 'boolean', enum: [true] },
+ },
+ required: ['auditions', 'success'],
+ additionalProperties: false,
+});
+
+const auditMessagesResponseSchema = ajv.compile<{ messages: IMessage[] }>({
+ type: 'object',
+ properties: {
+ messages: { type: 'array', items: { type: 'object' } },
+ success: { type: 'boolean', enum: [true] },
+ },
+ required: ['messages', 'success'],
+ additionalProperties: false,
+});
+
+const auditErrorResponseSchema = ajv.compile({
+ type: 'object',
+ properties: {
+ success: { type: 'boolean', enum: [false] },
+ error: { type: 'string' },
+ errorType: { type: 'string' },
+ },
+ required: ['success', 'error'],
+});
+
+API.v1.get(
+ 'audit.auditions',
+ {
+ authRequired: true,
+ permissionsRequired: ['can-audit-log'],
+ query: isAuditAuditionsProps,
+ license: ['auditing'],
+ rateLimiterOptions: { numRequestsAllowed: 10, intervalTimeInMS: 60000 },
+ response: {
+ 200: auditAuditionsResponseSchema,
+ 400: auditErrorResponseSchema,
+ },
+ },
+ async function action() {
+ const startDate = parseDateOrFail(this.queryParams.startDate, 'startDate');
+ const endDate = parseDateOrFail(this.queryParams.endDate, 'endDate');
+
+ const auditions = await auditGetAuditionsMethod(this.userId, startDate, endDate);
+ return API.v1.success({ auditions });
+ },
+);
+
+API.v1.post(
+ 'audit.messages',
+ {
+ authRequired: true,
+ permissionsRequired: ['can-audit'],
+ body: isAuditMessagesProps,
+ license: ['auditing'],
+ rateLimiterOptions: { numRequestsAllowed: 10, intervalTimeInMS: 60000 },
+ response: {
+ 200: auditMessagesResponseSchema,
+ 400: auditErrorResponseSchema,
+ },
+ },
+ async function action() {
+ const { rid, users, msg, type, visitor, agent } = this.bodyParams;
+ const startDate = parseDateOrFail(this.bodyParams.startDate, 'startDate');
+ const endDate = parseDateOrFail(this.bodyParams.endDate, 'endDate');
+
+ const messages = await auditGetMessagesMethod(this.userId, {
+ rid,
+ startDate,
+ endDate,
+ users,
+ msg,
+ type,
+ visitor,
+ agent,
+ });
+
+ return API.v1.success({ messages });
+ },
+);
+
+API.v1.post(
+ 'audit.omnichannel.messages',
+ {
+ authRequired: true,
+ permissionsRequired: ['can-audit'],
+ body: isAuditOmnichannelMessagesProps,
+ license: ['auditing'],
+ rateLimiterOptions: { numRequestsAllowed: 10, intervalTimeInMS: 60000 },
+ response: {
+ 200: auditMessagesResponseSchema,
+ 400: auditErrorResponseSchema,
+ },
+ },
+ async function action() {
+ const { users, msg, type, visitor, agent } = this.bodyParams;
+ const startDate = parseDateOrFail(this.bodyParams.startDate, 'startDate');
+ const endDate = parseDateOrFail(this.bodyParams.endDate, 'endDate');
+
+ const messages = await auditGetOmnichannelMessagesMethod(this.userId, {
+ startDate,
+ endDate,
+ users,
+ msg,
+ type,
+ visitor,
+ agent,
+ });
+
+ return API.v1.success({ messages });
+ },
+);
diff --git a/apps/meteor/ee/server/lib/audit/functions.ts b/apps/meteor/ee/server/lib/audit/functions.ts
new file mode 100644
index 0000000000000..8b3457ee16fc1
--- /dev/null
+++ b/apps/meteor/ee/server/lib/audit/functions.ts
@@ -0,0 +1,227 @@
+import type { ILivechatAgent, ILivechatVisitor, IMessage, IRoom, IUser, IAuditLog } from '@rocket.chat/core-typings';
+import { LivechatRooms, Messages, Rooms, Users, AuditLog } from '@rocket.chat/models';
+import { escapeRegExp } from '@rocket.chat/string-helpers';
+import { isTruthy } from '@rocket.chat/tools';
+import { Meteor } from 'meteor/meteor';
+import type { Filter } from 'mongodb';
+
+import { hasPermissionAsync } from '../../../../app/authorization/server/functions/hasPermission';
+import { updateCounter } from '../../../../app/statistics/server';
+import { callbacks } from '../../../../server/lib/callbacks';
+import { i18n } from '../../../../server/lib/i18n';
+
+const getValue = (room: IRoom | null) => room && { rids: [room._id], name: room.name };
+
+const getUsersIdFromUserName = async (usernames: IUser['username'][]) => {
+ const users = usernames ? await Users.findByUsernames(usernames.filter(isTruthy)).toArray() : undefined;
+
+ return users?.filter(isTruthy).map((userId) => userId._id);
+};
+
+const getRoomInfoByAuditParams = async ({
+ type,
+ roomId: rid,
+ users: usernames,
+ visitor,
+ agent,
+ userId,
+}: {
+ type: string;
+ roomId: IRoom['_id'];
+ users: NonNullable[];
+ visitor: ILivechatVisitor['_id'];
+ agent: ILivechatAgent['_id'];
+ userId: string;
+}) => {
+ if (rid) {
+ return getValue(await Rooms.findOne({ _id: rid, abacAttributes: { $exists: false } }));
+ }
+
+ if (type === 'd') {
+ return getValue(await Rooms.findDirectRoomContainingAllUsernames(usernames));
+ }
+
+ if (type === 'l') {
+ console.warn('Deprecation Warning! This method will be removed in the next version (4.0.0)');
+ const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}, { userId });
+ const rooms: IRoom[] = await LivechatRooms.findByVisitorIdAndAgentId(
+ visitor,
+ agent,
+ {
+ projection: { _id: 1 },
+ },
+ extraQuery,
+ ).toArray();
+ return rooms?.length ? { rids: rooms.map(({ _id }) => _id), name: i18n.t('Omnichannel') } : undefined;
+ }
+};
+
+const requireAuditor = async (userId: string | null): Promise => {
+ if (!userId) {
+ throw new Meteor.Error('Not allowed');
+ }
+
+ const user = await Users.findOneById(userId);
+ if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) {
+ throw new Meteor.Error('Not allowed');
+ }
+ return user;
+};
+
+type AuditMessagesParams = {
+ rid?: IRoom['_id'];
+ startDate: Date;
+ endDate: Date;
+ users: NonNullable[];
+ msg: IMessage['msg'];
+ type: string;
+ visitor?: ILivechatVisitor['_id'];
+ agent?: ILivechatAgent['_id'];
+};
+
+export const auditGetMessagesMethod = async (userId: string | null, params: AuditMessagesParams): Promise => {
+ const { rid, startDate, endDate, users: usernames, msg, type, visitor, agent } = params;
+
+ const user = await requireAuditor(userId);
+
+ const userFields = {
+ _id: user._id,
+ username: user.username,
+ ...(user.name && { name: user.name }),
+ ...(user.avatarETag && { avatarETag: user.avatarETag }),
+ };
+
+ let rids;
+ let name;
+
+ const query: Filter = {
+ ts: {
+ $gt: startDate,
+ $lt: endDate,
+ },
+ };
+
+ if (type === 'u') {
+ const usersId = await getUsersIdFromUserName(usernames);
+ query['u._id'] = { $in: usersId };
+
+ const abacRooms = await Rooms.findAllPrivateRoomsWithAbacAttributes({ projection: { _id: 1 } })
+ .map((doc) => doc._id)
+ .toArray();
+
+ query.rid = { $nin: abacRooms };
+ } else {
+ const roomInfo = await getRoomInfoByAuditParams({
+ type,
+ roomId: rid ?? '',
+ users: usernames,
+ visitor: visitor ?? '',
+ agent: agent ?? '',
+ userId: user._id,
+ });
+ if (!roomInfo) {
+ throw new Meteor.Error(`Room doesn't exist`);
+ }
+
+ rids = roomInfo.rids;
+ name = roomInfo.name;
+ query.rid = { $in: rids };
+ }
+
+ if (msg) {
+ const regex = new RegExp(escapeRegExp(msg).trim(), 'i');
+ query.msg = regex;
+ }
+
+ const messages = await Messages.find(query).toArray();
+
+ await AuditLog.insertOne({
+ ts: new Date(),
+ results: messages.length,
+ u: userFields,
+ fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent },
+ });
+
+ updateCounter({ settingsId: 'Message_Auditing_Panel_Load_Count' });
+
+ return messages;
+};
+
+type AuditOmnichannelMessagesParams = {
+ startDate: Date;
+ endDate: Date;
+ users: NonNullable[];
+ msg: IMessage['msg'];
+ type: string;
+ visitor?: ILivechatVisitor['_id'];
+ agent?: ILivechatAgent['_id'];
+};
+
+export const auditGetOmnichannelMessagesMethod = async (
+ userId: string | null,
+ params: AuditOmnichannelMessagesParams,
+): Promise => {
+ const { startDate, endDate, users: usernames, msg, type, visitor, agent } = params;
+
+ const user = await requireAuditor(userId);
+
+ const userFields = {
+ _id: user._id,
+ username: user.username,
+ ...(user.name && { name: user.name }),
+ ...(user.avatarETag && { avatarETag: user.avatarETag }),
+ };
+
+ const rooms: IRoom[] = await LivechatRooms.findByVisitorIdAndAgentId(visitor, agent, {
+ projection: { _id: 1 },
+ }).toArray();
+ const rids = rooms?.length ? rooms.map(({ _id }) => _id) : undefined;
+ const name = i18n.t('Omnichannel');
+
+ const query: Filter = {
+ rid: { $in: rids },
+ ts: {
+ $gt: startDate,
+ $lt: endDate,
+ },
+ };
+
+ if (msg) {
+ const regex = new RegExp(escapeRegExp(msg).trim(), 'i');
+ query.msg = regex;
+ }
+
+ const messages = await Messages.find(query).toArray();
+
+ await AuditLog.insertOne({
+ ts: new Date(),
+ results: messages.length,
+ u: userFields,
+ fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent },
+ });
+
+ return messages;
+};
+
+export const auditGetAuditionsMethod = async (userId: string | null, startDate: Date, endDate: Date): Promise => {
+ if (!userId || !(await hasPermissionAsync(userId, 'can-audit-log'))) {
+ throw new Meteor.Error('Not allowed');
+ }
+ return AuditLog.find(
+ {
+ ts: {
+ $gt: startDate,
+ $lt: endDate,
+ },
+ },
+ {
+ projection: {
+ 'u.services': 0,
+ 'u.roles': 0,
+ 'u.lastLogin': 0,
+ 'u.statusConnection': 0,
+ 'u.emails': 0,
+ },
+ },
+ ).toArray();
+};
diff --git a/apps/meteor/ee/server/lib/audit/methods.ts b/apps/meteor/ee/server/lib/audit/methods.ts
index 592e45e9437d0..2c15060485313 100644
--- a/apps/meteor/ee/server/lib/audit/methods.ts
+++ b/apps/meteor/ee/server/lib/audit/methods.ts
@@ -1,64 +1,11 @@
import type { ILivechatAgent, ILivechatVisitor, IMessage, IRoom, IUser, IAuditLog } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
-import { LivechatRooms, Messages, Rooms, Users, AuditLog } from '@rocket.chat/models';
-import { escapeRegExp } from '@rocket.chat/string-helpers';
-import { isTruthy } from '@rocket.chat/tools';
import { check } from 'meteor/check';
import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
import { Meteor } from 'meteor/meteor';
-import type { Filter } from 'mongodb';
-import { hasPermissionAsync } from '../../../../app/authorization/server/functions/hasPermission';
-import { updateCounter } from '../../../../app/statistics/server';
-import { callbacks } from '../../../../server/lib/callbacks';
-import { i18n } from '../../../../server/lib/i18n';
-
-const getValue = (room: IRoom | null) => room && { rids: [room._id], name: room.name };
-
-const getUsersIdFromUserName = async (usernames: IUser['username'][]) => {
- const users = usernames ? await Users.findByUsernames(usernames.filter(isTruthy)).toArray() : undefined;
-
- return users?.filter(isTruthy).map((userId) => userId._id);
-};
-
-const getRoomInfoByAuditParams = async ({
- type,
- roomId: rid,
- users: usernames,
- visitor,
- agent,
- userId,
-}: {
- type: string;
- roomId: IRoom['_id'];
- users: NonNullable[];
- visitor: ILivechatVisitor['_id'];
- agent: ILivechatAgent['_id'];
- userId: string;
-}) => {
- if (rid) {
- // When ABAC is enabled, only rooms without ABAC attributes are considered for auditing by room ID.
- return getValue(await Rooms.findOne({ _id: rid, abacAttributes: { $exists: false } }));
- }
-
- if (type === 'd') {
- return getValue(await Rooms.findDirectRoomContainingAllUsernames(usernames));
- }
-
- if (type === 'l') {
- console.warn('Deprecation Warning! This method will be removed in the next version (4.0.0)');
- const extraQuery = await callbacks.run('livechat.applyRoomRestrictions', {}, { userId });
- const rooms: IRoom[] = await LivechatRooms.findByVisitorIdAndAgentId(
- visitor,
- agent,
- {
- projection: { _id: 1 },
- },
- extraQuery,
- ).toArray();
- return rooms?.length ? { rids: rooms.map(({ _id }) => _id), name: i18n.t('Omnichannel') } : undefined;
- }
-};
+import { auditGetAuditionsMethod, auditGetMessagesMethod, auditGetOmnichannelMessagesMethod } from './functions';
+import { methodDeprecationLogger } from '../../../../app/lib/server/lib/deprecationWarningLogger';
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -87,144 +34,23 @@ declare module '@rocket.chat/ddp-client' {
}
Meteor.methods({
- async auditGetOmnichannelMessages({ startDate, endDate, users: usernames, msg, type, visitor, agent }) {
- check(startDate, Date);
- check(endDate, Date);
-
- const user = (await Meteor.userAsync()) as IUser;
- if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) {
- throw new Meteor.Error('Not allowed');
- }
-
- const userFields = {
- _id: user._id,
- username: user.username,
- ...(user.name && { name: user.name }),
- ...(user.avatarETag && { avatarETag: user.avatarETag }),
- };
-
- const rooms: IRoom[] = await LivechatRooms.findByVisitorIdAndAgentId(visitor, agent, {
- projection: { _id: 1 },
- }).toArray();
- const rids = rooms?.length ? rooms.map(({ _id }) => _id) : undefined;
- const name = i18n.t('Omnichannel');
-
- const query: Filter = {
- rid: { $in: rids },
- ts: {
- $gt: startDate,
- $lt: endDate,
- },
- };
-
- if (msg) {
- const regex = new RegExp(escapeRegExp(msg).trim(), 'i');
- query.msg = regex;
- }
- const messages = await Messages.find(query).toArray();
-
- // Once the filter is applied, messages will be shown and a log containing all filters will be saved for further auditing.
-
- await AuditLog.insertOne({
- ts: new Date(),
- results: messages.length,
- u: userFields,
- fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent },
- });
-
- return messages;
+ async auditGetOmnichannelMessages(params) {
+ methodDeprecationLogger.method('auditGetOmnichannelMessages', '9.0.0', '/v1/audit.omnichannel.messages');
+ check(params.startDate, Date);
+ check(params.endDate, Date);
+ return auditGetOmnichannelMessagesMethod(Meteor.userId(), params);
},
- async auditGetMessages({ rid, startDate, endDate, users: usernames, msg, type, visitor, agent }) {
- check(startDate, Date);
- check(endDate, Date);
-
- const user = (await Meteor.userAsync()) as IUser;
- if (!user || !(await hasPermissionAsync(user._id, 'can-audit'))) {
- throw new Meteor.Error('Not allowed');
- }
-
- const userFields = {
- _id: user._id,
- username: user.username,
- ...(user.name && { name: user.name }),
- ...(user.avatarETag && { avatarETag: user.avatarETag }),
- };
-
- let rids;
- let name;
-
- const query: Filter = {
- ts: {
- $gt: startDate,
- $lt: endDate,
- },
- };
-
- if (type === 'u') {
- const usersId = await getUsersIdFromUserName(usernames);
- query['u._id'] = { $in: usersId };
-
- const abacRooms = await Rooms.findAllPrivateRoomsWithAbacAttributes({ projection: { _id: 1 } })
- .map((doc) => doc._id)
- .toArray();
-
- query.rid = { $nin: abacRooms };
- } else {
- const roomInfo = await getRoomInfoByAuditParams({ type, roomId: rid, users: usernames, visitor, agent, userId: user._id });
- if (!roomInfo) {
- throw new Meteor.Error(`Room doesn't exist`);
- }
-
- rids = roomInfo.rids;
- name = roomInfo.name;
- query.rid = { $in: rids };
- }
-
- if (msg) {
- const regex = new RegExp(escapeRegExp(msg).trim(), 'i');
- query.msg = regex;
- }
-
- const messages = await Messages.find(query).toArray();
-
- // Once the filter is applied, messages will be shown and a log containing all filters will be saved for further auditing.
-
- await AuditLog.insertOne({
- ts: new Date(),
- results: messages.length,
- u: userFields,
- fields: { msg, users: usernames, rids, room: name, startDate, endDate, type, visitor, agent },
- });
-
- updateCounter({ settingsId: 'Message_Auditing_Panel_Load_Count' });
-
- return messages;
+ async auditGetMessages(params) {
+ methodDeprecationLogger.method('auditGetMessages', '9.0.0', '/v1/audit.messages');
+ check(params.startDate, Date);
+ check(params.endDate, Date);
+ return auditGetMessagesMethod(Meteor.userId(), params);
},
async auditGetAuditions({ startDate, endDate }) {
+ methodDeprecationLogger.method('auditGetAuditions', '9.0.0', '/v1/audit.auditions');
check(startDate, Date);
check(endDate, Date);
- const uid = Meteor.userId();
- if (!uid || !(await hasPermissionAsync(uid, 'can-audit-log'))) {
- throw new Meteor.Error('Not allowed');
- }
- return AuditLog.find(
- {
- // 'u._id': userId,
- ts: {
- $gt: startDate,
- $lt: endDate,
- },
- },
- {
- projection: {
- 'u.services': 0,
- 'u.roles': 0,
- 'u.lastLogin': 0,
- 'u.statusConnection': 0,
- 'u.emails': 0,
- },
- },
- ).toArray();
+ return auditGetAuditionsMethod(Meteor.userId(), startDate, endDate);
},
});