From c3450e924a91731bbc3239529dde68fb107312ad Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 25 Nov 2025 11:02:07 -0600 Subject: [PATCH 1/2] add abac statistics --- .../app/statistics/server/lib/statistics.ts | 22 +++++++++++++++++++ packages/core-typings/src/IStats.ts | 4 ++++ .../src/models/IAbacAttributesModel.ts | 1 + .../model-typings/src/models/IRoomsModel.ts | 2 ++ packages/models/src/models/AbacAttributes.ts | 21 ++++++++++++++++++ packages/models/src/models/Rooms.ts | 4 ++++ 6 files changed, 54 insertions(+) diff --git a/apps/meteor/app/statistics/server/lib/statistics.ts b/apps/meteor/app/statistics/server/lib/statistics.ts index 0fadf701d4657..73292480d74f4 100644 --- a/apps/meteor/app/statistics/server/lib/statistics.ts +++ b/apps/meteor/app/statistics/server/lib/statistics.ts @@ -4,6 +4,7 @@ import os from 'os'; import { Analytics, Team, VideoConf, Presence } from '@rocket.chat/core-services'; import type { IRoom, IStats, ISetting } from '@rocket.chat/core-typings'; import { UserStatus } from '@rocket.chat/core-typings'; +import { License } from '@rocket.chat/license'; import { NotificationQueue, Rooms, @@ -25,6 +26,7 @@ import { Subscriptions, Users, LivechatRooms, + AbacAttributes, } from '@rocket.chat/models'; import { MongoInternals } from 'meteor/mongo'; import moment from 'moment'; @@ -609,6 +611,26 @@ export const statistics = { statistics.webRTCEnabledForOmnichannel = settings.get('Omnichannel_call_provider') === 'WebRTC'; statistics.omnichannelWebRTCCalls = await Rooms.findCountOfRoomsWithActiveCalls(); + // ABAC stats + if (License.hasModule('abac')) { + statistics.abacEnabled = settings.get('ABAC_Enabled'); + statsPms.push( + AbacAttributes.estimatedDocumentCount().then((result) => { + statistics.abacTotalAttributes = result; + }), + ); + statsPms.push( + AbacAttributes.countTotalValues().then((result) => { + statistics.abacTotalAttributeValues = result; + }), + ); + statsPms.push( + Rooms.countAbacEnabled().then((result) => { + statistics.abacRoomsEnrolled = result; + }), + ); + } + await Promise.all(statsPms).catch(log); return statistics; diff --git a/packages/core-typings/src/IStats.ts b/packages/core-typings/src/IStats.ts index a940be16fd374..bee28ac0ddf1c 100644 --- a/packages/core-typings/src/IStats.ts +++ b/packages/core-typings/src/IStats.ts @@ -271,4 +271,8 @@ export interface IStats { totalUpsellViews: number; totalUpsellClicks: number; }; + abacEnabled?: boolean; + abacTotalAttributes?: number; + abacTotalAttributeValues?: number; + abacRoomsEnrolled?: number; } diff --git a/packages/model-typings/src/models/IAbacAttributesModel.ts b/packages/model-typings/src/models/IAbacAttributesModel.ts index 6e1ae5050ee59..485aa7bae751a 100644 --- a/packages/model-typings/src/models/IAbacAttributesModel.ts +++ b/packages/model-typings/src/models/IAbacAttributesModel.ts @@ -6,4 +6,5 @@ import type { IBaseModel } from './IBaseModel'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface IAbacAttributesModel extends IBaseModel { findOneByKey(key: string, options?: FindOptions): Promise; + countTotalValues(): Promise; } diff --git a/packages/model-typings/src/models/IRoomsModel.ts b/packages/model-typings/src/models/IRoomsModel.ts index 7f10b3e06f2f3..d0d9f183bcf61 100644 --- a/packages/model-typings/src/models/IRoomsModel.ts +++ b/packages/model-typings/src/models/IRoomsModel.ts @@ -125,6 +125,8 @@ export interface IRoomsModel extends IBaseModel { findByBroadcast(options?: FindOptions): FindCursor; + countAbacEnabled(): Promise; + setAsFederated(roomId: IRoom['_id'], { mrid, origin }: { mrid: string; origin: string }): Promise; setRoomTypeById(roomId: IRoom['_id'], roomType: IRoom['t']): Promise; diff --git a/packages/models/src/models/AbacAttributes.ts b/packages/models/src/models/AbacAttributes.ts index 5ced8887ddfb0..24d1cf7aa46a8 100644 --- a/packages/models/src/models/AbacAttributes.ts +++ b/packages/models/src/models/AbacAttributes.ts @@ -15,4 +15,25 @@ export class AbacAttributesRaw extends BaseRaw { findOneByKey(key: string, options: FindOptions = {}): Promise { return this.findOne({ key }, options); } + + async countTotalValues(): Promise { + const [result] = await this.col + .aggregate<{ totalValues: number }>([ + { + $group: { + _id: null, + totalValues: { + $sum: { + $size: { + $ifNull: ['$values', []], + }, + }, + }, + }, + }, + ]) + .toArray(); + + return result?.totalValues ?? 0; + } } diff --git a/packages/models/src/models/Rooms.ts b/packages/models/src/models/Rooms.ts index 3dbfea10cdff2..1ec3304bc71fd 100644 --- a/packages/models/src/models/Rooms.ts +++ b/packages/models/src/models/Rooms.ts @@ -2312,4 +2312,8 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { // TODO implement return []; } + + countAbacEnabled(): Promise { + return this.countDocuments({ abacAttributes: { $exists: true } }); + } } From 917b547e7cc9437aedf5e2cec95bc1378c604e9b Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Tue, 25 Nov 2025 11:33:18 -0600 Subject: [PATCH 2/2] archived --- packages/models/src/models/Rooms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/models/src/models/Rooms.ts b/packages/models/src/models/Rooms.ts index 1ec3304bc71fd..7d28f32f63c32 100644 --- a/packages/models/src/models/Rooms.ts +++ b/packages/models/src/models/Rooms.ts @@ -2314,6 +2314,6 @@ export class RoomsRaw extends BaseRaw implements IRoomsModel { } countAbacEnabled(): Promise { - return this.countDocuments({ abacAttributes: { $exists: true } }); + return this.countDocuments({ abacAttributes: { $exists: true }, archived: { $ne: true } }); } }