feat: `audit.settings` endpoint (#35258)
Co-authored-by: Lucas Pelegrino <16467257+lucas-a-pelegrino@users.noreply.github.com>pull/35531/head
parent
38f1c508c9
commit
bb4ff0db3d
@ -0,0 +1,6 @@ |
||||
--- |
||||
"@rocket.chat/meteor": minor |
||||
"@rocket.chat/rest-typings": minor |
||||
--- |
||||
|
||||
Introduces `/v1/audit.settings` endpoint for querying changed settings audit events |
||||
@ -0,0 +1,104 @@ |
||||
import { ServerEvents } from '@rocket.chat/models'; |
||||
import { isServerEventsAuditSettingsProps } from '@rocket.chat/rest-typings'; |
||||
import { ajv } from '@rocket.chat/rest-typings/src/v1/Ajv'; |
||||
|
||||
import { API } from '../api'; |
||||
import { getPaginationItems } from '../helpers/getPaginationItems'; |
||||
|
||||
API.v1.get( |
||||
'audit.settings', |
||||
{ |
||||
response: { |
||||
200: ajv.compile({ |
||||
additionalProperties: false, |
||||
type: 'object', |
||||
properties: { |
||||
events: { |
||||
type: 'array', |
||||
items: { |
||||
type: 'object', |
||||
}, |
||||
}, |
||||
count: { |
||||
type: 'number', |
||||
description: 'The number of events returned in this response.', |
||||
}, |
||||
offset: { |
||||
type: 'number', |
||||
description: 'The number of events that were skipped in this response.', |
||||
}, |
||||
total: { |
||||
type: 'number', |
||||
description: 'The total number of events that match the query.', |
||||
}, |
||||
success: { |
||||
type: 'boolean', |
||||
description: 'Indicates if the request was successful.', |
||||
}, |
||||
}, |
||||
required: ['events', 'count', 'offset', 'total', 'success'], |
||||
}), |
||||
400: ajv.compile({ |
||||
type: 'object', |
||||
properties: { |
||||
success: { |
||||
type: 'boolean', |
||||
enum: [false], |
||||
}, |
||||
error: { |
||||
type: 'string', |
||||
}, |
||||
errorType: { |
||||
type: 'string', |
||||
}, |
||||
}, |
||||
required: ['success', 'error'], |
||||
}), |
||||
}, |
||||
query: isServerEventsAuditSettingsProps, |
||||
authRequired: true, |
||||
permissionsRequired: ['can-audit'], |
||||
}, |
||||
async function action() { |
||||
const { start, end, settingId, actor } = this.queryParams; |
||||
|
||||
if (start && isNaN(Date.parse(start as string))) { |
||||
return API.v1.failure('The "start" query parameter must be a valid date.'); |
||||
} |
||||
|
||||
if (end && isNaN(Date.parse(end as string))) { |
||||
return API.v1.failure('The "end" query parameter must be a valid date.'); |
||||
} |
||||
|
||||
const { offset, count } = await getPaginationItems(this.queryParams as Record<string, string | number | null | undefined>); |
||||
const { sort } = await this.parseJsonQuery(); |
||||
const _sort = { ts: sort?.ts ? sort?.ts : -1 }; |
||||
|
||||
const { cursor, totalCount } = ServerEvents.findPaginated( |
||||
{ |
||||
...(settingId && { 'data.key': 'id', 'data.value': settingId }), |
||||
...(actor && { actor }), |
||||
ts: { |
||||
$gte: start ? new Date(start as string) : new Date(0), |
||||
$lte: end ? new Date(end as string) : new Date(), |
||||
}, |
||||
t: 'settings.changed', |
||||
}, |
||||
{ |
||||
sort: _sort, |
||||
skip: offset, |
||||
limit: count, |
||||
allowDiskUse: true, |
||||
}, |
||||
); |
||||
|
||||
const [events, total] = await Promise.all([cursor.toArray(), totalCount]); |
||||
|
||||
return API.v1.success({ |
||||
events, |
||||
count: events.length, |
||||
offset, |
||||
total, |
||||
}); |
||||
}, |
||||
); |
||||
@ -0,0 +1,84 @@ |
||||
import type { IAuditServerActor } from '@rocket.chat/core-typings'; |
||||
import Ajv from 'ajv'; |
||||
|
||||
import type { PaginatedRequest } from '../../helpers/PaginatedRequest'; |
||||
|
||||
const ajv = new Ajv({ |
||||
coerceTypes: true, |
||||
}); |
||||
|
||||
export type ServerEventsAuditSettingsParamsGET = PaginatedRequest<{ |
||||
start?: string; |
||||
end?: string; |
||||
settingId?: string; |
||||
actor?: IAuditServerActor; |
||||
}>; |
||||
|
||||
const ServerEventsAuditSettingsParamsGetSchema = { |
||||
type: 'object', |
||||
properties: { |
||||
sort: { |
||||
type: 'object', |
||||
nullable: true, |
||||
properties: { |
||||
ts: { |
||||
type: 'number', |
||||
nullable: true, |
||||
}, |
||||
}, |
||||
}, |
||||
count: { |
||||
type: 'number', |
||||
nullable: true, |
||||
}, |
||||
offset: { |
||||
type: 'number', |
||||
nullable: true, |
||||
}, |
||||
start: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
end: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
settingId: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
actor: { |
||||
type: 'object', |
||||
nullable: true, |
||||
properties: { |
||||
type: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
_id: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
username: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
ip: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
useragent: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
reason: { |
||||
type: 'string', |
||||
nullable: true, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
additionalProperties: false, |
||||
}; |
||||
|
||||
export const isServerEventsAuditSettingsProps = ajv.compile<ServerEventsAuditSettingsParamsGET>(ServerEventsAuditSettingsParamsGetSchema); |
||||
@ -0,0 +1,2 @@ |
||||
export * from './ServerEventsAuditSettingsParamsGET'; |
||||
export * from './server-events'; |
||||
@ -0,0 +1,12 @@ |
||||
import type { IServerEvents } from '@rocket.chat/core-typings'; |
||||
|
||||
import type { ServerEventsAuditSettingsParamsGET } from './ServerEventsAuditSettingsParamsGET'; |
||||
import type { PaginatedResult } from '../../helpers/PaginatedResult'; |
||||
|
||||
export type ServerEventsEndpoints = { |
||||
'/v1/audit.settings': { |
||||
GET: (params: ServerEventsAuditSettingsParamsGET) => PaginatedResult<{ |
||||
events: IServerEvents['settings.changed'][]; |
||||
}>; |
||||
}; |
||||
}; |
||||
Loading…
Reference in new issue