From e519b8e859f795543f4e770e99e765aba3082088 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Sat, 6 Jul 2024 17:25:04 +0200 Subject: [PATCH 01/20] feat: userGroup monitoring script --- src/data/externalConfig/Namespaces.ts | 2 + .../MessageMSTeamsRepository.ts | 2 +- .../UserGroupD2Repository.ts | 22 +++ .../UserGroupsMonitoringConfigD2Repository.ts | 36 +++++ src/domain/entities/Base.ts | 1 + .../user-group-monitoring/UserGroups.ts | 87 +++++++++++ .../UserGroupsMonitoringOptions.ts | 8 + .../MessageRepository.ts | 0 .../UserGroupRepository.ts | 7 + .../UserGroupsMonitoringConfigRepository.ts | 6 + .../CompareMetadataObjectsUseCase.ts | 5 + .../GetLogFormatDateUseCase.ts | 19 +++ .../CompareMetadataObjectsUseCase.data.ts | 0 .../CompareMetadataObjectsUseCase.specs.ts | 0 .../MonitorUsersByAuthorityUseCase.ts | 2 +- .../SaveAuthoritiesMonitoringConfigUseCase.ts | 16 +- .../CompareUserGroupsUseCase.ts | 97 ++++++++++++ .../GetUserGroupsMonitoringConfigUseCase.ts | 9 ++ .../GetUserGroupsUseCase.ts | 12 ++ .../MonitorUserGroupsUseCase.ts | 125 +++++++++++++++ .../SaveUserGroupsMonitoringConfigUseCase.ts | 18 +++ .../CompareUserGroupsUseCase.data.ts | 145 ++++++++++++++++++ .../CompareUserGroupsUseCase.specs.ts | 23 +++ src/scripts/commands/usermonitoring.ts | 42 +++++ 24 files changed, 669 insertions(+), 15 deletions(-) create mode 100644 src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts create mode 100644 src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts create mode 100644 src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts create mode 100644 src/domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions.ts rename src/domain/repositories/user-monitoring/{authorities-monitoring => common}/MessageRepository.ts (100%) create mode 100644 src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts create mode 100644 src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts create mode 100644 src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.data.ts create mode 100644 src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.specs.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts create mode 100644 src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts diff --git a/src/data/externalConfig/Namespaces.ts b/src/data/externalConfig/Namespaces.ts index 4e5cfee9..aead6f0f 100644 --- a/src/data/externalConfig/Namespaces.ts +++ b/src/data/externalConfig/Namespaces.ts @@ -6,10 +6,12 @@ export const Namespace = { PERMISSION_FIXER: "permission-fixer", TWO_FACTOR_MONITORING: "two-factor-monitoring", AUTHORITIES_MONITOR: "authorities-monitor", + USER_GROUPS_MONITORING: "user-groups-monitoring", } as const; export const NamespaceProperties: Record = { [Namespace.PERMISSION_FIXER]: [], [Namespace.TWO_FACTOR_MONITORING]: [], [Namespace.AUTHORITIES_MONITOR]: [], + [Namespace.USER_GROUPS_MONITORING]: [], }; diff --git a/src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts b/src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts index 3cce9960..89901d68 100644 --- a/src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts +++ b/src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts @@ -2,7 +2,7 @@ import _, { isEmpty } from "lodash"; import log from "utils/log"; import { Async } from "domain/entities/Async"; import { MSTeamsWebhookOptions } from "data/user-monitoring/entities/MSTeamsWebhookOptions"; -import { MessageRepository } from "domain/repositories/user-monitoring/authorities-monitoring/MessageRepository"; +import { MessageRepository } from "domain/repositories/user-monitoring/common/MessageRepository"; export class MessageMSTeamsRepository implements MessageRepository { constructor(private webhook: MSTeamsWebhookOptions) {} diff --git a/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts b/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts new file mode 100644 index 00000000..03f25c1a --- /dev/null +++ b/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts @@ -0,0 +1,22 @@ +import { Id } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; +import { D2Api } from "@eyeseetea/d2-api/2.36"; + +export class UserGroupD2Repository implements UserGroupRepository { + constructor(private api: D2Api) {} + + async get(ids: Id[]): Async { + const { userGroups } = await this.api.metadata + .get({ + userGroups: { + fields: { $all: true, users: { id: true, name: true } }, + filter: { id: { in: ids } }, + }, + }) + .getData(); + + return userGroups as UserGroup[]; + } +} diff --git a/src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts b/src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts new file mode 100644 index 00000000..7d7b5e0a --- /dev/null +++ b/src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts @@ -0,0 +1,36 @@ +import _ from "lodash"; + +import log from "utils/log"; +import { D2Api } from "@eyeseetea/d2-api/2.36"; +import { Async } from "domain/entities/Async"; +import { getObject } from "../common/GetDataStoreObjectByKey"; +import { d2ToolsNamespace, Namespace } from "data/externalConfig/Namespaces"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; + +export class UserGroupsMonitoringConfigD2Repository implements UserGroupsMonitoringConfigRepository { + private api: D2Api; + + constructor(api: D2Api) { + this.api = api; + } + + public async get(): Async { + const config = await getObject( + this.api, + d2ToolsNamespace, + Namespace.USER_GROUPS_MONITORING + ); + + if (!config) { + log.warn("Error loading config from datastore"); + throw new Error("Error loading config from datastore"); + } + + return config; + } + + public async save(config: UserGroupsMonitoringOptions): Promise { + await this.api.dataStore(d2ToolsNamespace).save(Namespace.USER_GROUPS_MONITORING, config).getData(); + } +} diff --git a/src/domain/entities/Base.ts b/src/domain/entities/Base.ts index c1ef5894..a7456a48 100644 --- a/src/domain/entities/Base.ts +++ b/src/domain/entities/Base.ts @@ -20,5 +20,6 @@ export function getId(obj: Obj): Id { export type Code = string; export type Name = string; +export type Access = string; export type Identifiable = Id | Code | Name; diff --git a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts new file mode 100644 index 00000000..31b81431 --- /dev/null +++ b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts @@ -0,0 +1,87 @@ +import { D2UserGroup } from "@eyeseetea/d2-api/2.36"; +import { Access, Id, NamedRef, Ref } from "domain/entities/Base"; +import { U } from "vitest/dist/types-198fd1d9"; + +// export declare type D2UserGroup = { +// access: D2Access; +// attributeValues: D2AttributeValue[]; +// code: Id; +// created: string; +// createdBy: D2User; +// displayName: string; +// externalAccess: boolean; +// favorite: boolean; +// favorites: string[]; +// href: string; +// id: Id; +// lastUpdated: string; +// lastUpdatedBy: D2User; +// managedByGroups: D2UserGroup[]; +// managedGroups: D2UserGroup[]; +// name: string; +// publicAccess: string; +// sharing: Sharing; +// translations: D2Translation[]; +// user: D2User; +// userAccesses: D2UserAccess[]; +// userGroupAccesses: D2UserGroupAccess[]; +// users: D2User[]; +// }; +// export declare type D2UserGroupAccess = { +// access: string; +// displayName: string; +// id: string; +// userGroupUid: string; +// }; + +// declare type Access = string; +// interface IdAccess { +// id: Id; +// access: Access; +// } +export interface Sharing { + owner: Id; + public: Access; + external: boolean; + users: Record; + userGroups: Record; +} + +export type UserGroup = Pick & + Partial< + Omit< + D2UserGroup, + "users" | "lastUpdatedBy" | "managedByGroups" | "sharing" | "createdBy" | "user" + > & { + created: string; + lastUpdatedBy: UserDetails; + managedByGroups: Ref[]; + users: NamedRef[]; + sharing: Sharing; + createdBy: UserDetails; + user: UserDetails; + } + >; + +export type UserDetails = NamedRef & { + username: string; + displayName: string; +}; + +export type SharingUser = { + id: Id; + access: Access; + displayName: string; +}; + +export type UserGroupDiff = { + id: Id; + name: string; + newProps: Partial; + changedPropsLost: Partial; + changedPropsAdded: Partial; + usersChanges: { + users_Lost: NamedRef[]; + users_Added: NamedRef[]; + }; +}; diff --git a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions.ts b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions.ts new file mode 100644 index 00000000..c2e7e68e --- /dev/null +++ b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions.ts @@ -0,0 +1,8 @@ +import { Id } from "domain/entities/Base"; +import { UserGroup } from "./UserGroups"; + +export type UserGroupsMonitoringOptions = { + groupsToMonitor: Id[]; + lastExecution: string; + monitoredUserGroups: UserGroup[]; +}; diff --git a/src/domain/repositories/user-monitoring/authorities-monitoring/MessageRepository.ts b/src/domain/repositories/user-monitoring/common/MessageRepository.ts similarity index 100% rename from src/domain/repositories/user-monitoring/authorities-monitoring/MessageRepository.ts rename to src/domain/repositories/user-monitoring/common/MessageRepository.ts diff --git a/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts b/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts new file mode 100644 index 00000000..610a529e --- /dev/null +++ b/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts @@ -0,0 +1,7 @@ +import { Id } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; + +export interface UserGroupRepository { + get(ids: Id[]): Async; +} diff --git a/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts b/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts new file mode 100644 index 00000000..1a7c9bde --- /dev/null +++ b/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts @@ -0,0 +1,6 @@ +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; + +export interface UserGroupsMonitoringConfigRepository { + get(): Promise; + save(config: UserGroupsMonitoringOptions): Promise; +} diff --git a/src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts b/src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts new file mode 100644 index 00000000..66d06a46 --- /dev/null +++ b/src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts @@ -0,0 +1,5 @@ +export class CompareMetadataObjectsUseCase { + constructor() {} + + async execute(obj1: T, obj2: T): any[] {} +} diff --git a/src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts b/src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts new file mode 100644 index 00000000..4dedbe09 --- /dev/null +++ b/src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts @@ -0,0 +1,19 @@ +export class GetLogFormatDateUseCase { + private logFormatDate(date: Date): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); + const seconds = String(date.getSeconds()).padStart(2, "0"); + const milliseconds = String(date.getMilliseconds()).padStart(3, "0"); + + return `${year}-${month}-${day}T${hours}:${minutes}:${seconds},${milliseconds}`; + } + + constructor() {} + + execute(date: Date): string { + return this.logFormatDate(date); + } +} diff --git a/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.data.ts b/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.data.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.specs.ts b/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.specs.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts index 769ce6be..36aac299 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts @@ -2,7 +2,7 @@ import _ from "lodash"; import log from "utils/log"; import { Async } from "domain/entities/Async"; -import { MessageRepository } from "domain/repositories/user-monitoring/authorities-monitoring/MessageRepository"; +import { MessageRepository } from "domain/repositories/user-monitoring/common/MessageRepository"; import { UserRolesRepository } from "domain/repositories/user-monitoring/authorities-monitoring/UserRolesRepository"; import { AuthoritiesMonitoringConfigRepository } from "domain/repositories/user-monitoring/authorities-monitoring/AuthoritiesMonitoringConfigRepository"; diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts index b0a92a65..baf35908 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts @@ -6,23 +6,13 @@ import { UsersByAuthority, } from "domain/entities/user-monitoring/authorities-monitoring/AuthoritiesMonitoringOptions"; +import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; + export class SaveAuthoritiesMonitoringConfigUseCase { constructor(private configRepository: AuthoritiesMonitoringConfigRepository) {} - private logFormatDate(date: Date): string { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, "0"); - const day = String(date.getDate()).padStart(2, "0"); - const hours = String(date.getHours()).padStart(2, "0"); - const minutes = String(date.getMinutes()).padStart(2, "0"); - const seconds = String(date.getSeconds()).padStart(2, "0"); - const milliseconds = String(date.getMilliseconds()).padStart(3, "0"); - - return `${year}-${month}-${day}T${hours}:${minutes}:${seconds},${milliseconds}`; - } - async execute(options: AuthoritiesMonitoringOptions, usersByAuthority: UsersByAuthority): Async { - options.lastExecution = this.logFormatDate(new Date()); + options.lastExecution = new GetLogFormatDateUseCase().execute(new Date()); options.usersByAuthority = usersByAuthority; await this.configRepository.save(options); diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts new file mode 100644 index 00000000..83c3730d --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts @@ -0,0 +1,97 @@ +import _ from "lodash"; +import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; + +export class CompareUserGroupsUseCase { + constructor() {} + + private compareObjects(obj1: any, obj2: any): any { + return _.reduce( + obj1, + (result, value, key) => { + if (_.has(obj2, key)) { + const newValue = _.get(obj2, key); + + if (!_.isEqual(value, newValue)) { + if (_.isObjectLike(value) && _.isObjectLike(newValue)) { + const nestedDiff = this.compareObjects(value, newValue); + if (!_.isEmpty(nestedDiff)) { + return _.set(result, key, nestedDiff); + } + } else { + return _.set(result, key, newValue); + } + } + } + return result; + }, + {} + ); + } + + private getNewProps(oldUserGroup: UserGroup, newUserGroup: UserGroup): Partial { + let newProps: Partial = {}; + + _.forOwn(newUserGroup, (value, key) => { + if (!_.has(oldUserGroup, key)) { + newProps = _.set(newProps, key, value); + } else { + const oldValue = _.get(oldUserGroup, key, undefined); + if (!_.isEqual(value, oldValue)) { + if ((_.isObjectLike(oldValue) || _.isArrayLike(oldValue)) && _.isEmpty(oldValue)) { + newProps = _.set(newProps, key, value); + } + } + } + }); + + return newProps; + } + + private compareUserGroupProperties(oldUserGroup: UserGroup, newUserGroup: UserGroup): UserGroupDiff { + let changedPropsLost: Partial = {}; + let changedPropsAdded: Partial = {}; + let usersChanges = { + users_Lost: [], + users_Added: [], + }; + + _.forOwn(oldUserGroup, (value, key) => { + if (_.has(newUserGroup, key)) { + const newValue = _.get(newUserGroup, key, undefined); + + if (!_.isEqual(value, newValue)) { + if (key === "users") { + usersChanges = _.set( + usersChanges, + `${key}_Lost`, + _.differenceBy(value as any, newValue, "id") + ); + usersChanges = _.set( + usersChanges, + `${key}_Added`, + _.differenceBy(newValue, value as any, "id") + ); + } else { + changedPropsLost = _.set(changedPropsLost, key, value); + changedPropsAdded = _.set(changedPropsAdded, key, newValue); + } + } + } + }); + + const newProps = this.getNewProps(oldUserGroup, newUserGroup); + + return { + id: oldUserGroup.id, + name: oldUserGroup.name, + changedPropsLost: changedPropsLost, + changedPropsAdded: changedPropsAdded, + usersChanges: usersChanges, + newProps: newProps, + }; + } + + execute(oldUserGroup: UserGroup, newUserGroup: UserGroup): UserGroupDiff { + return this.compareUserGroupProperties(oldUserGroup, newUserGroup); + } +} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts new file mode 100644 index 00000000..fedbedd8 --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts @@ -0,0 +1,9 @@ +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; + +export class GetUserGroupsMonitoringConfigUseCase { + constructor(private configRepository: UserGroupsMonitoringConfigRepository) {} + + async execute() { + return this.configRepository.get(); + } +} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts new file mode 100644 index 00000000..13c45df1 --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts @@ -0,0 +1,12 @@ +import { Id } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; + +export class GetUserGroupsUseCase { + constructor(private userGroupRepository: UserGroupRepository) {} + + async execute(ids: Id[]): Async { + return this.userGroupRepository.get(ids); + } +} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts new file mode 100644 index 00000000..2441cdf8 --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts @@ -0,0 +1,125 @@ +import _ from "lodash"; +import log from "utils/log"; + +import { Id } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; + +import { MessageRepository } from "domain/repositories/user-monitoring/common/MessageRepository"; +import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; + +import { GetUserGroupsMonitoringConfigUseCase } from "./GetUserGroupsMonitoringConfigUseCase"; +import { GetUserGroupsUseCase } from "./GetUserGroupsUseCase"; +import { SaveUserGroupsMonitoringConfigUseCase } from "./SaveUserGroupsMonitoringConfigUseCase"; +import { CompareUserGroupsUseCase } from "./CompareUserGroupsUseCase"; + +export class MonitorUserGroupsUseCase { + constructor( + private userGroupRepository: UserGroupRepository, + private externalConfigRepository: UserGroupsMonitoringConfigRepository, + private MessageRepository: MessageRepository + ) {} + + private stringifyObject(ojb: any) { + return JSON.stringify(ojb, null, 2); + } + + private makeMessages(userGroupsChanges: UserGroupDiff[]): string { + const messages = userGroupsChanges.map(changes => { + const header = `Changes in group ${changes.id} | ${changes.name}:\n`; + const message = [header]; + let newPropsMsg = ""; + let changedPropsLostMsg = ""; + let changedPropsAddedMsg = ""; + + if (!_.isEmpty(changes.newProps)) { + newPropsMsg = `New entries:\n${this.stringifyObject(changes.newProps)}\n`; + message.push(newPropsMsg); + } + + if (!_.isEmpty(changes.changedPropsLost) && !_.isEmpty(changes.changedPropsAdded)) { + message.push("Modified fields:\n"); + + changedPropsLostMsg = `Old values:\n${this.stringifyObject(changes.changedPropsLost)}\n`; + message.push(changedPropsLostMsg); + + changedPropsAddedMsg = `New values:\n${this.stringifyObject(changes.changedPropsAdded)}\n`; + message.push(changedPropsAddedMsg); + } + + if (!_.isEmpty(changes.usersChanges.users_Lost) || !_.isEmpty(changes.usersChanges.users_Added)) { + message.push("User assignment changes:\n"); + + const usersLostMsg = `Users lost:\n${this.stringifyObject( + changes.usersChanges.users_Lost + )}\n`; + message.push(usersLostMsg); + + const usersAddedMsg = `Users added:\n${this.stringifyObject( + changes.usersChanges.users_Added + )}\n`; + message.push(usersAddedMsg); + } + return message.join("\n"); + }); + + return messages.join("\n\n"); + } + + async execute(setDataStore: boolean): Async { + const options: UserGroupsMonitoringOptions = await new GetUserGroupsMonitoringConfigUseCase( + this.externalConfigRepository + ).execute(); + + log.info(`Get user groups with ids: ${options.groupsToMonitor.join(", ")}`); + + const getGroupsUseCase = new GetUserGroupsUseCase(this.userGroupRepository); + const compareUserGroupsUseCase = new CompareUserGroupsUseCase(); + + const userGroups: UserGroup[] = await getGroupsUseCase.execute(options.groupsToMonitor); + log.info("Retrieved user groups:"); + + if (!setDataStore) { + const userGroupsChanges = userGroups.flatMap(group => { + const orig = options.monitoredUserGroups.find(g => g.id === group.id); + if (!orig) { + log.info("No previous data for this group."); + return []; + } + + const changes = compareUserGroupsUseCase.execute(orig, group); + + if ( + _.isEmpty(changes.changedPropsAdded) && + _.isEmpty(changes.changedPropsLost) && + _.isEmpty(changes.newProps) && + _.isEmpty(changes.usersChanges) + ) { + return []; + } + + return changes; + }); + + if (_.isEmpty(userGroupsChanges)) { + log.info("Report: No changes."); + } else { + const messages = this.makeMessages(userGroupsChanges); + // const teamsStatus = await this.MessageRepository.sendMessage(messages); + // if (teamsStatus) { + // log.info(`Message sent to MSTeams`); + // } + + log.info(`Report:\n${messages}`); + } + } + + // log.info("Updating datastore..."); + // await new SaveUserGroupsMonitoringConfigUseCase(this.externalConfigRepository).execute( + // options, + // userGroups + // ); + } +} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts new file mode 100644 index 00000000..7071cdbe --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts @@ -0,0 +1,18 @@ +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; + +import { Async } from "domain/entities/Async"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; +import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; + +import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; + +export class SaveUserGroupsMonitoringConfigUseCase { + constructor(private configRepository: UserGroupsMonitoringConfigRepository) {} + + async execute(options: UserGroupsMonitoringOptions, monitoredUserGroups: UserGroup[]): Async { + options.lastExecution = new GetLogFormatDateUseCase().execute(new Date()); + options.monitoredUserGroups = monitoredUserGroups; + + await this.configRepository.save(options); + } +} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts new file mode 100644 index 00000000..43bb577e --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts @@ -0,0 +1,145 @@ +import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; + +export const emptyDiff: UserGroupDiff = { + id: "UfhhwZK73Lg", + name: "WIDP IT team", + changedProps: {}, + newProps: {}, +}; + +export const minimalUserGroup: UserGroup = { + id: "UfhhwZK73Lg", + name: "WIDP IT team", +}; + +export const userGroup1: UserGroup = { + created: "2020-01-06T09:56:43.579", + lastUpdated: "2024-06-10T21:31:09.850", + name: "WIDP IT team", + id: "UfhhwZK73Lg", + href: "http://localhost:8080/api/userGroups/UfhhwZK73Lg", + displayName: "WIDP IT team", + publicAccess: "--------", + externalAccess: false, + favorite: false, + lastUpdatedBy: { + displayName: "Ignacio del Cano Costa", + name: "Ignacio del Cano Costa", + id: "kD52FGwJgDF", + username: "idelcano", + }, + access: { + read: true, + update: true, + externalize: true, + write: true, + delete: true, + manage: true, + }, + sharing: { + owner: "ilJDyuqlwDC", + userGroups: { + L2K8KDwssiB: { + displayName: "NTD user management", + access: "r-------", + id: "L2K8KDwssiB", + }, + L5dlGQ4m5av: { + displayName: "WIDP User Manager", + access: "r-------", + id: "L5dlGQ4m5av", + }, + UfhhwZK73Lg: { + displayName: "WIDP IT team", + access: "rw------", + id: "UfhhwZK73Lg", + }, + sCjEPgiOhP1: { + displayName: "WIDP admins", + access: "r-------", + id: "sCjEPgiOhP1", + }, + }, + external: false, + public: "--------", + users: {}, + }, + createdBy: { + displayName: "Lise GROUT", + name: "Lise GROUT", + id: "ilJDyuqlwDC", + username: "lise.grout", + }, + user: { + displayName: "Lise GROUT", + name: "Lise GROUT", + id: "ilJDyuqlwDC", + username: "lise.grout", + }, + favorites: [], + userGroupAccesses: [ + { + access: "r-------", + userGroupUid: "L2K8KDwssiB", + displayName: "NTD user management", + id: "L2K8KDwssiB", + }, + { + access: "r-------", + userGroupUid: "L5dlGQ4m5av", + displayName: "WIDP User Manager", + id: "L5dlGQ4m5av", + }, + { + access: "r-------", + userGroupUid: "sCjEPgiOhP1", + displayName: "WIDP admins", + id: "sCjEPgiOhP1", + }, + { + access: "rw------", + userGroupUid: "UfhhwZK73Lg", + displayName: "WIDP IT team", + id: "UfhhwZK73Lg", + }, + ], + managedByGroups: [ + { + id: "JusJWdDa1LM", + }, + ], + attributeValues: [], + users: [ + { + name: "Foche Ignacio", + id: "H4atNsEuKxP", + }, + { + name: "Nazar Shandra", + id: "hfaMYUsDm8u", + }, + { + name: "Marc GARNICA CAPARROS", + id: "UrYtDCrhioH", + }, + { + name: "Pablo Foche", + id: "Qu9goywu6cV", + }, + { + name: "Bot Basic access", + id: "QiUHDbdHdBU", + }, + { + name: "user dev", + id: "smGarTiKDdV", + }, + { + name: "Bot Automated-Tasks", + id: "bI1uY3KuAKV", + }, + ], + managedGroups: [], + translations: [], + userAccesses: [], +}; diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts new file mode 100644 index 00000000..610ade3a --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts @@ -0,0 +1,23 @@ +import { mock, when, instance } from "ts-mockito"; +import { describe, it, expect } from "vitest"; +import _ from "lodash"; + +import { CompareUserGroupsUseCase } from "../CompareUserGroupsUseCase"; +import { emptyDiff, minimalUserGroup, userGroup1 } from "./CompareUserGroupsUseCase.data"; + +describe("CompareUserGroupsUseCase", () => { + it("Should return empty array when comparing the same objects", () => { + const useCase = new CompareUserGroupsUseCase(); + + const minUserGroup2 = _.cloneDeep(minimalUserGroup); + + const result = useCase.execute(minimalUserGroup, minUserGroup2); + + const userGroup2 = _.cloneDeep(userGroup1); + + const result2 = useCase.execute(userGroup1, userGroup2); + + expect(result).toEqual(emptyDiff); + expect(result2).toEqual(emptyDiff); + }); +}); diff --git a/src/scripts/commands/usermonitoring.ts b/src/scripts/commands/usermonitoring.ts index 92da9bbe..5e8127ca 100644 --- a/src/scripts/commands/usermonitoring.ts +++ b/src/scripts/commands/usermonitoring.ts @@ -23,6 +23,10 @@ import { MessageMSTeamsRepository } from "data/user-monitoring/authorities-monit import { MSTeamsWebhookOptions } from "data/user-monitoring/entities/MSTeamsWebhookOptions"; import { MonitorUsersByAuthorityUseCase } from "domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase"; +import { UserGroupD2Repository } from "data/user-monitoring/user-group-monitoring/UserGroupD2Repository"; +import { UserGroupsMonitoringConfigD2Repository } from "data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository"; +import { MonitorUserGroupsUseCase } from "domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase"; + export function getCommand() { return subcommands({ name: "users-monitoring", @@ -30,6 +34,7 @@ export function getCommand() { "run-permissions-fixer": runUsersMonitoringCmd, "run-2fa-reporter": run2FAReporterCmd, "run-authorities-monitoring": runAuthoritiesMonitoring, + "run-user-group-monitoring": runUserGroupMonitoringCmd, }, }); } @@ -132,6 +137,43 @@ const runAuthoritiesMonitoring = command({ }, }); +const runUserGroupMonitoringCmd = command({ + name: "run-user-group-monitoring", + description: + "Run user group monitoring, a --config-file must be provided (usermonitoring run-user-group-monitoring --config-file config.json)", + args: { + config_file: option({ + type: string, + long: "config-file", + description: "Config file", + }), + setDataStore: flag({ + type: boolean, + short: "s", + long: "set-datastore", + description: + "Write users groups to datastore, use in script setup. It assumes there is a monitoring config in d2-tools/user-groups-monitoring", + }), + }, + + handler: async args => { + const auth = getAuthFromFile(args.config_file); + const webhook = getWebhookConfFromFile(args.config_file); + const api = getD2Api(auth.apiurl); + + const userGroupsRepository = new UserGroupD2Repository(api); + const externalConfigRepository = new UserGroupsMonitoringConfigD2Repository(api); + const MessageRepository = new MessageMSTeamsRepository(webhook); + + log.info(`Run User group monitoring`); + await new MonitorUserGroupsUseCase( + userGroupsRepository, + externalConfigRepository, + MessageRepository + ).execute(args.setDataStore); + }, +}); + function getAuthFromFile(config_file: string): UserMonitoringAuth { const fs = require("fs"); const configJSON = JSON.parse(fs.readFileSync("./" + config_file, "utf8")); From 4d0946aa472d1bc755940f2b14280086863fe901 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:59:06 +0200 Subject: [PATCH 02/20] feat: add README, enable commented code --- README.md | 52 +++++++++++++++++++ .../MonitorUserGroupsUseCase.ts | 18 +++---- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f0ec4b9a..bbbe52a2 100644 --- a/README.md +++ b/README.md @@ -668,6 +668,58 @@ A sample: } ``` +### User Groups Monitoring + +This script will compare the metadata of the monitored userGroups with the version stored in the datastore and generate a report of the changes. This report will be sent to the MS Teams channel set in the webhook config section. Then the new version of the metadata will be stored in the datastore. + +#### Execution: + +```bash +yarn install + +yarn build + +yarn start usermonitoring run-user-group-monitoring --config-file config.json + +# To get the debug logs and store them in a file use: +LOG_LEVEL=debug yarn start usermonitoring run-user-group-monitoring --config-file config.json &> user-group-monitoring.log +``` + +#### Parameters: + +- `--config-file`: Connection and webhook config file. +- `-s` | `--set-datastore`: Write usergroups data to datastore, use in script setup. It assumes there is a monitoring config in d2-tools/user-groups-monitoring. + +#### Requirements: + +A config file with the access info of the server and the message webhook details: + +```JSON +{ + "URL": { + "username": "user", + "password": "passwd", + "server": "https://dhis.url/" + }, + "WEBHOOK": { + "ms_url": "http://webhook.url/", + "proxy": "http://proxy.url/", + "server_name": "INSTANCE_NAME" + } +} +``` + +This reports stores data into the `d2-tools.user-groups-monitoring` datastore. This key needs to be setup before the first run to get a correct report. +Its possible to leave `monitoredUserGroups` empty and use the `-s` flag to populate it. + +The report, potentially, has tree sections for each user group: + +- New entries: JSON with the properties that were unset or empty and changed. +- Modified fields: This section has two JSONs, one showing the old values and one with the news. +- User assignment changes: This section will show the users lost and added to the group. + +If a section is empty it will be omited. + ## Move Attributes from a Program Get all the TEIS in the program and move the value from the attribute in the argument `--from-attribute-id` to the attribute `--to-attribute-id`. Then delete the value in `--from-attribute-id`. diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts index 2441cdf8..c9c2dfcf 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts @@ -107,19 +107,19 @@ export class MonitorUserGroupsUseCase { log.info("Report: No changes."); } else { const messages = this.makeMessages(userGroupsChanges); - // const teamsStatus = await this.MessageRepository.sendMessage(messages); - // if (teamsStatus) { - // log.info(`Message sent to MSTeams`); - // } + const teamsStatus = await this.MessageRepository.sendMessage(messages); + if (teamsStatus) { + log.info(`Message sent to MSTeams`); + } log.info(`Report:\n${messages}`); } } - // log.info("Updating datastore..."); - // await new SaveUserGroupsMonitoringConfigUseCase(this.externalConfigRepository).execute( - // options, - // userGroups - // ); + log.info("Updating datastore..."); + await new SaveUserGroupsMonitoringConfigUseCase(this.externalConfigRepository).execute( + options, + userGroups + ); } } From c6fb23f77c2301c10718a7055bd1e383b78f9717 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Sun, 7 Jul 2024 20:27:09 +0200 Subject: [PATCH 03/20] fix: update tests --- .../CompareUserGroupsUseCase.data.ts | 123 +++++++++--------- .../CompareUserGroupsUseCase.specs.ts | 3 +- 2 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts index 43bb577e..f75ceb5b 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts @@ -1,32 +1,37 @@ import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; export const emptyDiff: UserGroupDiff = { - id: "UfhhwZK73Lg", + id: "QW4BriFFvLi", name: "WIDP IT team", - changedProps: {}, + changedPropsLost: {}, + changedPropsAdded: {}, + usersChanges: { + users_Lost: [], + users_Added: [], + }, newProps: {}, }; export const minimalUserGroup: UserGroup = { - id: "UfhhwZK73Lg", + id: "QW4BriFFvLi", name: "WIDP IT team", }; export const userGroup1: UserGroup = { created: "2020-01-06T09:56:43.579", lastUpdated: "2024-06-10T21:31:09.850", - name: "WIDP IT team", - id: "UfhhwZK73Lg", - href: "http://localhost:8080/api/userGroups/UfhhwZK73Lg", - displayName: "WIDP IT team", + name: "Tech Team Alpha", + id: "id123", + href: "http://example.com/api/userGroups/id123", + displayName: "Tech Team Alpha", publicAccess: "--------", externalAccess: false, favorite: false, lastUpdatedBy: { - displayName: "Ignacio del Cano Costa", - name: "Ignacio del Cano Costa", - id: "kD52FGwJgDF", - username: "idelcano", + displayName: "User Alpha", + name: "User Alpha", + id: "user01", + username: "user.alpha", }, access: { read: true, @@ -37,27 +42,27 @@ export const userGroup1: UserGroup = { manage: true, }, sharing: { - owner: "ilJDyuqlwDC", + owner: "owner01", userGroups: { - L2K8KDwssiB: { - displayName: "NTD user management", + group01: { + displayName: "Project Management Team", access: "r-------", - id: "L2K8KDwssiB", + id: "group01", }, - L5dlGQ4m5av: { - displayName: "WIDP User Manager", + group02: { + displayName: "Development Team", access: "r-------", - id: "L5dlGQ4m5av", + id: "group02", }, - UfhhwZK73Lg: { - displayName: "WIDP IT team", + id123: { + displayName: "Tech Team Alpha", access: "rw------", - id: "UfhhwZK73Lg", + id: "id123", }, - sCjEPgiOhP1: { - displayName: "WIDP admins", + group03: { + displayName: "Operations Team", access: "r-------", - id: "sCjEPgiOhP1", + id: "group03", }, }, external: false, @@ -65,78 +70,78 @@ export const userGroup1: UserGroup = { users: {}, }, createdBy: { - displayName: "Lise GROUT", - name: "Lise GROUT", - id: "ilJDyuqlwDC", - username: "lise.grout", + displayName: "Alex Doe", + name: "Alex Doe", + id: "owner01", + username: "alex.doe", }, user: { - displayName: "Lise GROUT", - name: "Lise GROUT", - id: "ilJDyuqlwDC", - username: "lise.grout", + displayName: "Alex Doe", + name: "Alex Doe", + id: "owner01", + username: "alex.doe", }, favorites: [], userGroupAccesses: [ { access: "r-------", - userGroupUid: "L2K8KDwssiB", - displayName: "NTD user management", - id: "L2K8KDwssiB", + userGroupUid: "group01", + displayName: "Project Management Team", + id: "group01", }, { access: "r-------", - userGroupUid: "L5dlGQ4m5av", - displayName: "WIDP User Manager", - id: "L5dlGQ4m5av", + userGroupUid: "group02", + displayName: "Development Team", + id: "group02", }, { access: "r-------", - userGroupUid: "sCjEPgiOhP1", - displayName: "WIDP admins", - id: "sCjEPgiOhP1", + userGroupUid: "group03", + displayName: "Operations Team", + id: "group03", }, { access: "rw------", - userGroupUid: "UfhhwZK73Lg", - displayName: "WIDP IT team", - id: "UfhhwZK73Lg", + userGroupUid: "id123", + displayName: "Tech Team Alpha", + id: "id123", }, ], managedByGroups: [ { - id: "JusJWdDa1LM", + id: "managerGroup01", }, ], attributeValues: [], users: [ { - name: "Foche Ignacio", - id: "H4atNsEuKxP", + name: "John Smith", + id: "user02", }, { - name: "Nazar Shandra", - id: "hfaMYUsDm8u", + name: "Jane Doe", + id: "user03", }, { - name: "Marc GARNICA CAPARROS", - id: "UrYtDCrhioH", + name: "Mike Johnson", + id: "user04", }, { - name: "Pablo Foche", - id: "Qu9goywu6cV", + name: "Emily Davis", + id: "user05", }, { - name: "Bot Basic access", - id: "QiUHDbdHdBU", + name: "Chris Brown", + id: "user06", }, { - name: "user dev", - id: "smGarTiKDdV", + name: "Pat Taylor", + id: "user07", }, { - name: "Bot Automated-Tasks", - id: "bI1uY3KuAKV", + name: "Sam Robin", + id: "user08", }, ], managedGroups: [], diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts index 610ade3a..29ea1456 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts @@ -1,4 +1,3 @@ -import { mock, when, instance } from "ts-mockito"; import { describe, it, expect } from "vitest"; import _ from "lodash"; @@ -21,3 +20,5 @@ describe("CompareUserGroupsUseCase", () => { expect(result2).toEqual(emptyDiff); }); }); + +// TODO: Finish the tests From 8f0d708a4efe2d71fafa11a22b8b66c3ad91dcad Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Sun, 7 Jul 2024 20:28:35 +0200 Subject: [PATCH 04/20] fix: add missing changes --- .../__tests__/CompareUserGroupsUseCase.data.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts index f75ceb5b..5b8c678e 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts @@ -1,8 +1,8 @@ import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; export const emptyDiff: UserGroupDiff = { - id: "QW4BriFFvLi", - name: "WIDP IT team", + id: "id123", + name: "Tech Team Alpha", changedPropsLost: {}, changedPropsAdded: {}, usersChanges: { @@ -13,8 +13,8 @@ export const emptyDiff: UserGroupDiff = { }; export const minimalUserGroup: UserGroup = { - id: "QW4BriFFvLi", - name: "WIDP IT team", + id: "id123", + name: "Tech Team Alpha", }; export const userGroup1: UserGroup = { From 42494f508935e230eadbe1369565188d3346d2c7 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Sun, 7 Jul 2024 20:33:02 +0200 Subject: [PATCH 05/20] fix: remove old useCase and test --- .../user-monitoring/CompareMetadataObjectsUseCase.ts | 5 ----- .../__tests__/CompareMetadataObjectsUseCase.data.ts | 0 .../__tests__/CompareMetadataObjectsUseCase.specs.ts | 0 3 files changed, 5 deletions(-) delete mode 100644 src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts delete mode 100644 src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.data.ts delete mode 100644 src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.specs.ts diff --git a/src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts b/src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts deleted file mode 100644 index 66d06a46..00000000 --- a/src/domain/usecases/user-monitoring/CompareMetadataObjectsUseCase.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class CompareMetadataObjectsUseCase { - constructor() {} - - async execute(obj1: T, obj2: T): any[] {} -} diff --git a/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.data.ts b/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.data.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.specs.ts b/src/domain/usecases/user-monitoring/__tests__/CompareMetadataObjectsUseCase.specs.ts deleted file mode 100644 index e69de29b..00000000 From 14080ed05acc3529257882ce32471a8262ea0ac5 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:21:59 +0200 Subject: [PATCH 06/20] feat: add run-user-template-monitoring command, clean up UserGroups and minor fixes to user group monitoring files. --- src/data/externalConfig/Namespaces.ts | 2 + .../UserD2Repository.ts | 78 +++++++++ ...erTemplatesMonitoringConfigD2Repository.ts | 36 +++++ .../user-group-monitoring/UserGroups.ts | 39 ----- .../UserTemplatesMonitoringOptions.ts | 8 + .../user-template-monitoring/Users.ts | 26 +++ .../UserRepository.ts | 7 + ...UserTemplatesMonitoringConfigRepository.ts | 6 + .../CompareUserGroupsUseCase.ts | 2 +- .../MonitorUserGroupsUseCase.ts | 7 +- .../CompareUserTemplatesUseCase.ts | 81 ++++++++++ ...GetUserTemplatesMonitoringConfigUseCase.ts | 9 ++ .../GetUserTemplatesUseCase.ts | 12 ++ .../MonitorUserTemplatesUseCase.ts | 149 ++++++++++++++++++ ...aveUserTemplatesMonitoringConfigUseCase.ts | 18 +++ src/scripts/commands/usermonitoring.ts | 50 +++++- 16 files changed, 482 insertions(+), 48 deletions(-) create mode 100644 src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts create mode 100644 src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts create mode 100644 src/domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions.ts create mode 100644 src/domain/entities/user-monitoring/user-template-monitoring/Users.ts create mode 100644 src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts create mode 100644 src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts diff --git a/src/data/externalConfig/Namespaces.ts b/src/data/externalConfig/Namespaces.ts index aead6f0f..f61be247 100644 --- a/src/data/externalConfig/Namespaces.ts +++ b/src/data/externalConfig/Namespaces.ts @@ -7,6 +7,7 @@ export const Namespace = { TWO_FACTOR_MONITORING: "two-factor-monitoring", AUTHORITIES_MONITOR: "authorities-monitor", USER_GROUPS_MONITORING: "user-groups-monitoring", + USER_TEMPLATE_MONITORING: "user-template-monitoring", } as const; export const NamespaceProperties: Record = { @@ -14,4 +15,5 @@ export const NamespaceProperties: Record = { [Namespace.TWO_FACTOR_MONITORING]: [], [Namespace.AUTHORITIES_MONITOR]: [], [Namespace.USER_GROUPS_MONITORING]: [], + [Namespace.USER_TEMPLATE_MONITORING]: [], }; diff --git a/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts new file mode 100644 index 00000000..6a010428 --- /dev/null +++ b/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts @@ -0,0 +1,78 @@ +import { Username } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { UserRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserRepository"; +import { D2Api, SelectedPick, D2UserSchema } from "@eyeseetea/d2-api/2.36"; + +export class UserD2Repository implements UserRepository { + constructor(private api: D2Api) {} + + async getByUsername(usernames: Username[]): Async { + const users = await this.api.models.users + .get({ + fields: userFields, + filter: { username: { in: usernames } }, + }) + .getData(); + + return users.objects.map((user: D2User) => { + return { + ...user, + id: user.id, + username: user.username, + userCredentials: { + ...user.userCredentials, + }, + } as User; + }); + } +} + +const userFields = { + $all: true, + username: true, + userRoles: { id: true, name: true }, + userGroups: { id: true, name: true }, + userCredentials: { + access: true, + accountExpiry: true, + attributeValues: true, + catDimensionConstraints: true, + code: true, + cogsDimensionConstraints: true, + created: true, + createdBy: true, + disabled: true, + displayName: true, + externalAccess: true, + externalAuth: true, + favorite: true, + favorites: true, + href: true, + id: true, + invitation: true, + lastLogin: true, + lastUpdated: true, + lastUpdatedBy: true, + ldapId: true, + name: true, + openId: true, + password: true, + passwordLastUpdated: true, + publicAccess: true, + selfRegistered: true, + sharing: true, + translations: true, + twoFA: true, + user: true, + userAccesses: true, + userGroupAccesses: true, + userInfo: true, + username: true, + userRoles: false, + }, +} as const; + +type D2User = { + username?: string; +} & Partial>; diff --git a/src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts b/src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts new file mode 100644 index 00000000..c6e04584 --- /dev/null +++ b/src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts @@ -0,0 +1,36 @@ +import _ from "lodash"; + +import log from "utils/log"; +import { D2Api } from "@eyeseetea/d2-api/2.36"; +import { Async } from "domain/entities/Async"; +import { getObject } from "../common/GetDataStoreObjectByKey"; +import { d2ToolsNamespace, Namespace } from "data/externalConfig/Namespaces"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; + +export class UserTemplatesMonitoringConfigD2Repository implements UserTemplatesMonitoringConfigRepository { + private api: D2Api; + + constructor(api: D2Api) { + this.api = api; + } + + public async get(): Async { + const config = await getObject( + this.api, + d2ToolsNamespace, + Namespace.USER_TEMPLATE_MONITORING + ); + + if (!config) { + log.warn("Error loading config from datastore"); + throw new Error("Error loading config from datastore"); + } + + return config; + } + + public async save(config: UserTemplatesMonitoringOptions): Promise { + await this.api.dataStore(d2ToolsNamespace).save(Namespace.USER_TEMPLATE_MONITORING, config).getData(); + } +} diff --git a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts index 31b81431..611f880c 100644 --- a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts +++ b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts @@ -1,44 +1,5 @@ import { D2UserGroup } from "@eyeseetea/d2-api/2.36"; import { Access, Id, NamedRef, Ref } from "domain/entities/Base"; -import { U } from "vitest/dist/types-198fd1d9"; - -// export declare type D2UserGroup = { -// access: D2Access; -// attributeValues: D2AttributeValue[]; -// code: Id; -// created: string; -// createdBy: D2User; -// displayName: string; -// externalAccess: boolean; -// favorite: boolean; -// favorites: string[]; -// href: string; -// id: Id; -// lastUpdated: string; -// lastUpdatedBy: D2User; -// managedByGroups: D2UserGroup[]; -// managedGroups: D2UserGroup[]; -// name: string; -// publicAccess: string; -// sharing: Sharing; -// translations: D2Translation[]; -// user: D2User; -// userAccesses: D2UserAccess[]; -// userGroupAccesses: D2UserGroupAccess[]; -// users: D2User[]; -// }; -// export declare type D2UserGroupAccess = { -// access: string; -// displayName: string; -// id: string; -// userGroupUid: string; -// }; - -// declare type Access = string; -// interface IdAccess { -// id: Id; -// access: Access; -// } export interface Sharing { owner: Id; public: Access; diff --git a/src/domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions.ts b/src/domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions.ts new file mode 100644 index 00000000..5ce0fb60 --- /dev/null +++ b/src/domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions.ts @@ -0,0 +1,8 @@ +import { Username } from "domain/entities/Base"; +import { User } from "./Users"; + +export type UserTemplatesMonitoringOptions = { + templatesToMonitor: Username[]; + lastExecution: string; + monitoredUserTemplates: User[]; +}; diff --git a/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts b/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts new file mode 100644 index 00000000..1ac1ee2e --- /dev/null +++ b/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts @@ -0,0 +1,26 @@ +import { D2User, D2UserCredentials } from "@eyeseetea/d2-api/2.36"; +import { Id, Username, NamedRef } from "domain/entities/Base"; + +type UserCredentials = Partial>; + +export type User = { + id: Id; + username: Username; + userCredentials?: UserCredentials; +} & Partial; + +type MembershipChanges = { + userRoles_Lost: NamedRef[]; + userRoles_Added: NamedRef[]; + userGroups_Lost: NamedRef[]; + userGroups_Added: NamedRef[]; +}; + +export type UserTemplateDiff = { + id: Id; + username: Username; + newProps: Partial; + changedPropsLost: Partial; + changedPropsAdded: Partial; + membershipChanges: MembershipChanges; +}; diff --git a/src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts b/src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts new file mode 100644 index 00000000..bbad4551 --- /dev/null +++ b/src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts @@ -0,0 +1,7 @@ +import { Username } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; + +export interface UserRepository { + getByUsername(usernames: Username[]): Async; +} diff --git a/src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts b/src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts new file mode 100644 index 00000000..797371d9 --- /dev/null +++ b/src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts @@ -0,0 +1,6 @@ +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; + +export interface UserTemplatesMonitoringConfigRepository { + get(): Promise; + save(config: UserTemplatesMonitoringOptions): Promise; +} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts index 83c3730d..c6dfb1a3 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts @@ -57,7 +57,7 @@ export class CompareUserGroupsUseCase { _.forOwn(oldUserGroup, (value, key) => { if (_.has(newUserGroup, key)) { - const newValue = _.get(newUserGroup, key, undefined); + const newValue: any = _.get(newUserGroup, key, undefined); if (!_.isEqual(value, newValue)) { if (key === "users") { diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts index c9c2dfcf..a6269ce8 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts @@ -1,7 +1,6 @@ import _ from "lodash"; import log from "utils/log"; -import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; @@ -10,10 +9,10 @@ import { MessageRepository } from "domain/repositories/user-monitoring/common/Me import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; -import { GetUserGroupsMonitoringConfigUseCase } from "./GetUserGroupsMonitoringConfigUseCase"; import { GetUserGroupsUseCase } from "./GetUserGroupsUseCase"; -import { SaveUserGroupsMonitoringConfigUseCase } from "./SaveUserGroupsMonitoringConfigUseCase"; import { CompareUserGroupsUseCase } from "./CompareUserGroupsUseCase"; +import { GetUserGroupsMonitoringConfigUseCase } from "./GetUserGroupsMonitoringConfigUseCase"; +import { SaveUserGroupsMonitoringConfigUseCase } from "./SaveUserGroupsMonitoringConfigUseCase"; export class MonitorUserGroupsUseCase { constructor( @@ -79,7 +78,7 @@ export class MonitorUserGroupsUseCase { const compareUserGroupsUseCase = new CompareUserGroupsUseCase(); const userGroups: UserGroup[] = await getGroupsUseCase.execute(options.groupsToMonitor); - log.info("Retrieved user groups:"); + log.info(`Retrieved user groups: ${userGroups.map(g => g.id).join(", ")}`); if (!setDataStore) { const userGroupsChanges = userGroups.flatMap(group => { diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts new file mode 100644 index 00000000..06c25b7e --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts @@ -0,0 +1,81 @@ +import _ from "lodash"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; + +export class CompareUserTemplatesUseCase { + constructor() {} + + private membershipKeys = ["userRoles", "userGroups"]; + + private getNewProps(oldUserTemplate: User, newUserTemplate: User): Partial { + let newProps: Partial = {}; + + _.forOwn(newUserTemplate, (value, key) => { + if (this.membershipKeys.includes(key)) { + return; + } + + if (!_.has(oldUserTemplate, key)) { + newProps = _.set(newProps, key, value); + } else { + const oldValue = _.get(oldUserTemplate, key, undefined); + if (!_.isEqual(value, oldValue)) { + if ((_.isObjectLike(oldValue) || _.isArrayLike(oldValue)) && _.isEmpty(oldValue)) { + newProps = _.set(newProps, key, value); + } + } + } + }); + + return newProps; + } + + private compareMembershipProperties(oldUserTemplate: User, newUserTemplate: User): UserTemplateDiff { + let changedPropsLost: Partial = {}; + let changedPropsAdded: Partial = {}; + let membershipChanges = { + userRoles_Lost: [], + userRoles_Added: [], + userGroups_Lost: [], + userGroups_Added: [], + }; + + _.forOwn(oldUserTemplate, (value, key) => { + if (_.has(newUserTemplate, key)) { + const newValue: any = _.get(newUserTemplate, key, undefined); + + if (!_.isEqual(value, newValue)) { + if (this.membershipKeys.includes(key)) { + membershipChanges = _.set( + membershipChanges, + `${key}_Lost`, + _.differenceBy(value as any, newValue, "id") + ); + membershipChanges = _.set( + membershipChanges, + `${key}_Added`, + _.differenceBy(newValue, value as any, "id") + ); + } else { + changedPropsLost = _.set(changedPropsLost, key, value); + changedPropsAdded = _.set(changedPropsAdded, key, newValue); + } + } + } + }); + + const newProps = this.getNewProps(oldUserTemplate, newUserTemplate); + + return { + id: oldUserTemplate.id, + username: oldUserTemplate.username, + changedPropsLost: changedPropsLost, + changedPropsAdded: changedPropsAdded, + membershipChanges: membershipChanges, + newProps: newProps, + }; + } + + execute(oldUserTemplate: User, newUserTemplate: User): UserTemplateDiff { + return this.compareMembershipProperties(oldUserTemplate, newUserTemplate); + } +} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts new file mode 100644 index 00000000..785f93be --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts @@ -0,0 +1,9 @@ +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; + +export class GetUserTemplatesMonitoringConfigUseCase { + constructor(private configRepository: UserTemplatesMonitoringConfigRepository) {} + + async execute() { + return this.configRepository.get(); + } +} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts new file mode 100644 index 00000000..9c58de24 --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts @@ -0,0 +1,12 @@ +import { Username } from "domain/entities/Base"; +import { Async } from "domain/entities/Async"; +import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { UserRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserRepository"; + +export class GetUserTemplatesUseCase { + constructor(private userGroupRepository: UserRepository) {} + + async execute(usernames: Username[]): Async { + return this.userGroupRepository.getByUsername(usernames); + } +} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts new file mode 100644 index 00000000..1497861e --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts @@ -0,0 +1,149 @@ +import _ from "lodash"; +import log from "utils/log"; + +import { Async } from "domain/entities/Async"; +import { NamedRef } from "domain/entities/Base"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; + +import { MessageRepository } from "domain/repositories/user-monitoring/common/MessageRepository"; +import { UserRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserRepository"; +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; + +import { GetUserTemplatesUseCase } from "./GetUserTemplatesUseCase"; +import { CompareUserTemplatesUseCase } from "./CompareUserTemplatesUseCase"; +import { GetUserTemplatesMonitoringConfigUseCase } from "./GetUserTemplatesMonitoringConfigUseCase"; +import { SaveUserTemplatesMonitoringConfigUseCase } from "./SaveUserTemplatesMonitoringConfigUseCase"; + +export class MonitorUserTemplatesUseCase { + constructor( + private usersRepository: UserRepository, + private externalConfigRepository: UserTemplatesMonitoringConfigRepository, + private MessageRepository: MessageRepository + ) {} + + private stringifyObject(ojb: any) { + return JSON.stringify(ojb, null, 2); + } + + private checkMembershipChanges( + lostMembership: NamedRef[], + addedMembership: NamedRef[], + membershipType: "User Roles" | "User Groups" + ): string[] { + const message: string[] = []; + + if (!_.isEmpty(lostMembership) || !_.isEmpty(addedMembership)) { + message.push(`${membershipType} changes:\n`); + + const usersLostMsg = `${membershipType} lost:\n${this.stringifyObject(lostMembership)}\n`; + message.push(usersLostMsg); + + const usersAddedMsg = `${membershipType} added:\n${this.stringifyObject(addedMembership)}\n`; + message.push(usersAddedMsg); + } + + return message; + } + + private makeMessages(userTemplatesChanges: UserTemplateDiff[]): string { + const messages = userTemplatesChanges.map(changes => { + const header = `Changes in template ${changes.id} | ${changes.username}:\n`; + const message = [header]; + let newPropsMsg = ""; + let changedPropsLostMsg = ""; + let changedPropsAddedMsg = ""; + + if (!_.isEmpty(changes.newProps)) { + newPropsMsg = `New entries:\n${this.stringifyObject(changes.newProps)}\n`; + message.push(newPropsMsg); + } + + if (!_.isEmpty(changes.changedPropsLost) && !_.isEmpty(changes.changedPropsAdded)) { + message.push("Modified fields:\n"); + + changedPropsLostMsg = `Old values:\n${this.stringifyObject(changes.changedPropsLost)}\n`; + message.push(changedPropsLostMsg); + + changedPropsAddedMsg = `New values:\n${this.stringifyObject(changes.changedPropsAdded)}\n`; + message.push(changedPropsAddedMsg); + } + + const rolesMembershipMessage = this.checkMembershipChanges( + changes.membershipChanges.userRoles_Lost, + changes.membershipChanges.userRoles_Added, + "User Roles" + ); + + const groupsMembershipMessage = this.checkMembershipChanges( + changes.membershipChanges.userRoles_Lost, + changes.membershipChanges.userRoles_Added, + "User Groups" + ); + + message.push(...rolesMembershipMessage, ...groupsMembershipMessage); + + return message.join("\n"); + }); + + return messages.join("\n\n"); + } + + async execute(setDataStore: boolean): Async { + const options: UserTemplatesMonitoringOptions = await new GetUserTemplatesMonitoringConfigUseCase( + this.externalConfigRepository + ).execute(); + + log.info(`Get user groups with usernames: ${options.templatesToMonitor.join(", ")}`); + + const getTemplatesUseCase = new GetUserTemplatesUseCase(this.usersRepository); + const compareUserTemplatesUseCase = new CompareUserTemplatesUseCase(); + + const userTemplates: User[] = await getTemplatesUseCase.execute(options.templatesToMonitor); + log.info(`Retrieved user templates: ${userTemplates.map(g => g.username).join(", ")}`); + + if (!setDataStore) { + const userGroupsChanges = userTemplates.flatMap(user => { + const templateUsername = user.username; + const orig = options.monitoredUserTemplates.find(g => g.username === templateUsername); + if (!orig) { + log.info(`No previous data for template: ${templateUsername}.`); + return []; + } + + const changes = compareUserTemplatesUseCase.execute(orig, user); + + if ( + _.isEmpty(changes.changedPropsAdded) && + _.isEmpty(changes.changedPropsLost) && + _.isEmpty(changes.newProps) && + _.isEmpty(changes.membershipChanges) + ) { + return []; + } + + return changes; + }); + + log.info(`userGroupsChanges: ${this.stringifyObject(userGroupsChanges)}`); + + if (_.isEmpty(userGroupsChanges)) { + log.info("Report: No changes."); + } else { + const messages = this.makeMessages(userGroupsChanges); + const teamsStatus = await this.MessageRepository.sendMessage(messages); + if (teamsStatus) { + log.info(`Message sent to MSTeams`); + } + + log.info(`Report:\n${messages}`); + } + } + + log.info("Updating datastore..."); + await new SaveUserTemplatesMonitoringConfigUseCase(this.externalConfigRepository).execute( + options, + userTemplates + ); + } +} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts new file mode 100644 index 00000000..bb9fc0c0 --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts @@ -0,0 +1,18 @@ +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; + +import { Async } from "domain/entities/Async"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; +import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; + +import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; + +export class SaveUserTemplatesMonitoringConfigUseCase { + constructor(private configRepository: UserTemplatesMonitoringConfigRepository) {} + + async execute(options: UserTemplatesMonitoringOptions, monitoredUserTemplates: User[]): Async { + options.lastExecution = new GetLogFormatDateUseCase().execute(new Date()); + options.monitoredUserTemplates = monitoredUserTemplates; + + await this.configRepository.save(options); + } +} diff --git a/src/scripts/commands/usermonitoring.ts b/src/scripts/commands/usermonitoring.ts index 5e8127ca..f3325957 100644 --- a/src/scripts/commands/usermonitoring.ts +++ b/src/scripts/commands/usermonitoring.ts @@ -27,6 +27,10 @@ import { UserGroupD2Repository } from "data/user-monitoring/user-group-monitorin import { UserGroupsMonitoringConfigD2Repository } from "data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository"; import { MonitorUserGroupsUseCase } from "domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase"; +import { UserD2Repository } from "data/user-monitoring/user-template-monitoring/UserD2Repository"; +import { UserTemplatesMonitoringConfigD2Repository } from "data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository"; +import { MonitorUserTemplatesUseCase } from "domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase"; + export function getCommand() { return subcommands({ name: "users-monitoring", @@ -35,6 +39,7 @@ export function getCommand() { "run-2fa-reporter": run2FAReporterCmd, "run-authorities-monitoring": runAuthoritiesMonitoring, "run-user-group-monitoring": runUserGroupMonitoringCmd, + "run-user-template-monitoring": runUserTemplateMonitoringCmd, }, }); } @@ -126,13 +131,13 @@ const runAuthoritiesMonitoring = command({ const api = getD2Api(auth.apiurl); const UserRolesRepository = new UserRolesD2Repository(api); const externalConfigRepository = new AuthoritiesMonitoringConfigD2Repository(api); - const MessageRepository = new MessageMSTeamsRepository(webhook); + const messageRepository = new MessageMSTeamsRepository(webhook); log.info(`Run user authorities monitoring`); await new MonitorUsersByAuthorityUseCase( UserRolesRepository, externalConfigRepository, - MessageRepository + messageRepository ).execute(args.setDataStore); }, }); @@ -163,13 +168,50 @@ const runUserGroupMonitoringCmd = command({ const userGroupsRepository = new UserGroupD2Repository(api); const externalConfigRepository = new UserGroupsMonitoringConfigD2Repository(api); - const MessageRepository = new MessageMSTeamsRepository(webhook); + const messageRepository = new MessageMSTeamsRepository(webhook); log.info(`Run User group monitoring`); await new MonitorUserGroupsUseCase( userGroupsRepository, externalConfigRepository, - MessageRepository + messageRepository + ).execute(args.setDataStore); + }, +}); + +const runUserTemplateMonitoringCmd = command({ + name: "run-user-template-monitoring", + description: + "Run user template monitoring, a --config-file must be provided (usermonitoring run-user-template-monitoring --config-file config.json)", + args: { + config_file: option({ + type: string, + long: "config-file", + description: "Config file", + }), + setDataStore: flag({ + type: boolean, + short: "s", + long: "set-datastore", + description: + "Write users templates to datastore, use in script setup. It assumes there is a monitoring config in d2-tools/user-groups-monitoring", + }), + }, + + handler: async args => { + const auth = getAuthFromFile(args.config_file); + const webhook = getWebhookConfFromFile(args.config_file); + const api = getD2Api(auth.apiurl); + + const usersRepository = new UserD2Repository(api); + const externalConfigRepository = new UserTemplatesMonitoringConfigD2Repository(api); + const messageRepository = new MessageMSTeamsRepository(webhook); + + log.info(`Run User template monitoring`); + await new MonitorUserTemplatesUseCase( + usersRepository, + externalConfigRepository, + messageRepository ).execute(args.setDataStore); }, }); From 672eef83719d47cc9fc62bda0d033a24296b8982 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:18:58 +0200 Subject: [PATCH 07/20] feat: finish UserGroups compare test --- .../UserGroupD2Repository.ts | 19 +- src/domain/entities/Base.ts | 2 +- .../user-group-monitoring/UserGroups.ts | 6 +- .../CompareUserGroupsUseCase.data.ts | 268 ++++++++++++++++++ .../CompareUserGroupsUseCase.specs.ts | 16 +- 5 files changed, 303 insertions(+), 8 deletions(-) diff --git a/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts b/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts index 03f25c1a..f88e8db7 100644 --- a/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts +++ b/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts @@ -2,7 +2,7 @@ import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; -import { D2Api } from "@eyeseetea/d2-api/2.36"; +import { D2Api, MetadataPick, D2UserGroupSchema } from "@eyeseetea/d2-api/2.36"; export class UserGroupD2Repository implements UserGroupRepository { constructor(private api: D2Api) {} @@ -11,12 +11,25 @@ export class UserGroupD2Repository implements UserGroupRepository { const { userGroups } = await this.api.metadata .get({ userGroups: { - fields: { $all: true, users: { id: true, name: true } }, + fields: userFields, filter: { id: { in: ids } }, }, }) .getData(); - return userGroups as UserGroup[]; + return userGroups.map((userGroup: D2UserGroup) => { + return { + ...userGroup, + id: userGroup.id, + name: userGroup.name, + } as UserGroup; + }); } } + +const userFields = { $all: true, users: { id: true, name: true } } as const; + +type D2UserGroup = { + id: Id; + name: string; +} & Partial["userGroups"][number]>; diff --git a/src/domain/entities/Base.ts b/src/domain/entities/Base.ts index a7456a48..df3d38fa 100644 --- a/src/domain/entities/Base.ts +++ b/src/domain/entities/Base.ts @@ -20,6 +20,6 @@ export function getId(obj: Obj): Id { export type Code = string; export type Name = string; -export type Access = string; +export type IdAccess = { id: Id; access: string }; export type Identifiable = Id | Code | Name; diff --git a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts index 611f880c..521915de 100644 --- a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts +++ b/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts @@ -1,8 +1,8 @@ import { D2UserGroup } from "@eyeseetea/d2-api/2.36"; -import { Access, Id, NamedRef, Ref } from "domain/entities/Base"; +import { Id, NamedRef, Ref } from "domain/entities/Base"; export interface Sharing { owner: Id; - public: Access; + public: string; external: boolean; users: Record; userGroups: Record; @@ -31,7 +31,7 @@ export type UserDetails = NamedRef & { export type SharingUser = { id: Id; - access: Access; + access: string; displayName: string; }; diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts index 5b8c678e..d66256c3 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts @@ -12,6 +12,142 @@ export const emptyDiff: UserGroupDiff = { newProps: {}, }; +export const userGroup1Diff: UserGroupDiff = { + id: "id123", + name: "Tech Team Alpha", + changedPropsLost: { + displayName: "Tech Team Alpha", + lastUpdatedBy: { + displayName: "User Alpha", + name: "User Alpha", + id: "user01", + username: "user.alpha", + }, + sharing: { + owner: "owner01", + userGroups: { + group01: { + displayName: "Project Management Team", + access: "r-------", + id: "group01", + }, + group02: { + displayName: "Development Team", + access: "r-------", + id: "group02", + }, + id123: { + displayName: "Tech Team Alpha", + access: "rw------", + id: "id123", + }, + group03: { + displayName: "Operations Team", + access: "r-------", + id: "group03", + }, + }, + external: false, + public: "--------", + users: {}, + }, + userGroupAccesses: [ + { + access: "r-------", + userGroupUid: "group01", + displayName: "Project Management Team", + id: "group01", + }, + { + access: "r-------", + userGroupUid: "group02", + displayName: "Development Team", + id: "group02", + }, + { + access: "r-------", + userGroupUid: "group03", + displayName: "Operations Team", + id: "group03", + }, + { + access: "rw------", + userGroupUid: "id123", + displayName: "Tech Team Alpha", + id: "id123", + }, + ], + }, + changedPropsAdded: { + displayName: "Tech Team Beta", + lastUpdatedBy: { + displayName: "User Beta", + name: "User Beta", + id: "user02", + username: "user.beta", + }, + sharing: { + owner: "owner02", + userGroups: { + group01: { + displayName: "Project Management Team", + access: "r-------", + id: "group01", + }, + group02: { + displayName: "Development Team", + access: "r-------", + id: "group02", + }, + id456: { + displayName: "Tech Team Beta", + access: "rw------", + id: "id456", + }, + group03: { + displayName: "Operations Team", + access: "r-------", + id: "group03", + }, + }, + external: false, + public: "--------", + users: {}, + }, + userGroupAccesses: [ + { + access: "r-------", + userGroupUid: "group01", + displayName: "Project Management Team", + id: "group01", + }, + { + access: "r-------", + userGroupUid: "group02", + displayName: "Development Team", + id: "group02", + }, + { + access: "r-------", + userGroupUid: "group03", + displayName: "Operations Team", + id: "group03", + }, + { + access: "rw------", + userGroupUid: "id456", + displayName: "Tech Team Beta", + id: "id456", + }, + ], + }, + usersChanges: { + users_Lost: [], + users_Added: [], + }, + newProps: {}, +}; + export const minimalUserGroup: UserGroup = { id: "id123", name: "Tech Team Alpha", @@ -148,3 +284,135 @@ export const userGroup1: UserGroup = { translations: [], userAccesses: [], }; + +export const userGroup1Updated: UserGroup = { + created: "2020-01-06T09:56:43.579", + lastUpdated: "2024-06-10T21:31:09.850", + name: "Tech Team Alpha", + id: "id123", + href: "http://example.com/api/userGroups/id123", + displayName: "Tech Team Beta", + publicAccess: "--------", + externalAccess: false, + favorite: false, + lastUpdatedBy: { + displayName: "User Beta", + name: "User Beta", + id: "user02", + username: "user.beta", + }, + access: { + read: true, + update: true, + externalize: true, + write: true, + delete: true, + manage: true, + }, + sharing: { + owner: "owner02", + userGroups: { + group01: { + displayName: "Project Management Team", + access: "r-------", + id: "group01", + }, + group02: { + displayName: "Development Team", + access: "r-------", + id: "group02", + }, + id456: { + displayName: "Tech Team Beta", + access: "rw------", + id: "id456", + }, + group03: { + displayName: "Operations Team", + access: "r-------", + id: "group03", + }, + }, + external: false, + public: "--------", + users: {}, + }, + createdBy: { + displayName: "Alex Doe", + name: "Alex Doe", + id: "owner01", + username: "alex.doe", + }, + user: { + displayName: "Alex Doe", + name: "Alex Doe", + id: "owner01", + username: "alex.doe", + }, + favorites: [], + userGroupAccesses: [ + { + access: "r-------", + userGroupUid: "group01", + displayName: "Project Management Team", + id: "group01", + }, + { + access: "r-------", + userGroupUid: "group02", + displayName: "Development Team", + id: "group02", + }, + { + access: "r-------", + userGroupUid: "group03", + displayName: "Operations Team", + id: "group03", + }, + { + access: "rw------", + userGroupUid: "id456", + displayName: "Tech Team Beta", + id: "id456", + }, + ], + managedByGroups: [ + { + id: "managerGroup01", + }, + ], + attributeValues: [], + users: [ + { + name: "John Smith", + id: "user02", + }, + { + name: "Jane Doe", + id: "user03", + }, + { + name: "Mike Johnson", + id: "user04", + }, + { + name: "Emily Davis", + id: "user05", + }, + { + name: "Chris Brown", + id: "user06", + }, + { + name: "Pat Taylor", + id: "user07", + }, + { + name: "Sam Robin", + id: "user08", + }, + ], + managedGroups: [], + translations: [], + userAccesses: [], +}; diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts index 29ea1456..c627726f 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts @@ -2,7 +2,13 @@ import { describe, it, expect } from "vitest"; import _ from "lodash"; import { CompareUserGroupsUseCase } from "../CompareUserGroupsUseCase"; -import { emptyDiff, minimalUserGroup, userGroup1 } from "./CompareUserGroupsUseCase.data"; +import { + emptyDiff, + userGroup1Diff, + minimalUserGroup, + userGroup1, + userGroup1Updated, +} from "./CompareUserGroupsUseCase.data"; describe("CompareUserGroupsUseCase", () => { it("Should return empty array when comparing the same objects", () => { @@ -19,6 +25,14 @@ describe("CompareUserGroupsUseCase", () => { expect(result).toEqual(emptyDiff); expect(result2).toEqual(emptyDiff); }); + + it("Should return the differences between two user groups", () => { + const useCase = new CompareUserGroupsUseCase(); + + const result = useCase.execute(userGroup1, userGroup1Updated); + + expect(result).toEqual(userGroup1Diff); + }); }); // TODO: Finish the tests From 3f0bd6de81dbd68f10d9b34344667a50907fd8e7 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:34:53 +0200 Subject: [PATCH 08/20] feat: finish run-user-template-monitoring tests --- .../UserD2Repository.ts | 1 + src/domain/entities/Access.ts | 8 + .../user-template-monitoring/Users.ts | 85 +++- .../CompareUserTemplatesUseCase.data.ts | 449 ++++++++++++++++++ .../CompareUserTemplatesUseCase.specs.ts | 41 ++ 5 files changed, 579 insertions(+), 5 deletions(-) create mode 100644 src/domain/entities/Access.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts create mode 100644 src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts diff --git a/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts index 6a010428..37c2389c 100644 --- a/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts +++ b/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts @@ -12,6 +12,7 @@ export class UserD2Repository implements UserRepository { .get({ fields: userFields, filter: { username: { in: usernames } }, + paging: false, }) .getData(); diff --git a/src/domain/entities/Access.ts b/src/domain/entities/Access.ts new file mode 100644 index 00000000..8a47a036 --- /dev/null +++ b/src/domain/entities/Access.ts @@ -0,0 +1,8 @@ +export type Access = { + read: boolean; + update: boolean; + externalize: boolean; + write: boolean; + delete: boolean; + manage: boolean; +}; diff --git a/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts b/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts index 1ac1ee2e..8f34dcb0 100644 --- a/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts +++ b/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts @@ -1,13 +1,88 @@ -import { D2User, D2UserCredentials } from "@eyeseetea/d2-api/2.36"; -import { Id, Username, NamedRef } from "domain/entities/Base"; - -type UserCredentials = Partial>; +import { Access } from "domain/entities/Access"; +import { Id, Username, NamedRef, StringDateTime, Ref, IdAccess } from "domain/entities/Base"; +import { Translation } from "domain/entities/Translation"; export type User = { id: Id; username: Username; + lastUpdated?: StringDateTime; + created?: string; + twoFA?: boolean; + invitation?: boolean; + selfRegistered?: boolean; + firstName?: string; + name?: string; + favorite?: boolean; + displayName?: string; + externalAuth?: boolean; + externalAccess?: boolean; + surname?: string; + disabled?: boolean; + lastUpdatedBy?: UserReference; + sharing?: Sharing; + access?: Access; userCredentials?: UserCredentials; -} & Partial; + createdBy?: UserReference; + user?: UserReference; + translations?: Translation[]; + dataViewOrganisationUnits?: Ref[]; + attributeValues?: AttributeValue[]; + userGroups?: NamedRef[]; + userRoles?: NamedRef[]; + userAccesses?: UserAccess[]; + userGroupAccesses?: UserGroupAccess[]; + favorites?: string[]; + cogsDimensionConstraints?: Ref[]; + catDimensionConstraints?: Ref[]; + teiSearchOrganisationUnits?: Ref[]; + organisationUnits?: Ref[]; +}; + +type UserAccess = { + access: string; + displayName: string; + id: string; + userUid: string; +}; + +type UserGroupAccess = { + access: string; + displayName: string; + id: string; + userGroupUid: string; +}; + +type AttributeValue = { + attribute: Id; + value: string; +}; + +type UserReference = NamedRef & { + displayName: string; + username: string; +}; + +type Sharing = { + userGroups: Record; + external: boolean; + users: Record; +}; + +type UserCredentials = { + externalAuth: boolean; + disabled: boolean; + id: string; + twoFA?: boolean; + twoFactorEnabled?: boolean; + invitation: boolean; + selfRegistered: boolean; + username: string; + access: Access; + sharing: Sharing; + cogsDimensionConstraints: Ref[]; + catDimensionConstraints: Ref[]; + previousPasswords?: string[]; +}; type MembershipChanges = { userRoles_Lost: NamedRef[]; diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts new file mode 100644 index 00000000..4eb376fc --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts @@ -0,0 +1,449 @@ +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; + +export const user1: User = { + lastUpdated: "2024-06-10T10:25:27.228", + id: "cNtWc18LXBS", + created: "2018-06-09T01:05:48.008", + twoFA: false, + invitation: false, + selfRegistered: false, + firstName: "User Template", + name: "User Template", + favorite: false, + displayName: "User Template", + externalAuth: false, + externalAccess: false, + surname: "User", + disabled: true, + username: "user.template", + lastUpdatedBy: { + displayName: "User", + name: "User", + id: "user_id", + username: "user", + }, + sharing: { + userGroups: {}, + external: false, + users: {}, + }, + access: { + read: true, + update: true, + externalize: true, + write: true, + delete: true, + manage: true, + }, + userCredentials: { + externalAuth: false, + disabled: true, + id: "cNtWc18LXBS", + twoFA: false, + invitation: false, + selfRegistered: false, + username: "user.template", + access: { + read: true, + update: true, + externalize: true, + write: true, + delete: true, + manage: true, + }, + sharing: { + userGroups: {}, + external: false, + users: {}, + }, + cogsDimensionConstraints: [], + catDimensionConstraints: [], + previousPasswords: [], + }, + createdBy: { + displayName: "User", + name: "User", + id: "user_id", + username: "user", + }, + user: { + displayName: "User", + name: "User", + id: "user_id", + username: "user", + }, + translations: [], + dataViewOrganisationUnits: [ + { + id: "org_unit_id", + }, + ], + userGroupAccesses: [], + attributeValues: [], + userGroups: [ + { + name: "User Group 1", + id: "user_group_id_1", + }, + { + name: "User Group 2", + id: "user_group_id_2", + }, + ], + userRoles: [ + { + name: "Role 1", + id: "role_id_1", + }, + { + name: "Role 2", + id: "role_id_2", + }, + { + name: "Role 3", + id: "role_id_3", + }, + ], + userAccesses: [], + favorites: [], + cogsDimensionConstraints: [], + catDimensionConstraints: [], + teiSearchOrganisationUnits: [], + organisationUnits: [ + { + id: "org_unit_id", + }, + ], +}; + +export const user1Updated: User = { + lastUpdated: "2024-06-11T10:25:27.228", + id: "cNtWc18LXBS", + created: "2018-06-09T01:05:48.008", + twoFA: true, + invitation: true, + selfRegistered: true, + firstName: "Updated User Template", + name: "Updated User Template", + favorite: true, + displayName: "Updated User Template", + externalAuth: true, + externalAccess: true, + surname: "Updated User", + disabled: false, + username: "user.template", + lastUpdatedBy: { + displayName: "Updated User", + name: "Updated User", + id: "updated_user_id", + username: "updated_user", + }, + sharing: { + userGroups: {}, + external: true, + users: {}, + }, + access: { + read: false, + update: false, + externalize: false, + write: false, + delete: false, + manage: false, + }, + userCredentials: { + externalAuth: true, + disabled: false, + id: "cNtWc18LXBS", + twoFA: true, + invitation: true, + selfRegistered: true, + username: "user.template", + access: { + read: false, + update: false, + externalize: false, + write: false, + delete: false, + manage: false, + }, + sharing: { + userGroups: {}, + external: true, + users: {}, + }, + cogsDimensionConstraints: [], + catDimensionConstraints: [], + previousPasswords: [], + }, + createdBy: { + displayName: "Updated User", + name: "Updated User", + id: "updated_user_id", + username: "updated_user", + }, + user: { + displayName: "Updated User", + name: "Updated User", + id: "updated_user_id", + username: "updated_user", + }, + translations: [], + dataViewOrganisationUnits: [ + { + id: "updated_org_unit_id", + }, + ], + userGroupAccesses: [], + attributeValues: [], + userGroups: [ + { + name: "Updated User Group 1", + id: "updated_user_group_id_1", + }, + { + name: "Updated User Group 2", + id: "updated_user_group_id_2", + }, + ], + userRoles: [ + { + name: "Updated Role 1", + id: "updated_role_id_1", + }, + { + name: "Updated Role 2", + id: "updated_role_id_2", + }, + { + name: "Updated Role 3", + id: "updated_role_id_3", + }, + ], + userAccesses: [], + favorites: [], + cogsDimensionConstraints: [], + catDimensionConstraints: [], + teiSearchOrganisationUnits: [], + organisationUnits: [ + { + id: "updated_org_unit_id", + }, + ], +}; + +export const expectedDiff: UserTemplateDiff = { + id: "cNtWc18LXBS", + username: "user.template", + changedPropsLost: { + lastUpdated: "2024-06-10T10:25:27.228", + twoFA: false, + invitation: false, + selfRegistered: false, + firstName: "User Template", + name: "User Template", + favorite: false, + displayName: "User Template", + externalAuth: false, + externalAccess: false, + surname: "User", + disabled: true, + lastUpdatedBy: { + displayName: "User", + name: "User", + id: "user_id", + username: "user", + }, + sharing: { + userGroups: {}, + external: false, + users: {}, + }, + access: { + read: true, + update: true, + externalize: true, + write: true, + delete: true, + manage: true, + }, + userCredentials: { + externalAuth: false, + disabled: true, + id: "cNtWc18LXBS", + twoFA: false, + invitation: false, + selfRegistered: false, + username: "user.template", + access: { + read: true, + update: true, + externalize: true, + write: true, + delete: true, + manage: true, + }, + sharing: { + userGroups: {}, + external: false, + users: {}, + }, + cogsDimensionConstraints: [], + catDimensionConstraints: [], + previousPasswords: [], + }, + createdBy: { + displayName: "User", + name: "User", + id: "user_id", + username: "user", + }, + user: { + displayName: "User", + name: "User", + id: "user_id", + username: "user", + }, + dataViewOrganisationUnits: [ + { + id: "org_unit_id", + }, + ], + organisationUnits: [ + { + id: "org_unit_id", + }, + ], + }, + changedPropsAdded: { + lastUpdated: "2024-06-11T10:25:27.228", + twoFA: true, + invitation: true, + selfRegistered: true, + firstName: "Updated User Template", + name: "Updated User Template", + favorite: true, + displayName: "Updated User Template", + externalAuth: true, + externalAccess: true, + surname: "Updated User", + disabled: false, + lastUpdatedBy: { + displayName: "Updated User", + name: "Updated User", + id: "updated_user_id", + username: "updated_user", + }, + sharing: { + userGroups: {}, + external: true, + users: {}, + }, + access: { + read: false, + update: false, + externalize: false, + write: false, + delete: false, + manage: false, + }, + userCredentials: { + externalAuth: true, + disabled: false, + id: "cNtWc18LXBS", + twoFA: true, + invitation: true, + selfRegistered: true, + username: "user.template", + access: { + read: false, + update: false, + externalize: false, + write: false, + delete: false, + manage: false, + }, + sharing: { + userGroups: {}, + external: true, + users: {}, + }, + cogsDimensionConstraints: [], + catDimensionConstraints: [], + previousPasswords: [], + }, + createdBy: { + displayName: "Updated User", + name: "Updated User", + id: "updated_user_id", + username: "updated_user", + }, + user: { + displayName: "Updated User", + name: "Updated User", + id: "updated_user_id", + username: "updated_user", + }, + dataViewOrganisationUnits: [ + { + id: "updated_org_unit_id", + }, + ], + organisationUnits: [ + { + id: "updated_org_unit_id", + }, + ], + }, + membershipChanges: { + userRoles_Lost: [ + { + name: "Role 1", + id: "role_id_1", + }, + { + name: "Role 2", + id: "role_id_2", + }, + { + name: "Role 3", + id: "role_id_3", + }, + ], + userRoles_Added: [ + { + name: "Updated Role 1", + id: "updated_role_id_1", + }, + { + name: "Updated Role 2", + id: "updated_role_id_2", + }, + { + name: "Updated Role 3", + id: "updated_role_id_3", + }, + ], + userGroups_Lost: [ + { + name: "User Group 1", + id: "user_group_id_1", + }, + { + name: "User Group 2", + id: "user_group_id_2", + }, + ], + userGroups_Added: [ + { + name: "Updated User Group 1", + id: "updated_user_group_id_1", + }, + { + name: "Updated User Group 2", + id: "updated_user_group_id_2", + }, + ], + }, + newProps: {}, +}; diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts new file mode 100644 index 00000000..f568bddc --- /dev/null +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts @@ -0,0 +1,41 @@ +import { describe, it, expect, beforeEach } from "vitest"; + +import { user1, user1Updated, expectedDiff } from "./CompareUserTemplatesUseCase.data"; + +import { CompareUserTemplatesUseCase } from "../CompareUserTemplatesUseCase"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; + +describe("CompareUserTemplatesUseCase", () => { + let useCase: CompareUserTemplatesUseCase; + + beforeEach(() => { + useCase = new CompareUserTemplatesUseCase(); + }); + + it("should not fild differences between the same user templates", () => { + const noChangesDiff: UserTemplateDiff = { + id: user1.id, + username: user1.username, + changedPropsLost: {}, + changedPropsAdded: {}, + membershipChanges: { + userRoles_Lost: [], + userRoles_Added: [], + userGroups_Lost: [], + userGroups_Added: [], + }, + newProps: {}, + }; + + const diff = useCase.execute(user1, user1); + + expect(diff).toEqual(noChangesDiff); + }); + + it("should compare user templates and return the differences", () => { + const diff = useCase.execute(user1, user1Updated); + console.log(JSON.stringify(diff, null, 2)); + + expect(diff).toEqual(expectedDiff); + }); +}); From 691685c0cf180a4e3929f58dc2dd8c62cf19fdc7 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:36:55 +0200 Subject: [PATCH 09/20] feat: make MessageMSTeamsRepository common. --- .../MessageMSTeamsRepository.ts | 4 ++-- .../repositories/user-monitoring/common/MessageRepository.ts | 2 +- .../authorities-monitoring/MonitorUsersByAuthorityUseCase.ts | 5 ++++- .../user-group-monitoring/MonitorUserGroupsUseCase.ts | 5 ++++- .../user-template-monitoring/MonitorUserTemplatesUseCase.ts | 5 ++++- src/scripts/commands/usermonitoring.ts | 2 +- 6 files changed, 16 insertions(+), 7 deletions(-) rename src/data/user-monitoring/{authorities-monitoring => common}/MessageMSTeamsRepository.ts (89%) diff --git a/src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts b/src/data/user-monitoring/common/MessageMSTeamsRepository.ts similarity index 89% rename from src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts rename to src/data/user-monitoring/common/MessageMSTeamsRepository.ts index 89901d68..15381035 100644 --- a/src/data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository.ts +++ b/src/data/user-monitoring/common/MessageMSTeamsRepository.ts @@ -7,7 +7,7 @@ import { MessageRepository } from "domain/repositories/user-monitoring/common/Me export class MessageMSTeamsRepository implements MessageRepository { constructor(private webhook: MSTeamsWebhookOptions) {} - async sendMessage(message: string): Async { + async sendMessage(messageType: string, message: string): Async { const httpProxy = this.webhook.proxy; const url = this.webhook.ms_url; const server_name = this.webhook.server_name; @@ -18,7 +18,7 @@ export class MessageMSTeamsRepository implements MessageRepository { } const postData = JSON.stringify({ - text: `[*AUTHORITIES-MONITORING* - ${server_name}] - ${message}`, + text: `[*${messageType}* - ${server_name}] - ${message}`, }); const requestOptions = { diff --git a/src/domain/repositories/user-monitoring/common/MessageRepository.ts b/src/domain/repositories/user-monitoring/common/MessageRepository.ts index 08ae34eb..ad8bdfc0 100644 --- a/src/domain/repositories/user-monitoring/common/MessageRepository.ts +++ b/src/domain/repositories/user-monitoring/common/MessageRepository.ts @@ -1,5 +1,5 @@ import { Async } from "domain/entities/Async"; export interface MessageRepository { - sendMessage(message: string): Async; + sendMessage(messageType: string, message: string): Async; } diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts index 36aac299..9a7c4ab6 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts @@ -74,7 +74,10 @@ export class MonitorUsersByAuthorityUseCase { log.info("Report: No changes."); } else { const messages = this.makeMessages(newUsers, usersLosingAuth); - const teamsStatus = await this.MessageRepository.sendMessage(messages); + const teamsStatus = await this.MessageRepository.sendMessage( + "AUTHORITIES-MONITORING", + messages + ); if (teamsStatus) { log.info(`Message sent to MSTeams`); } diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts index a6269ce8..24932841 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts @@ -106,7 +106,10 @@ export class MonitorUserGroupsUseCase { log.info("Report: No changes."); } else { const messages = this.makeMessages(userGroupsChanges); - const teamsStatus = await this.MessageRepository.sendMessage(messages); + const teamsStatus = await this.MessageRepository.sendMessage( + "USERGROUPS-MONITORING", + messages + ); if (teamsStatus) { log.info(`Message sent to MSTeams`); } diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts index 1497861e..039c91cf 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts @@ -131,7 +131,10 @@ export class MonitorUserTemplatesUseCase { log.info("Report: No changes."); } else { const messages = this.makeMessages(userGroupsChanges); - const teamsStatus = await this.MessageRepository.sendMessage(messages); + const teamsStatus = await this.MessageRepository.sendMessage( + "USER-TEMPLATES-MONITORING", + messages + ); if (teamsStatus) { log.info(`Message sent to MSTeams`); } diff --git a/src/scripts/commands/usermonitoring.ts b/src/scripts/commands/usermonitoring.ts index f3325957..c8d9176d 100644 --- a/src/scripts/commands/usermonitoring.ts +++ b/src/scripts/commands/usermonitoring.ts @@ -19,7 +19,7 @@ import { PermissionFixerUserD2Repository } from "data/user-monitoring/permission import { AuthoritiesMonitoringConfigD2Repository } from "data/user-monitoring/authorities-monitoring/AuthoritiesMonitoringConfigD2Repository"; import { UserRolesD2Repository } from "data/user-monitoring/authorities-monitoring/UserRolesD2Repository"; -import { MessageMSTeamsRepository } from "data/user-monitoring/authorities-monitoring/MessageMSTeamsRepository"; +import { MessageMSTeamsRepository } from "data/user-monitoring/common/MessageMSTeamsRepository"; import { MSTeamsWebhookOptions } from "data/user-monitoring/entities/MSTeamsWebhookOptions"; import { MonitorUsersByAuthorityUseCase } from "domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase"; From a6b222f28a05ca9f05fc27b2315610236276d8e8 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:40:27 +0200 Subject: [PATCH 10/20] fix: clean-up leftovers in tests. --- .../__tests__/CompareUserGroupsUseCase.specs.ts | 2 -- .../__tests__/CompareUserTemplatesUseCase.specs.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts index c627726f..976799c2 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts @@ -34,5 +34,3 @@ describe("CompareUserGroupsUseCase", () => { expect(result).toEqual(userGroup1Diff); }); }); - -// TODO: Finish the tests diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts index f568bddc..2e1ddfea 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts @@ -34,7 +34,6 @@ describe("CompareUserTemplatesUseCase", () => { it("should compare user templates and return the differences", () => { const diff = useCase.execute(user1, user1Updated); - console.log(JSON.stringify(diff, null, 2)); expect(diff).toEqual(expectedDiff); }); From 99fa14430ec01354e5ec6e32248ea9dfda5b55cb Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:58:19 +0200 Subject: [PATCH 11/20] fix: change run-user-template-monitoring to run-user-templates-monitoring for consistency --- src/data/externalConfig/Namespaces.ts | 4 ++-- src/scripts/commands/usermonitoring.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/externalConfig/Namespaces.ts b/src/data/externalConfig/Namespaces.ts index f61be247..e2c12bf7 100644 --- a/src/data/externalConfig/Namespaces.ts +++ b/src/data/externalConfig/Namespaces.ts @@ -1,13 +1,13 @@ export const d2ToolsNamespace = "d2-tools"; -export type Namespace = typeof Namespace[keyof typeof Namespace]; +export type Namespace = (typeof Namespace)[keyof typeof Namespace]; export const Namespace = { PERMISSION_FIXER: "permission-fixer", TWO_FACTOR_MONITORING: "two-factor-monitoring", AUTHORITIES_MONITOR: "authorities-monitor", USER_GROUPS_MONITORING: "user-groups-monitoring", - USER_TEMPLATE_MONITORING: "user-template-monitoring", + USER_TEMPLATE_MONITORING: "user-templates-monitoring", } as const; export const NamespaceProperties: Record = { diff --git a/src/scripts/commands/usermonitoring.ts b/src/scripts/commands/usermonitoring.ts index c8d9176d..e9239330 100644 --- a/src/scripts/commands/usermonitoring.ts +++ b/src/scripts/commands/usermonitoring.ts @@ -39,7 +39,7 @@ export function getCommand() { "run-2fa-reporter": run2FAReporterCmd, "run-authorities-monitoring": runAuthoritiesMonitoring, "run-user-group-monitoring": runUserGroupMonitoringCmd, - "run-user-template-monitoring": runUserTemplateMonitoringCmd, + "run-user-templates-monitoring": runUserTemplateMonitoringCmd, }, }); } @@ -180,7 +180,7 @@ const runUserGroupMonitoringCmd = command({ }); const runUserTemplateMonitoringCmd = command({ - name: "run-user-template-monitoring", + name: "run-user-templates-monitoring", description: "Run user template monitoring, a --config-file must be provided (usermonitoring run-user-template-monitoring --config-file config.json)", args: { From f85b244e1f89658bfea7ec7bd5d98ef2d1d8c1d9 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:58:42 +0200 Subject: [PATCH 12/20] feat: Add README for run-user-templates-monitoring --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 41f0bbde..658639f5 100644 --- a/README.md +++ b/README.md @@ -724,7 +724,62 @@ The report, potentially, has tree sections for each user group: - Modified fields: This section has two JSONs, one showing the old values and one with the news. - User assignment changes: This section will show the users lost and added to the group. -If a section is empty it will be omited. +If a section is empty it will be omitted. + +### User Templates Monitoring + +The User Templates Monitoring script is used to compare user templates with the version stored in the datastore and generate a report of the changes. The report includes information on modified fields, and a detailed report on user groups and roles added or lost. This report will be sent to the MS Teams channel set in the webhook config section. The new version of the metadata will be stored in the datastore. + +#### Execution: + +```bash +yarn install + +yarn build + +yarn start usermonitoring run-user-templates-monitoring --config-file config.json + +# To get the debug logs and store them in a file use: +LOG_LEVEL=debug yarn start usermonitoring run-user-templates-monitoring --config-file config.json &> user-templates-monitoring.log +``` + +#### Parameters: + +- `--config-file`: Connection and webhook config file. +- `-s` | `--set-datastore`: Write user templates data to datastore, use in script setup. It assumes there is a monitoring config in d2-tools/user-templates-monitoring. + +#### Requirements: + +A config file with the access info of the server and the message webhook details: + +```JSON +{ + "URL": { + "username": "user", + "password": "passwd", + "server": "https://dhis.url/" + }, + "WEBHOOK": { + "ms_url": "http://webhook.url/", + "proxy": "http://proxy.url/", + "server_name": "INSTANCE_NAME" + } +} +``` + +#### Report + +This reports stores data into the `d2-tools.user-templates-monitoring` datastore. This key needs to be setup before the first run to get a correct report. + +Its possible to leave `monitoredUserTemplates` empty and use the `-s` flag to populate it. + +The report includes the following sections: + +- New entries: This section lists new properties that didn't exist in the old version. +- Modified fields: This section shows the fields that have been modified in the user templates and shows the before/after values. +- User Membership changes: This section displays the changes in the template userGroups and userRoles membership. + +If a section is empty, it will be omitted from the report. ## Move Attributes from a Program From 8ceeadebe99b20c04be257d49118e57298aa1a88 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Fri, 6 Sep 2024 08:34:28 +0200 Subject: [PATCH 13/20] fix: make folder naming consistent with script name, fix typos --- README.md | 4 ++-- .../UserGroupD2Repository.ts | 4 ++-- .../UserGroupsMonitoringConfigD2Repository.ts | 4 ++-- .../UserD2Repository.ts | 4 ++-- ...erTemplatesMonitoringConfigD2Repository.ts | 4 ++-- .../UserGroups.ts | 0 .../UserGroupsMonitoringOptions.ts | 0 .../UserTemplatesMonitoringOptions.ts | 0 .../Users.ts | 0 .../UserGroupRepository.ts | 2 +- .../UserGroupsMonitoringConfigRepository.ts | 2 +- .../UserRepository.ts | 2 +- ...UserTemplatesMonitoringConfigRepository.ts | 2 +- .../CompareUserGroupsUseCase.ts | 2 +- .../GetUserGroupsMonitoringConfigUseCase.ts | 2 +- .../GetUserGroupsUseCase.ts | 4 ++-- .../MonitorUserGroupsUseCase.ts | 8 +++---- .../SaveUserGroupsMonitoringConfigUseCase.ts | 6 ++--- .../CompareUserGroupsUseCase.data.ts | 2 +- .../CompareUserGroupsUseCase.specs.ts | 0 .../CompareUserTemplatesUseCase.ts | 2 +- ...GetUserTemplatesMonitoringConfigUseCase.ts | 2 +- .../GetUserTemplatesUseCase.ts | 4 ++-- .../MonitorUserTemplatesUseCase.ts | 8 +++---- ...aveUserTemplatesMonitoringConfigUseCase.ts | 6 ++--- .../CompareUserTemplatesUseCase.data.ts | 2 +- .../CompareUserTemplatesUseCase.specs.ts | 2 +- src/scripts/commands/usermonitoring.ts | 22 +++++++++---------- 28 files changed, 50 insertions(+), 50 deletions(-) rename src/data/user-monitoring/{user-group-monitoring => user-groups-monitoring}/UserGroupD2Repository.ts (93%) rename src/data/user-monitoring/{user-group-monitoring => user-groups-monitoring}/UserGroupsMonitoringConfigD2Repository.ts (88%) rename src/data/user-monitoring/{user-template-monitoring => user-templates-monitoring}/UserD2Repository.ts (96%) rename src/data/user-monitoring/{user-template-monitoring => user-templates-monitoring}/UserTemplatesMonitoringConfigD2Repository.ts (87%) rename src/domain/entities/user-monitoring/{user-group-monitoring => user-groups-monitoring}/UserGroups.ts (100%) rename src/domain/entities/user-monitoring/{user-group-monitoring => user-groups-monitoring}/UserGroupsMonitoringOptions.ts (100%) rename src/domain/entities/user-monitoring/{user-template-monitoring => user-templates-monitoring}/UserTemplatesMonitoringOptions.ts (100%) rename src/domain/entities/user-monitoring/{user-template-monitoring => user-templates-monitoring}/Users.ts (100%) rename src/domain/repositories/user-monitoring/{user-group-monitoring => user-groups-monitoring}/UserGroupRepository.ts (88%) rename src/domain/repositories/user-monitoring/{user-group-monitoring => user-groups-monitoring}/UserGroupsMonitoringConfigRepository.ts (78%) rename src/domain/repositories/user-monitoring/{user-template-monitoring => user-templates-monitoring}/UserRepository.ts (91%) rename src/domain/repositories/user-monitoring/{user-template-monitoring => user-templates-monitoring}/UserTemplatesMonitoringConfigRepository.ts (76%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/CompareUserGroupsUseCase.ts (98%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/GetUserGroupsMonitoringConfigUseCase.ts (75%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/GetUserGroupsUseCase.ts (83%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/MonitorUserGroupsUseCase.ts (95%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/SaveUserGroupsMonitoringConfigUseCase.ts (80%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/__tests__/CompareUserGroupsUseCase.data.ts (99%) rename src/domain/usecases/user-monitoring/{user-group-monitoring => user-groups-monitoring}/__tests__/CompareUserGroupsUseCase.specs.ts (100%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/CompareUserTemplatesUseCase.ts (98%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/GetUserTemplatesMonitoringConfigUseCase.ts (74%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/GetUserTemplatesUseCase.ts (86%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/MonitorUserTemplatesUseCase.ts (95%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/SaveUserTemplatesMonitoringConfigUseCase.ts (79%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/__tests__/CompareUserTemplatesUseCase.data.ts (99%) rename src/domain/usecases/user-monitoring/{user-template-monitoring => user-templates-monitoring}/__tests__/CompareUserTemplatesUseCase.specs.ts (96%) diff --git a/README.md b/README.md index 658639f5..47b0a2cb 100644 --- a/README.md +++ b/README.md @@ -685,10 +685,10 @@ yarn install yarn build -yarn start usermonitoring run-user-group-monitoring --config-file config.json +yarn start usermonitoring run-user-groups-monitoring --config-file config.json # To get the debug logs and store them in a file use: -LOG_LEVEL=debug yarn start usermonitoring run-user-group-monitoring --config-file config.json &> user-group-monitoring.log +LOG_LEVEL=debug yarn start usermonitoring run-user-groups-monitoring --config-file config.json &> user-groups-monitoring.log ``` #### Parameters: diff --git a/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts similarity index 93% rename from src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts rename to src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts index f88e8db7..c870837f 100644 --- a/src/data/user-monitoring/user-group-monitoring/UserGroupD2Repository.ts +++ b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts @@ -1,7 +1,7 @@ import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; -import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; -import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; +import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; +import { UserGroupRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository"; import { D2Api, MetadataPick, D2UserGroupSchema } from "@eyeseetea/d2-api/2.36"; export class UserGroupD2Repository implements UserGroupRepository { diff --git a/src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts b/src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts similarity index 88% rename from src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts rename to src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts index 7d7b5e0a..32f7529c 100644 --- a/src/data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository.ts +++ b/src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts @@ -5,8 +5,8 @@ import { D2Api } from "@eyeseetea/d2-api/2.36"; import { Async } from "domain/entities/Async"; import { getObject } from "../common/GetDataStoreObjectByKey"; import { d2ToolsNamespace, Namespace } from "data/externalConfig/Namespaces"; -import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; -import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; export class UserGroupsMonitoringConfigD2Repository implements UserGroupsMonitoringConfigRepository { private api: D2Api; diff --git a/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts similarity index 96% rename from src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts rename to src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts index 37c2389c..7320f189 100644 --- a/src/data/user-monitoring/user-template-monitoring/UserD2Repository.ts +++ b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts @@ -1,7 +1,7 @@ import { Username } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; -import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; -import { UserRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserRepository"; +import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; +import { UserRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserRepository"; import { D2Api, SelectedPick, D2UserSchema } from "@eyeseetea/d2-api/2.36"; export class UserD2Repository implements UserRepository { diff --git a/src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts b/src/data/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigD2Repository.ts similarity index 87% rename from src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts rename to src/data/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigD2Repository.ts index c6e04584..e11d629b 100644 --- a/src/data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository.ts +++ b/src/data/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigD2Repository.ts @@ -5,8 +5,8 @@ import { D2Api } from "@eyeseetea/d2-api/2.36"; import { Async } from "domain/entities/Async"; import { getObject } from "../common/GetDataStoreObjectByKey"; import { d2ToolsNamespace, Namespace } from "data/externalConfig/Namespaces"; -import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; -import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository"; export class UserTemplatesMonitoringConfigD2Repository implements UserTemplatesMonitoringConfigRepository { private api: D2Api; diff --git a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts b/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts similarity index 100% rename from src/domain/entities/user-monitoring/user-group-monitoring/UserGroups.ts rename to src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts diff --git a/src/domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions.ts b/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions.ts similarity index 100% rename from src/domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions.ts rename to src/domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions.ts diff --git a/src/domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions.ts b/src/domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions.ts similarity index 100% rename from src/domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions.ts rename to src/domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions.ts diff --git a/src/domain/entities/user-monitoring/user-template-monitoring/Users.ts b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts similarity index 100% rename from src/domain/entities/user-monitoring/user-template-monitoring/Users.ts rename to src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts diff --git a/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts b/src/domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository.ts similarity index 88% rename from src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts rename to src/domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository.ts index 610a529e..fc738205 100644 --- a/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository.ts +++ b/src/domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository.ts @@ -1,6 +1,6 @@ import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; -import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; export interface UserGroupRepository { get(ids: Id[]): Async; diff --git a/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts b/src/domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository.ts similarity index 78% rename from src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts rename to src/domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository.ts index 1a7c9bde..3ba7e53c 100644 --- a/src/domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository.ts +++ b/src/domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository.ts @@ -1,4 +1,4 @@ -import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; export interface UserGroupsMonitoringConfigRepository { get(): Promise; diff --git a/src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts b/src/domain/repositories/user-monitoring/user-templates-monitoring/UserRepository.ts similarity index 91% rename from src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts rename to src/domain/repositories/user-monitoring/user-templates-monitoring/UserRepository.ts index bbad4551..c57889e9 100644 --- a/src/domain/repositories/user-monitoring/user-template-monitoring/UserRepository.ts +++ b/src/domain/repositories/user-monitoring/user-templates-monitoring/UserRepository.ts @@ -1,6 +1,6 @@ import { Username } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; -import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; export interface UserRepository { getByUsername(usernames: Username[]): Async; diff --git a/src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts b/src/domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository.ts similarity index 76% rename from src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts rename to src/domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository.ts index 797371d9..0e5af567 100644 --- a/src/domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository.ts +++ b/src/domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository.ts @@ -1,4 +1,4 @@ -import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; export interface UserTemplatesMonitoringConfigRepository { get(): Promise; diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts similarity index 98% rename from src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts index c6dfb1a3..f4cc99d8 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/CompareUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts @@ -1,5 +1,5 @@ import _ from "lodash"; -import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; export class CompareUserGroupsUseCase { constructor() {} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts similarity index 75% rename from src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts index fedbedd8..9e6ee6d9 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts @@ -1,4 +1,4 @@ -import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; export class GetUserGroupsMonitoringConfigUseCase { constructor(private configRepository: UserGroupsMonitoringConfigRepository) {} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsUseCase.ts similarity index 83% rename from src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsUseCase.ts index 13c45df1..78b95a09 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/GetUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsUseCase.ts @@ -1,7 +1,7 @@ import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; -import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; -import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; +import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; +import { UserGroupRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository"; export class GetUserGroupsUseCase { constructor(private userGroupRepository: UserGroupRepository) {} diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts similarity index 95% rename from src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts index 24932841..a83ad667 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts @@ -2,12 +2,12 @@ import _ from "lodash"; import log from "utils/log"; import { Async } from "domain/entities/Async"; -import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; -import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; +import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; import { MessageRepository } from "domain/repositories/user-monitoring/common/MessageRepository"; -import { UserGroupRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupRepository"; -import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; +import { UserGroupRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository"; +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; import { GetUserGroupsUseCase } from "./GetUserGroupsUseCase"; import { CompareUserGroupsUseCase } from "./CompareUserGroupsUseCase"; diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts similarity index 80% rename from src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts index 7071cdbe..c07411ab 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts @@ -1,8 +1,8 @@ -import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigRepository"; +import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; import { Async } from "domain/entities/Async"; -import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-group-monitoring/UserGroupsMonitoringOptions"; -import { UserGroup } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; +import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts similarity index 99% rename from src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts index d66256c3..1fb7b362 100644 --- a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts @@ -1,4 +1,4 @@ -import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-group-monitoring/UserGroups"; +import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; export const emptyDiff: UserGroupDiff = { id: "id123", diff --git a/src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts similarity index 100% rename from src/domain/usecases/user-monitoring/user-group-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts similarity index 98% rename from src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts index 06c25b7e..ea3fc521 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/CompareUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts @@ -1,5 +1,5 @@ import _ from "lodash"; -import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; export class CompareUserTemplatesUseCase { constructor() {} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts similarity index 74% rename from src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts index 785f93be..8c0e084b 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts @@ -1,4 +1,4 @@ -import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository"; export class GetUserTemplatesMonitoringConfigUseCase { constructor(private configRepository: UserTemplatesMonitoringConfigRepository) {} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesUseCase.ts similarity index 86% rename from src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesUseCase.ts index 9c58de24..b31e0435 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/GetUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesUseCase.ts @@ -1,7 +1,7 @@ import { Username } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; -import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; -import { UserRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserRepository"; +import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; +import { UserRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserRepository"; export class GetUserTemplatesUseCase { constructor(private userGroupRepository: UserRepository) {} diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts similarity index 95% rename from src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts index 039c91cf..538415aa 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts @@ -3,12 +3,12 @@ import log from "utils/log"; import { Async } from "domain/entities/Async"; import { NamedRef } from "domain/entities/Base"; -import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; -import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; import { MessageRepository } from "domain/repositories/user-monitoring/common/MessageRepository"; -import { UserRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserRepository"; -import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; +import { UserRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserRepository"; +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository"; import { GetUserTemplatesUseCase } from "./GetUserTemplatesUseCase"; import { CompareUserTemplatesUseCase } from "./CompareUserTemplatesUseCase"; diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts similarity index 79% rename from src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts index bb9fc0c0..6a37f118 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts @@ -1,8 +1,8 @@ -import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigRepository"; +import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository"; import { Async } from "domain/entities/Async"; -import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-template-monitoring/UserTemplatesMonitoringOptions"; -import { User } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; +import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts similarity index 99% rename from src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts index 4eb376fc..37208ca0 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts @@ -1,4 +1,4 @@ -import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; export const user1: User = { lastUpdated: "2024-06-10T10:25:27.228", diff --git a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts similarity index 96% rename from src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts index 2e1ddfea..3f5c00bf 100644 --- a/src/domain/usecases/user-monitoring/user-template-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts @@ -3,7 +3,7 @@ import { describe, it, expect, beforeEach } from "vitest"; import { user1, user1Updated, expectedDiff } from "./CompareUserTemplatesUseCase.data"; import { CompareUserTemplatesUseCase } from "../CompareUserTemplatesUseCase"; -import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-template-monitoring/Users"; +import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; describe("CompareUserTemplatesUseCase", () => { let useCase: CompareUserTemplatesUseCase; diff --git a/src/scripts/commands/usermonitoring.ts b/src/scripts/commands/usermonitoring.ts index e9239330..dc02917b 100644 --- a/src/scripts/commands/usermonitoring.ts +++ b/src/scripts/commands/usermonitoring.ts @@ -23,13 +23,13 @@ import { MessageMSTeamsRepository } from "data/user-monitoring/common/MessageMST import { MSTeamsWebhookOptions } from "data/user-monitoring/entities/MSTeamsWebhookOptions"; import { MonitorUsersByAuthorityUseCase } from "domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase"; -import { UserGroupD2Repository } from "data/user-monitoring/user-group-monitoring/UserGroupD2Repository"; -import { UserGroupsMonitoringConfigD2Repository } from "data/user-monitoring/user-group-monitoring/UserGroupsMonitoringConfigD2Repository"; -import { MonitorUserGroupsUseCase } from "domain/usecases/user-monitoring/user-group-monitoring/MonitorUserGroupsUseCase"; +import { UserGroupD2Repository } from "data/user-monitoring/user-groups-monitoring/UserGroupD2Repository"; +import { UserGroupsMonitoringConfigD2Repository } from "data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository"; +import { MonitorUserGroupsUseCase } from "domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase"; -import { UserD2Repository } from "data/user-monitoring/user-template-monitoring/UserD2Repository"; -import { UserTemplatesMonitoringConfigD2Repository } from "data/user-monitoring/user-template-monitoring/UserTemplatesMonitoringConfigD2Repository"; -import { MonitorUserTemplatesUseCase } from "domain/usecases/user-monitoring/user-template-monitoring/MonitorUserTemplatesUseCase"; +import { UserD2Repository } from "data/user-monitoring/user-templates-monitoring/UserD2Repository"; +import { UserTemplatesMonitoringConfigD2Repository } from "data/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigD2Repository"; +import { MonitorUserTemplatesUseCase } from "domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase"; export function getCommand() { return subcommands({ @@ -38,7 +38,7 @@ export function getCommand() { "run-permissions-fixer": runUsersMonitoringCmd, "run-2fa-reporter": run2FAReporterCmd, "run-authorities-monitoring": runAuthoritiesMonitoring, - "run-user-group-monitoring": runUserGroupMonitoringCmd, + "run-user-groups-monitoring": runUserGroupMonitoringCmd, "run-user-templates-monitoring": runUserTemplateMonitoringCmd, }, }); @@ -143,9 +143,9 @@ const runAuthoritiesMonitoring = command({ }); const runUserGroupMonitoringCmd = command({ - name: "run-user-group-monitoring", + name: "run-user-groups-monitoring", description: - "Run user group monitoring, a --config-file must be provided (usermonitoring run-user-group-monitoring --config-file config.json)", + "Run user group monitoring, a --config-file must be provided (usermonitoring run-user-groups-monitoring --config-file config.json)", args: { config_file: option({ type: string, @@ -182,7 +182,7 @@ const runUserGroupMonitoringCmd = command({ const runUserTemplateMonitoringCmd = command({ name: "run-user-templates-monitoring", description: - "Run user template monitoring, a --config-file must be provided (usermonitoring run-user-template-monitoring --config-file config.json)", + "Run user template monitoring, a --config-file must be provided (usermonitoring run-user-templates-monitoring --config-file config.json)", args: { config_file: option({ type: string, @@ -194,7 +194,7 @@ const runUserTemplateMonitoringCmd = command({ short: "s", long: "set-datastore", description: - "Write users templates to datastore, use in script setup. It assumes there is a monitoring config in d2-tools/user-groups-monitoring", + "Write users templates to datastore, use in script setup. It assumes there is a monitoring config in d2-tools/user-templates-monitoring", }), }, From 4aa8b8313ce7df9f11f5ef0510d74b26b3088fec Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Fri, 6 Sep 2024 08:48:11 +0200 Subject: [PATCH 14/20] fix: remove unused import --- .../user-groups-monitoring/UserGroupD2Repository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts index c870837f..3d9fe907 100644 --- a/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts +++ b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts @@ -2,7 +2,7 @@ import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; import { UserGroupRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository"; -import { D2Api, MetadataPick, D2UserGroupSchema } from "@eyeseetea/d2-api/2.36"; +import { D2Api, MetadataPick } from "@eyeseetea/d2-api/2.36"; export class UserGroupD2Repository implements UserGroupRepository { constructor(private api: D2Api) {} From 57df8498e2cb72f046953db1c5896021fa0acb92 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:04:29 +0200 Subject: [PATCH 15/20] fix: address PR#52 comments round 1 typos and repeated lines in README usermonitoring.ts => userMonitoring.ts userMonitoring: config_file => configFile UserGroup/TemplateDiff replace _Lost/Added to camel case CompareUserTemplatesUseCase.specs move noChangesDiff to data folder CompareUserGroupsUseCase.data add usersChanges to the user difference test --- README.md | 22 +----------- .../user-groups-monitoring/UserGroups.ts | 4 +-- .../user-templates-monitoring/Users.ts | 8 ++--- .../CompareUserGroupsUseCase.ts | 8 ++--- .../MonitorUserGroupsUseCase.ts | 8 ++--- .../CompareUserTemplatesUseCase.ts | 12 +++---- .../MonitorUserTemplatesUseCase.ts | 12 +++---- src/scripts/cli.ts | 4 +-- .../{usermonitoring.ts => userMonitoring.ts} | 34 +++++++++---------- 9 files changed, 45 insertions(+), 67 deletions(-) rename src/scripts/commands/{usermonitoring.ts => userMonitoring.ts} (91%) diff --git a/README.md b/README.md index 47b0a2cb..568cce7e 100644 --- a/README.md +++ b/README.md @@ -406,10 +406,6 @@ yarn start users migrate \ #### Execution: ``` -yarn install - -yarn build - yarn start usermonitoring run-permissions-fixer --config-file config.json or yarn start usermonitoring run-2fa-reporter --config-file config.json @@ -418,10 +414,6 @@ yarn start usermonitoring run-2fa-reporter --config-file config.json #### Debug: ``` -yarn install - -yarn build:dev - LOG_LEVEL=debug node --inspect-brk dist/index.js usermonitoring run-users-monitoring --config-file config.json LOG_LEVEL=debug node --inspect-brk dist/index.js usermonitoring run-2fa-reporter --config-file config.json ``` @@ -594,10 +586,6 @@ Note: the names are used only to make easy understand and debug the keys. #### Execution: ```bash -yarn install - -yarn build - yarn start usermonitoring run-authorities-monitoring --config-file config.json # To get the debug logs and store them in a file use: @@ -629,7 +617,7 @@ A config file with the access info of the server and the message webhook details ``` This reports stores data into the `d2-tools.authorities-monitor` datastore. This key needs to be setup before the first run to get a correct report. -Its possible to leave `usersByAuthority` empty and use the `-s` flag to populate it. +It's possible to leave `usersByAuthority` empty and use the `-s` flag to populate it. A sample: @@ -681,10 +669,6 @@ This script will compare the metadata of the monitored userGroups with the versi #### Execution: ```bash -yarn install - -yarn build - yarn start usermonitoring run-user-groups-monitoring --config-file config.json # To get the debug logs and store them in a file use: @@ -733,10 +717,6 @@ The User Templates Monitoring script is used to compare user templates with the #### Execution: ```bash -yarn install - -yarn build - yarn start usermonitoring run-user-templates-monitoring --config-file config.json # To get the debug logs and store them in a file use: diff --git a/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts b/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts index 521915de..af0e2c39 100644 --- a/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts +++ b/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts @@ -42,7 +42,7 @@ export type UserGroupDiff = { changedPropsLost: Partial; changedPropsAdded: Partial; usersChanges: { - users_Lost: NamedRef[]; - users_Added: NamedRef[]; + usersLost: NamedRef[]; + usersAdded: NamedRef[]; }; }; diff --git a/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts index 8f34dcb0..7771e4cd 100644 --- a/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts +++ b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts @@ -85,10 +85,10 @@ type UserCredentials = { }; type MembershipChanges = { - userRoles_Lost: NamedRef[]; - userRoles_Added: NamedRef[]; - userGroups_Lost: NamedRef[]; - userGroups_Added: NamedRef[]; + userRolesLost: NamedRef[]; + userRolesAdded: NamedRef[]; + userGroupsLost: NamedRef[]; + userGroupsAdded: NamedRef[]; }; export type UserTemplateDiff = { diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts index f4cc99d8..6cfe03c2 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts @@ -51,8 +51,8 @@ export class CompareUserGroupsUseCase { let changedPropsLost: Partial = {}; let changedPropsAdded: Partial = {}; let usersChanges = { - users_Lost: [], - users_Added: [], + usersLost: [], + usersAdded: [], }; _.forOwn(oldUserGroup, (value, key) => { @@ -63,12 +63,12 @@ export class CompareUserGroupsUseCase { if (key === "users") { usersChanges = _.set( usersChanges, - `${key}_Lost`, + `${key}Lost`, _.differenceBy(value as any, newValue, "id") ); usersChanges = _.set( usersChanges, - `${key}_Added`, + `${key}Added`, _.differenceBy(newValue, value as any, "id") ); } else { diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts index a83ad667..344023e6 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts @@ -48,16 +48,14 @@ export class MonitorUserGroupsUseCase { message.push(changedPropsAddedMsg); } - if (!_.isEmpty(changes.usersChanges.users_Lost) || !_.isEmpty(changes.usersChanges.users_Added)) { + if (!_.isEmpty(changes.usersChanges.usersLost) || !_.isEmpty(changes.usersChanges.usersAdded)) { message.push("User assignment changes:\n"); - const usersLostMsg = `Users lost:\n${this.stringifyObject( - changes.usersChanges.users_Lost - )}\n`; + const usersLostMsg = `Users lost:\n${this.stringifyObject(changes.usersChanges.usersLost)}\n`; message.push(usersLostMsg); const usersAddedMsg = `Users added:\n${this.stringifyObject( - changes.usersChanges.users_Added + changes.usersChanges.usersAdded )}\n`; message.push(usersAddedMsg); } diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts index ea3fc521..315bf023 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts @@ -33,10 +33,10 @@ export class CompareUserTemplatesUseCase { let changedPropsLost: Partial = {}; let changedPropsAdded: Partial = {}; let membershipChanges = { - userRoles_Lost: [], - userRoles_Added: [], - userGroups_Lost: [], - userGroups_Added: [], + userRolesLost: [], + userRolesAdded: [], + userGroupsLost: [], + userGroupsAdded: [], }; _.forOwn(oldUserTemplate, (value, key) => { @@ -47,12 +47,12 @@ export class CompareUserTemplatesUseCase { if (this.membershipKeys.includes(key)) { membershipChanges = _.set( membershipChanges, - `${key}_Lost`, + `${key}Lost`, _.differenceBy(value as any, newValue, "id") ); membershipChanges = _.set( membershipChanges, - `${key}_Added`, + `${key}Added`, _.differenceBy(newValue, value as any, "id") ); } else { diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts index 538415aa..d22854ba 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts @@ -22,8 +22,8 @@ export class MonitorUserTemplatesUseCase { private MessageRepository: MessageRepository ) {} - private stringifyObject(ojb: any) { - return JSON.stringify(ojb, null, 2); + private stringifyObject(obj: any) { + return JSON.stringify(obj, null, 2); } private checkMembershipChanges( @@ -70,14 +70,14 @@ export class MonitorUserTemplatesUseCase { } const rolesMembershipMessage = this.checkMembershipChanges( - changes.membershipChanges.userRoles_Lost, - changes.membershipChanges.userRoles_Added, + changes.membershipChanges.userRolesLost, + changes.membershipChanges.userRolesAdded, "User Roles" ); const groupsMembershipMessage = this.checkMembershipChanges( - changes.membershipChanges.userRoles_Lost, - changes.membershipChanges.userRoles_Added, + changes.membershipChanges.userRolesLost, + changes.membershipChanges.userRolesAdded, "User Groups" ); diff --git a/src/scripts/cli.ts b/src/scripts/cli.ts index e173a2ca..2712f84a 100644 --- a/src/scripts/cli.ts +++ b/src/scripts/cli.ts @@ -4,7 +4,7 @@ import { run, subcommands } from "cmd-ts"; import * as datasets from "./commands/datasets"; import * as programs from "./commands/programs"; import * as orgunits from "./commands/orgunits"; -import * as usermonitoring from "./commands/usermonitoring"; +import * as userMonitoring from "./commands/userMonitoring"; import * as translations from "./commands/translations"; import * as dataValues from "./commands/dataValues"; import * as notifications from "./commands/notifications"; @@ -28,7 +28,7 @@ export function runCli() { events: events.getCommand(), sync: sync.getCommand(), users: users.getCommand(), - usermonitoring: usermonitoring.getCommand(), + usermonitoring: userMonitoring.getCommand(), loadTesting: loadTesting.getCommand(), categoryoptions: categoryoptions.getCommand(), indicators: indicators.getCommand(), diff --git a/src/scripts/commands/usermonitoring.ts b/src/scripts/commands/userMonitoring.ts similarity index 91% rename from src/scripts/commands/usermonitoring.ts rename to src/scripts/commands/userMonitoring.ts index dc02917b..717a6ffb 100644 --- a/src/scripts/commands/usermonitoring.ts +++ b/src/scripts/commands/userMonitoring.ts @@ -49,7 +49,7 @@ const run2FAReporterCmd = command({ description: "Run user 2factor reporter, a --config-file must be provided (usermonitoring run-2fa-reporter --config-file config.json)", args: { - config_file: option({ + configFile: option({ type: string, long: "config-file", description: "Config file", @@ -57,7 +57,7 @@ const run2FAReporterCmd = command({ }, handler: async args => { - const auth = getAuthFromFile(args.config_file); + const auth = getAuthFromFile(args.configFile); const api = getD2Api(auth.apiurl); const usersRepository = new TwoFactorUserD2Repository(api); const externalConfigRepository = new TwoFactorConfigD2Repository(api); @@ -78,7 +78,7 @@ const runUsersMonitoringCmd = command({ description: "Run user monitoring, a --config-file must be provided (usermonitoring run-permissions-fixer --config-file config.json)", args: { - config_file: option({ + configFile: option({ type: string, long: "config-file", description: "Config file", @@ -86,7 +86,7 @@ const runUsersMonitoringCmd = command({ }, handler: async args => { - const auth = getAuthFromFile(args.config_file); + const auth = getAuthFromFile(args.configFile); const api = getD2Api(auth.apiurl); const usersRepository = new PermissionFixerUserD2Repository(api); const userGroupsRepository = new PermissionFixerUserGroupD2Repository(api); @@ -111,7 +111,7 @@ const runAuthoritiesMonitoring = command({ description: "Run user authorities monitoring, a --config-file must be provided (usersmonitoring run-permissions-fixer --config-file config.json)", args: { - config_file: option({ + configFile: option({ type: string, long: "config-file", description: "Config file", @@ -126,8 +126,8 @@ const runAuthoritiesMonitoring = command({ }, handler: async args => { - const auth = getAuthFromFile(args.config_file); - const webhook = getWebhookConfFromFile(args.config_file); + const auth = getAuthFromFile(args.configFile); + const webhook = getWebhookConfFromFile(args.configFile); const api = getD2Api(auth.apiurl); const UserRolesRepository = new UserRolesD2Repository(api); const externalConfigRepository = new AuthoritiesMonitoringConfigD2Repository(api); @@ -147,7 +147,7 @@ const runUserGroupMonitoringCmd = command({ description: "Run user group monitoring, a --config-file must be provided (usermonitoring run-user-groups-monitoring --config-file config.json)", args: { - config_file: option({ + configFile: option({ type: string, long: "config-file", description: "Config file", @@ -162,8 +162,8 @@ const runUserGroupMonitoringCmd = command({ }, handler: async args => { - const auth = getAuthFromFile(args.config_file); - const webhook = getWebhookConfFromFile(args.config_file); + const auth = getAuthFromFile(args.configFile); + const webhook = getWebhookConfFromFile(args.configFile); const api = getD2Api(auth.apiurl); const userGroupsRepository = new UserGroupD2Repository(api); @@ -184,7 +184,7 @@ const runUserTemplateMonitoringCmd = command({ description: "Run user template monitoring, a --config-file must be provided (usermonitoring run-user-templates-monitoring --config-file config.json)", args: { - config_file: option({ + configFile: option({ type: string, long: "config-file", description: "Config file", @@ -199,8 +199,8 @@ const runUserTemplateMonitoringCmd = command({ }, handler: async args => { - const auth = getAuthFromFile(args.config_file); - const webhook = getWebhookConfFromFile(args.config_file); + const auth = getAuthFromFile(args.configFile); + const webhook = getWebhookConfFromFile(args.configFile); const api = getD2Api(auth.apiurl); const usersRepository = new UserD2Repository(api); @@ -216,9 +216,9 @@ const runUserTemplateMonitoringCmd = command({ }, }); -function getAuthFromFile(config_file: string): UserMonitoringAuth { +function getAuthFromFile(configFile: string): UserMonitoringAuth { const fs = require("fs"); - const configJSON = JSON.parse(fs.readFileSync("./" + config_file, "utf8")); + const configJSON = JSON.parse(fs.readFileSync("./" + configFile, "utf8")); const urlprefix = configJSON["URL"]["server"].split("//")[0] + "//"; const urlserver = configJSON["URL"]["server"].split("//")[1]; const apiurl: string = @@ -229,9 +229,9 @@ function getAuthFromFile(config_file: string): UserMonitoringAuth { }; } -function getWebhookConfFromFile(config_file: string): MSTeamsWebhookOptions { +function getWebhookConfFromFile(configFile: string): MSTeamsWebhookOptions { const fs = require("fs"); - const configJSON = JSON.parse(fs.readFileSync("./" + config_file, "utf8")); + const configJSON = JSON.parse(fs.readFileSync("./" + configFile, "utf8")); const ms_url = configJSON["WEBHOOK"]["ms_url"]; const proxy = configJSON["WEBHOOK"]["proxy"]; const server_name = configJSON["WEBHOOK"]["server_name"]; From ad425cf2f65a6c39d5d3378499021aceea951554 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:20:47 +0200 Subject: [PATCH 16/20] fix: address PR#52 comments round 2 Rework User and UserGroup entities and D2Repositories. Fix and improve some tests. --- .../UserGroupD2Repository.ts | 30 +++--- .../UserD2Repository.ts | 68 +++++++++++--- src/domain/entities/Access.ts | 23 +++++ src/domain/entities/AttributeValue.ts | 6 ++ src/domain/entities/Base.ts | 1 - src/domain/entities/UserReference.ts | 9 ++ .../user-groups-monitoring/UserGroups.ts | 59 +++++++----- .../user-templates-monitoring/Users.ts | 91 ++++++++----------- .../CompareUserGroupsUseCase.data.ts | 67 ++++++++++++-- .../CompareUserTemplatesUseCase.data.ts | 22 ++++- .../CompareUserTemplatesUseCase.specs.ts | 17 +--- 11 files changed, 259 insertions(+), 134 deletions(-) create mode 100644 src/domain/entities/AttributeValue.ts create mode 100644 src/domain/entities/UserReference.ts diff --git a/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts index 3d9fe907..8b70c638 100644 --- a/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts +++ b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts @@ -1,8 +1,9 @@ +import { D2Api } from "@eyeseetea/d2-api/2.36"; + import { Id } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; import { UserGroupRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupRepository"; -import { D2Api, MetadataPick } from "@eyeseetea/d2-api/2.36"; export class UserGroupD2Repository implements UserGroupRepository { constructor(private api: D2Api) {} @@ -17,19 +18,26 @@ export class UserGroupD2Repository implements UserGroupRepository { }) .getData(); - return userGroups.map((userGroup: D2UserGroup) => { + return userGroups.map((userGroup): UserGroup => { return { ...userGroup, - id: userGroup.id, - name: userGroup.name, - } as UserGroup; + attributeValues: userGroup.attributeValues.map(attributeValue => ({ + attribute: attributeValue.attribute.name, + value: attributeValue.value, + })), + }; }); } } -const userFields = { $all: true, users: { id: true, name: true } } as const; - -type D2UserGroup = { - id: Id; - name: string; -} & Partial["userGroups"][number]>; +const userFields = { + $all: true, + sharing: { userGroups: true, external: true, users: true, owner: true, public: true }, + AttributeValue: { attribute: { name: true }, value: true }, + user: { id: true, name: true, username: true, displayName: true }, + createdBy: { id: true, name: true, username: true, displayName: true }, + lastUpdatedBy: { id: true, name: true, username: true, displayName: true }, + userAccesses: { id: true, access: true, displayName: true, userUid: true }, + userGroupAccesses: { id: true, access: true, displayName: true, userUid: true }, + users: { id: true, name: true }, +} as const; diff --git a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts index 7320f189..0b4c4202 100644 --- a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts +++ b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts @@ -2,7 +2,7 @@ import { Username } from "domain/entities/Base"; import { Async } from "domain/entities/Async"; import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; import { UserRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserRepository"; -import { D2Api, SelectedPick, D2UserSchema } from "@eyeseetea/d2-api/2.36"; +import { D2Api } from "@eyeseetea/d2-api/2.36"; export class UserD2Repository implements UserRepository { constructor(private api: D2Api) {} @@ -16,24 +16,68 @@ export class UserD2Repository implements UserRepository { }) .getData(); - return users.objects.map((user: D2User) => { + return users.objects.map((user): User => { return { ...user, - id: user.id, - username: user.username, + username: user.userCredentials.username, + disabled: user.userCredentials.disabled, + twoFA: user.userCredentials.twoFA, + userRoles: user.userCredentials.userRoles, + invitation: user.userCredentials.invitation, + externalAuth: user.userCredentials.externalAuth, + selfRegistered: user.userCredentials.selfRegistered, + catDimensionConstraints: user.userCredentials.catDimensionConstraints, + cogsDimensionConstraints: user.userCredentials.cogsDimensionConstraints, + attributeValues: user.attributeValues.map(attributeValue => ({ + attribute: attributeValue.attribute.name, + value: attributeValue.value, + })), userCredentials: { - ...user.userCredentials, + externalAuth: user.userCredentials.externalAuth, + disabled: user.userCredentials.disabled, + id: user.userCredentials.id, + twoFA: user.userCredentials.twoFA, + invitation: user.userCredentials.invitation, + selfRegistered: user.userCredentials.selfRegistered, + username: user.userCredentials.username, + access: user.userCredentials.access, + sharing: user.userCredentials.sharing, + cogsDimensionConstraints: user.userCredentials.cogsDimensionConstraints, + catDimensionConstraints: user.userCredentials.catDimensionConstraints, }, - } as User; + }; }); } } const userFields = { - $all: true, - username: true, - userRoles: { id: true, name: true }, + id: true, + lastUpdated: true, + created: true, + invitation: true, + selfRegistered: true, + firstName: true, + name: true, + favorite: true, + displayName: true, + externalAuth: true, + externalAccess: true, + surname: true, + disabled: true, + sharing: true, + access: true, + translations: true, + favorites: true, + organisationUnits: { id: true }, userGroups: { id: true, name: true }, + dataViewOrganisationUnits: { id: true }, + teiSearchOrganisationUnits: { id: true }, + attributeValues: { attribute: { name: true }, value: true }, + user: { id: true, name: true, username: true, displayName: true }, + createdBy: { id: true, name: true, username: true, displayName: true }, + lastUpdatedBy: { id: true, name: true, username: true, displayName: true }, + userAccesses: { id: true, access: true, displayName: true, userUid: true }, + userGroupAccesses: { id: true, access: true, displayName: true, userUid: true }, userCredentials: { access: true, accountExpiry: true, @@ -70,10 +114,6 @@ const userFields = { userGroupAccesses: true, userInfo: true, username: true, - userRoles: false, + userRoles: { id: true, name: true }, }, } as const; - -type D2User = { - username?: string; -} & Partial>; diff --git a/src/domain/entities/Access.ts b/src/domain/entities/Access.ts index 8a47a036..f5f14cfa 100644 --- a/src/domain/entities/Access.ts +++ b/src/domain/entities/Access.ts @@ -6,3 +6,26 @@ export type Access = { delete: boolean; manage: boolean; }; + +export type UserAccess = { + access: AccessString; + displayName: string; + id: string; + userUid: string; +}; + +export type UserGroupAccess = { + access: AccessString; + displayName: string; + id: string; + userGroupUid: string; +}; + +/** + * AccessString stores sharing access rights. + * The first two characters represent read and write access for metadata. + * The second set of characters represent read and write access for data. + */ +// TODO: is it worth using the template? +// export type AccessString = `${"r" | "-"}${"w" | "-"}${"r" | "-"}${"w" | "-"}----`; +export type AccessString = string; diff --git a/src/domain/entities/AttributeValue.ts b/src/domain/entities/AttributeValue.ts new file mode 100644 index 00000000..ea597ba5 --- /dev/null +++ b/src/domain/entities/AttributeValue.ts @@ -0,0 +1,6 @@ +import { Id } from "domain/entities/Base"; + +export type AttributeValue = { + attribute: Id; + value: string; +}; diff --git a/src/domain/entities/Base.ts b/src/domain/entities/Base.ts index df3d38fa..c1ef5894 100644 --- a/src/domain/entities/Base.ts +++ b/src/domain/entities/Base.ts @@ -20,6 +20,5 @@ export function getId(obj: Obj): Id { export type Code = string; export type Name = string; -export type IdAccess = { id: Id; access: string }; export type Identifiable = Id | Code | Name; diff --git a/src/domain/entities/UserReference.ts b/src/domain/entities/UserReference.ts new file mode 100644 index 00000000..016f0547 --- /dev/null +++ b/src/domain/entities/UserReference.ts @@ -0,0 +1,9 @@ +import { NamedRef } from "domain/entities/Base"; + +/** + * UserReference can be used for the createdBy, lastUpdatedBy, and other similar fields. + */ +export type UserReference = NamedRef & { + displayName: string; + username: string; +}; diff --git a/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts b/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts index af0e2c39..eaacb083 100644 --- a/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts +++ b/src/domain/entities/user-monitoring/user-groups-monitoring/UserGroups.ts @@ -1,38 +1,47 @@ -import { D2UserGroup } from "@eyeseetea/d2-api/2.36"; import { Id, NamedRef, Ref } from "domain/entities/Base"; -export interface Sharing { + +import { UserReference } from "domain/entities/UserReference"; +import { AttributeValue } from "domain/entities/AttributeValue"; +import { Access, AccessString, UserAccess, UserGroupAccess } from "domain/entities/Access"; +import { Translation } from "domain/entities/Translation"; + +export type UserGroup = { + id: Id; + name: string; + access: Access; + attributeValues: AttributeValue[]; + created: string; + createdBy: UserReference; + displayName: string; + externalAccess?: boolean; + favorite: boolean; + favorites: string[]; + lastUpdated: string; + lastUpdatedBy: UserReference; + managedByGroups: Ref[]; + managedGroups: Ref[]; + sharing: Sharing; + user: UserReference; + users: NamedRef[]; + translations: Translation[]; + code?: Id; + publicAccess?: AccessString; + userAccesses?: UserAccess[]; + userGroupAccesses?: UserGroupAccess[]; +}; + +type Sharing = { owner: Id; public: string; external: boolean; users: Record; userGroups: Record; -} - -export type UserGroup = Pick & - Partial< - Omit< - D2UserGroup, - "users" | "lastUpdatedBy" | "managedByGroups" | "sharing" | "createdBy" | "user" - > & { - created: string; - lastUpdatedBy: UserDetails; - managedByGroups: Ref[]; - users: NamedRef[]; - sharing: Sharing; - createdBy: UserDetails; - user: UserDetails; - } - >; - -export type UserDetails = NamedRef & { - username: string; - displayName: string; }; -export type SharingUser = { +type SharingUser = { id: Id; access: string; - displayName: string; + displayName?: string; }; export type UserGroupDiff = { diff --git a/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts index 7771e4cd..a3ca11d1 100644 --- a/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts +++ b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts @@ -1,65 +1,44 @@ -import { Access } from "domain/entities/Access"; -import { Id, Username, NamedRef, StringDateTime, Ref, IdAccess } from "domain/entities/Base"; +import { Access, AccessString, UserAccess, UserGroupAccess } from "domain/entities/Access"; +import { AttributeValue } from "domain/entities/AttributeValue"; +import { Id, Username, NamedRef, StringDateTime, Ref } from "domain/entities/Base"; import { Translation } from "domain/entities/Translation"; +import { UserReference } from "domain/entities/UserReference"; export type User = { id: Id; username: Username; - lastUpdated?: StringDateTime; - created?: string; + lastUpdated: StringDateTime; + created: string; twoFA?: boolean; - invitation?: boolean; - selfRegistered?: boolean; - firstName?: string; - name?: string; - favorite?: boolean; - displayName?: string; - externalAuth?: boolean; - externalAccess?: boolean; - surname?: string; - disabled?: boolean; - lastUpdatedBy?: UserReference; - sharing?: Sharing; - access?: Access; - userCredentials?: UserCredentials; - createdBy?: UserReference; - user?: UserReference; - translations?: Translation[]; - dataViewOrganisationUnits?: Ref[]; - attributeValues?: AttributeValue[]; - userGroups?: NamedRef[]; - userRoles?: NamedRef[]; - userAccesses?: UserAccess[]; - userGroupAccesses?: UserGroupAccess[]; - favorites?: string[]; - cogsDimensionConstraints?: Ref[]; - catDimensionConstraints?: Ref[]; - teiSearchOrganisationUnits?: Ref[]; - organisationUnits?: Ref[]; -}; - -type UserAccess = { - access: string; - displayName: string; - id: string; - userUid: string; -}; - -type UserGroupAccess = { - access: string; - displayName: string; - id: string; - userGroupUid: string; -}; - -type AttributeValue = { - attribute: Id; - value: string; -}; - -type UserReference = NamedRef & { + twoFactorEnabled?: boolean; + invitation: boolean; + selfRegistered: boolean; + firstName: string; + name: string; + favorite: boolean; displayName: string; - username: string; + externalAuth: boolean; + externalAccess: boolean; + surname: string; + disabled: boolean; + lastUpdatedBy: UserReference; + sharing: Sharing; + access: Access; + userCredentials: UserCredentials; + createdBy: UserReference; + user: UserReference; + translations: Translation[]; + dataViewOrganisationUnits: Ref[]; + attributeValues: AttributeValue[]; + userGroups: NamedRef[]; + userRoles: NamedRef[]; + userAccesses: UserAccess[]; + userGroupAccesses: UserGroupAccess[]; + favorites: string[]; + cogsDimensionConstraints: Ref[]; + catDimensionConstraints: Ref[]; + teiSearchOrganisationUnits: Ref[]; + organisationUnits: Ref[]; }; type Sharing = { @@ -68,6 +47,8 @@ type Sharing = { users: Record; }; +type IdAccess = { id: Id; access: AccessString }; + type UserCredentials = { externalAuth: boolean; disabled: boolean; diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts index 1fb7b362..4f9ded4b 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts @@ -6,8 +6,8 @@ export const emptyDiff: UserGroupDiff = { changedPropsLost: {}, changedPropsAdded: {}, usersChanges: { - users_Lost: [], - users_Added: [], + usersLost: [], + usersAdded: [], }, newProps: {}, }; @@ -142,8 +142,18 @@ export const userGroup1Diff: UserGroupDiff = { ], }, usersChanges: { - users_Lost: [], - users_Added: [], + usersAdded: [ + { + id: "user09", + name: "Pat Robin", + }, + ], + usersLost: [ + { + id: "user08", + name: "Sam Robin", + }, + ], }, newProps: {}, }; @@ -151,6 +161,49 @@ export const userGroup1Diff: UserGroupDiff = { export const minimalUserGroup: UserGroup = { id: "id123", name: "Tech Team Alpha", + created: "2024-09-18T12:27:50.328", + lastUpdated: "2024-09-18T12:27:50.358", + createdBy: { + id: "USER_ID_1", + name: "John Doe", + displayName: "John Doe", + username: "admin", + }, + favorites: [], + lastUpdatedBy: { + id: "USER_ID_1", + name: "John Doe", + displayName: "John Doe", + username: "admin", + }, + sharing: { + owner: "USER_ID_1", + external: false, + users: {}, + userGroups: {}, + public: "rw------", + }, + displayName: "TEST GROUP", + access: { + manage: true, + externalize: false, + write: true, + read: true, + update: true, + delete: true, + }, + favorite: false, + user: { + id: "USER_ID_1", + name: "John Doe", + displayName: "John Doe", + username: "admin", + }, + attributeValues: [], + users: [], + managedGroups: [], + managedByGroups: [], + translations: [], }; export const userGroup1: UserGroup = { @@ -158,7 +211,6 @@ export const userGroup1: UserGroup = { lastUpdated: "2024-06-10T21:31:09.850", name: "Tech Team Alpha", id: "id123", - href: "http://example.com/api/userGroups/id123", displayName: "Tech Team Alpha", publicAccess: "--------", externalAccess: false, @@ -290,7 +342,6 @@ export const userGroup1Updated: UserGroup = { lastUpdated: "2024-06-10T21:31:09.850", name: "Tech Team Alpha", id: "id123", - href: "http://example.com/api/userGroups/id123", displayName: "Tech Team Beta", publicAccess: "--------", externalAccess: false, @@ -408,8 +459,8 @@ export const userGroup1Updated: UserGroup = { id: "user07", }, { - name: "Sam Robin", - id: "user08", + name: "Pat Robin", + id: "user09", }, ], managedGroups: [], diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts index 37208ca0..d9631dcf 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts @@ -232,6 +232,20 @@ export const user1Updated: User = { ], }; +export const noChangesDiff: UserTemplateDiff = { + id: user1.id, + username: user1.username, + changedPropsLost: {}, + changedPropsAdded: {}, + membershipChanges: { + userRolesLost: [], + userRolesAdded: [], + userGroupsLost: [], + userGroupsAdded: [], + }, + newProps: {}, +}; + export const expectedDiff: UserTemplateDiff = { id: "cNtWc18LXBS", username: "user.template", @@ -396,7 +410,7 @@ export const expectedDiff: UserTemplateDiff = { ], }, membershipChanges: { - userRoles_Lost: [ + userRolesLost: [ { name: "Role 1", id: "role_id_1", @@ -410,7 +424,7 @@ export const expectedDiff: UserTemplateDiff = { id: "role_id_3", }, ], - userRoles_Added: [ + userRolesAdded: [ { name: "Updated Role 1", id: "updated_role_id_1", @@ -424,7 +438,7 @@ export const expectedDiff: UserTemplateDiff = { id: "updated_role_id_3", }, ], - userGroups_Lost: [ + userGroupsLost: [ { name: "User Group 1", id: "user_group_id_1", @@ -434,7 +448,7 @@ export const expectedDiff: UserTemplateDiff = { id: "user_group_id_2", }, ], - userGroups_Added: [ + userGroupsAdded: [ { name: "Updated User Group 1", id: "updated_user_group_id_1", diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts index 3f5c00bf..00196f9c 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts @@ -1,9 +1,8 @@ import { describe, it, expect, beforeEach } from "vitest"; -import { user1, user1Updated, expectedDiff } from "./CompareUserTemplatesUseCase.data"; +import { user1, user1Updated, noChangesDiff, expectedDiff } from "./CompareUserTemplatesUseCase.data"; import { CompareUserTemplatesUseCase } from "../CompareUserTemplatesUseCase"; -import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; describe("CompareUserTemplatesUseCase", () => { let useCase: CompareUserTemplatesUseCase; @@ -13,20 +12,6 @@ describe("CompareUserTemplatesUseCase", () => { }); it("should not fild differences between the same user templates", () => { - const noChangesDiff: UserTemplateDiff = { - id: user1.id, - username: user1.username, - changedPropsLost: {}, - changedPropsAdded: {}, - membershipChanges: { - userRoles_Lost: [], - userRoles_Added: [], - userGroups_Lost: [], - userGroups_Added: [], - }, - newProps: {}, - }; - const diff = useCase.execute(user1, user1); expect(diff).toEqual(noChangesDiff); From b0475cb2a79c0f72b84f53cd1a06ef67c67f5a9d Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Mon, 23 Sep 2024 08:33:15 +0200 Subject: [PATCH 17/20] fix: change $all for the actual fields --- .../UserGroupD2Repository.ts | 17 +++++++++++++++-- .../UserD2Repository.ts | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts index 8b70c638..a430894e 100644 --- a/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts +++ b/src/data/user-monitoring/user-groups-monitoring/UserGroupD2Repository.ts @@ -31,9 +31,22 @@ export class UserGroupD2Repository implements UserGroupRepository { } const userFields = { - $all: true, + id: true, + code: true, + name: true, + access: true, + created: true, + favorite: true, + favorites: true, + lastUpdated: true, + displayName: true, + translations: true, + publicAccess: true, + externalAccess: true, + managedGroups: { id: true, name: true }, + managedByGroups: { id: true, name: true }, sharing: { userGroups: true, external: true, users: true, owner: true, public: true }, - AttributeValue: { attribute: { name: true }, value: true }, + attributeValues: { attribute: { name: true }, value: true }, user: { id: true, name: true, username: true, displayName: true }, createdBy: { id: true, name: true, username: true, displayName: true }, lastUpdatedBy: { id: true, name: true, username: true, displayName: true }, diff --git a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts index 0b4c4202..344d9be8 100644 --- a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts +++ b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts @@ -109,6 +109,8 @@ const userFields = { sharing: true, translations: true, twoFA: true, + // NOTE: twoFA changes to twoFactorEnabled in 2.4x + // twoFactorEnabled: true, user: true, userAccesses: true, userGroupAccesses: true, From 51789d369ab00cfc4ae113ff343373eb76ffb37c Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:19:01 +0200 Subject: [PATCH 18/20] fix: address PR#52 comments round 3 --- .../UserGroupsMonitoringConfigD2Repository.ts | 6 +- .../UserD2Repository.ts | 60 ++++--------------- .../user-templates-monitoring/Users.ts | 18 +++--- .../user-monitoring/GetLogFormatDate.ts | 13 ++++ .../GetLogFormatDateUseCase.ts | 19 ------ .../SaveAuthoritiesMonitoringConfigUseCase.ts | 11 ++-- ...rGroupsUseCase.ts => CompareUserGroups.ts} | 2 +- .../GetUserGroupsMonitoringConfigUseCase.ts | 3 +- .../MonitorUserGroupsUseCase.ts | 4 +- .../SaveUserGroupsMonitoringConfigUseCase.ts | 11 ++-- .../CompareUserGroupsUseCase.specs.ts | 6 +- ...atesUseCase.ts => CompareUserTemplates.ts} | 2 +- ...GetUserTemplatesMonitoringConfigUseCase.ts | 3 +- .../MonitorUserTemplatesUseCase.ts | 4 +- ...aveUserTemplatesMonitoringConfigUseCase.ts | 11 ++-- .../CompareUserTemplatesUseCase.data.ts | 4 ++ .../CompareUserTemplatesUseCase.specs.ts | 6 +- 17 files changed, 78 insertions(+), 105 deletions(-) create mode 100644 src/domain/usecases/user-monitoring/GetLogFormatDate.ts delete mode 100644 src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts rename src/domain/usecases/user-monitoring/user-groups-monitoring/{CompareUserGroupsUseCase.ts => CompareUserGroups.ts} (98%) rename src/domain/usecases/user-monitoring/user-templates-monitoring/{CompareUserTemplatesUseCase.ts => CompareUserTemplates.ts} (98%) diff --git a/src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts b/src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts index 32f7529c..65e9a804 100644 --- a/src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts +++ b/src/data/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigD2Repository.ts @@ -9,11 +9,7 @@ import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/use import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; export class UserGroupsMonitoringConfigD2Repository implements UserGroupsMonitoringConfigRepository { - private api: D2Api; - - constructor(api: D2Api) { - this.api = api; - } + constructor(private api: D2Api) {} public async get(): Async { const config = await getObject( diff --git a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts index 344d9be8..d0730ccf 100644 --- a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts +++ b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts @@ -32,19 +32,6 @@ export class UserD2Repository implements UserRepository { attribute: attributeValue.attribute.name, value: attributeValue.value, })), - userCredentials: { - externalAuth: user.userCredentials.externalAuth, - disabled: user.userCredentials.disabled, - id: user.userCredentials.id, - twoFA: user.userCredentials.twoFA, - invitation: user.userCredentials.invitation, - selfRegistered: user.userCredentials.selfRegistered, - username: user.userCredentials.username, - access: user.userCredentials.access, - sharing: user.userCredentials.sharing, - cogsDimensionConstraints: user.userCredentials.cogsDimensionConstraints, - catDimensionConstraints: user.userCredentials.catDimensionConstraints, - }, }; }); } @@ -52,18 +39,16 @@ export class UserD2Repository implements UserRepository { const userFields = { id: true, + code: true, lastUpdated: true, created: true, invitation: true, - selfRegistered: true, firstName: true, name: true, favorite: true, displayName: true, - externalAuth: true, externalAccess: true, surname: true, - disabled: true, sharing: true, access: true, translations: true, @@ -79,43 +64,22 @@ const userFields = { userAccesses: { id: true, access: true, displayName: true, userUid: true }, userGroupAccesses: { id: true, access: true, displayName: true, userUid: true }, userCredentials: { - access: true, - accountExpiry: true, - attributeValues: true, - catDimensionConstraints: true, - code: true, - cogsDimensionConstraints: true, - created: true, - createdBy: true, - disabled: true, - displayName: true, - externalAccess: true, - externalAuth: true, - favorite: true, - favorites: true, - href: true, id: true, - invitation: true, - lastLogin: true, - lastUpdated: true, - lastUpdatedBy: true, - ldapId: true, - name: true, - openId: true, - password: true, - passwordLastUpdated: true, - publicAccess: true, - selfRegistered: true, - sharing: true, - translations: true, + code: true, twoFA: true, // NOTE: twoFA changes to twoFactorEnabled in 2.4x // twoFactorEnabled: true, - user: true, - userAccesses: true, - userGroupAccesses: true, - userInfo: true, + access: true, + ldapId: true, + openId: true, + sharing: true, username: true, + disabled: true, + invitation: true, + externalAuth: true, + selfRegistered: true, + catDimensionConstraints: true, + cogsDimensionConstraints: true, userRoles: { id: true, name: true }, }, } as const; diff --git a/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts index a3ca11d1..05b3f6a0 100644 --- a/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts +++ b/src/domain/entities/user-monitoring/user-templates-monitoring/Users.ts @@ -6,6 +6,7 @@ import { UserReference } from "domain/entities/UserReference"; export type User = { id: Id; + code?: Id; username: Username; lastUpdated: StringDateTime; created: string; @@ -50,16 +51,19 @@ type Sharing = { type IdAccess = { id: Id; access: AccessString }; type UserCredentials = { - externalAuth: boolean; - disabled: boolean; - id: string; + id: Id; + code?: Id; + ldapId?: string; + openId?: string; + access: Access; twoFA?: boolean; - twoFactorEnabled?: boolean; - invitation: boolean; - selfRegistered: boolean; username: string; - access: Access; sharing: Sharing; + disabled: boolean; + invitation: boolean; + externalAuth: boolean; + selfRegistered: boolean; + twoFactorEnabled?: boolean; cogsDimensionConstraints: Ref[]; catDimensionConstraints: Ref[]; previousPasswords?: string[]; diff --git a/src/domain/usecases/user-monitoring/GetLogFormatDate.ts b/src/domain/usecases/user-monitoring/GetLogFormatDate.ts new file mode 100644 index 00000000..a95b4882 --- /dev/null +++ b/src/domain/usecases/user-monitoring/GetLogFormatDate.ts @@ -0,0 +1,13 @@ +export class GetLogFormatDate { + private logFormatDate(date: Date): string { + const isoString = date.toISOString(); + + return isoString.replace("Z", ""); + } + + constructor() {} + + execute(date: Date): string { + return this.logFormatDate(date); + } +} diff --git a/src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts b/src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts deleted file mode 100644 index 4dedbe09..00000000 --- a/src/domain/usecases/user-monitoring/GetLogFormatDateUseCase.ts +++ /dev/null @@ -1,19 +0,0 @@ -export class GetLogFormatDateUseCase { - private logFormatDate(date: Date): string { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, "0"); - const day = String(date.getDate()).padStart(2, "0"); - const hours = String(date.getHours()).padStart(2, "0"); - const minutes = String(date.getMinutes()).padStart(2, "0"); - const seconds = String(date.getSeconds()).padStart(2, "0"); - const milliseconds = String(date.getMilliseconds()).padStart(3, "0"); - - return `${year}-${month}-${day}T${hours}:${minutes}:${seconds},${milliseconds}`; - } - - constructor() {} - - execute(date: Date): string { - return this.logFormatDate(date); - } -} diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts index baf35908..0cb9a57f 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts @@ -6,15 +6,18 @@ import { UsersByAuthority, } from "domain/entities/user-monitoring/authorities-monitoring/AuthoritiesMonitoringOptions"; -import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; +import { GetLogFormatDate } from "../GetLogFormatDate"; export class SaveAuthoritiesMonitoringConfigUseCase { constructor(private configRepository: AuthoritiesMonitoringConfigRepository) {} async execute(options: AuthoritiesMonitoringOptions, usersByAuthority: UsersByAuthority): Async { - options.lastExecution = new GetLogFormatDateUseCase().execute(new Date()); - options.usersByAuthority = usersByAuthority; + const new_options = { + ...options, + lastExecution: new GetLogFormatDate().execute(new Date()), + usersByAuthority: usersByAuthority, + }; - await this.configRepository.save(options); + await this.configRepository.save(new_options); } } diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroups.ts similarity index 98% rename from src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroups.ts index 6cfe03c2..b4628b12 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/CompareUserGroups.ts @@ -1,7 +1,7 @@ import _ from "lodash"; import { UserGroup, UserGroupDiff } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; -export class CompareUserGroupsUseCase { +export class CompareUserGroups { constructor() {} private compareObjects(obj1: any, obj2: any): any { diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts index 9e6ee6d9..e89ae1e9 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/GetUserGroupsMonitoringConfigUseCase.ts @@ -1,9 +1,10 @@ +import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; export class GetUserGroupsMonitoringConfigUseCase { constructor(private configRepository: UserGroupsMonitoringConfigRepository) {} - async execute() { + async execute(): Promise { return this.configRepository.get(); } } diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts index 344023e6..6d8158a5 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts @@ -10,7 +10,7 @@ import { UserGroupRepository } from "domain/repositories/user-monitoring/user-gr import { UserGroupsMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-groups-monitoring/UserGroupsMonitoringConfigRepository"; import { GetUserGroupsUseCase } from "./GetUserGroupsUseCase"; -import { CompareUserGroupsUseCase } from "./CompareUserGroupsUseCase"; +import { CompareUserGroups } from "./CompareUserGroups"; import { GetUserGroupsMonitoringConfigUseCase } from "./GetUserGroupsMonitoringConfigUseCase"; import { SaveUserGroupsMonitoringConfigUseCase } from "./SaveUserGroupsMonitoringConfigUseCase"; @@ -73,7 +73,7 @@ export class MonitorUserGroupsUseCase { log.info(`Get user groups with ids: ${options.groupsToMonitor.join(", ")}`); const getGroupsUseCase = new GetUserGroupsUseCase(this.userGroupRepository); - const compareUserGroupsUseCase = new CompareUserGroupsUseCase(); + const compareUserGroupsUseCase = new CompareUserGroups(); const userGroups: UserGroup[] = await getGroupsUseCase.execute(options.groupsToMonitor); log.info(`Retrieved user groups: ${userGroups.map(g => g.id).join(", ")}`); diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts index c07411ab..3d869733 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts @@ -4,15 +4,18 @@ import { Async } from "domain/entities/Async"; import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; -import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; +import { GetLogFormatDate } from "../GetLogFormatDate"; export class SaveUserGroupsMonitoringConfigUseCase { constructor(private configRepository: UserGroupsMonitoringConfigRepository) {} async execute(options: UserGroupsMonitoringOptions, monitoredUserGroups: UserGroup[]): Async { - options.lastExecution = new GetLogFormatDateUseCase().execute(new Date()); - options.monitoredUserGroups = monitoredUserGroups; + const new_options = { + ...options, + lastExecution: new GetLogFormatDate().execute(new Date()), + monitoredUserGroups: monitoredUserGroups, + }; - await this.configRepository.save(options); + await this.configRepository.save(new_options); } } diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts index 976799c2..6485c1dc 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from "vitest"; import _ from "lodash"; -import { CompareUserGroupsUseCase } from "../CompareUserGroupsUseCase"; +import { CompareUserGroups } from "../CompareUserGroups"; import { emptyDiff, userGroup1Diff, @@ -12,7 +12,7 @@ import { describe("CompareUserGroupsUseCase", () => { it("Should return empty array when comparing the same objects", () => { - const useCase = new CompareUserGroupsUseCase(); + const useCase = new CompareUserGroups(); const minUserGroup2 = _.cloneDeep(minimalUserGroup); @@ -27,7 +27,7 @@ describe("CompareUserGroupsUseCase", () => { }); it("Should return the differences between two user groups", () => { - const useCase = new CompareUserGroupsUseCase(); + const useCase = new CompareUserGroups(); const result = useCase.execute(userGroup1, userGroup1Updated); diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplates.ts similarity index 98% rename from src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplates.ts index 315bf023..7520c49e 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/CompareUserTemplates.ts @@ -1,7 +1,7 @@ import _ from "lodash"; import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; -export class CompareUserTemplatesUseCase { +export class CompareUserTemplates { constructor() {} private membershipKeys = ["userRoles", "userGroups"]; diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts index 8c0e084b..cadc305e 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/GetUserTemplatesMonitoringConfigUseCase.ts @@ -1,9 +1,10 @@ +import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository"; export class GetUserTemplatesMonitoringConfigUseCase { constructor(private configRepository: UserTemplatesMonitoringConfigRepository) {} - async execute() { + async execute(): Promise { return this.configRepository.get(); } } diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts index d22854ba..0613efb7 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts @@ -11,7 +11,7 @@ import { UserRepository } from "domain/repositories/user-monitoring/user-templat import { UserTemplatesMonitoringConfigRepository } from "domain/repositories/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringConfigRepository"; import { GetUserTemplatesUseCase } from "./GetUserTemplatesUseCase"; -import { CompareUserTemplatesUseCase } from "./CompareUserTemplatesUseCase"; +import { CompareUserTemplates } from "./CompareUserTemplates"; import { GetUserTemplatesMonitoringConfigUseCase } from "./GetUserTemplatesMonitoringConfigUseCase"; import { SaveUserTemplatesMonitoringConfigUseCase } from "./SaveUserTemplatesMonitoringConfigUseCase"; @@ -97,7 +97,7 @@ export class MonitorUserTemplatesUseCase { log.info(`Get user groups with usernames: ${options.templatesToMonitor.join(", ")}`); const getTemplatesUseCase = new GetUserTemplatesUseCase(this.usersRepository); - const compareUserTemplatesUseCase = new CompareUserTemplatesUseCase(); + const compareUserTemplatesUseCase = new CompareUserTemplates(); const userTemplates: User[] = await getTemplatesUseCase.execute(options.templatesToMonitor); log.info(`Retrieved user templates: ${userTemplates.map(g => g.username).join(", ")}`); diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts index 6a37f118..e9bcfdc2 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts @@ -4,15 +4,18 @@ import { Async } from "domain/entities/Async"; import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; -import { GetLogFormatDateUseCase } from "../GetLogFormatDateUseCase"; +import { GetLogFormatDate } from "../GetLogFormatDate"; export class SaveUserTemplatesMonitoringConfigUseCase { constructor(private configRepository: UserTemplatesMonitoringConfigRepository) {} async execute(options: UserTemplatesMonitoringOptions, monitoredUserTemplates: User[]): Async { - options.lastExecution = new GetLogFormatDateUseCase().execute(new Date()); - options.monitoredUserTemplates = monitoredUserTemplates; + const new_options = { + ...options, + lastExecution: new GetLogFormatDate().execute(new Date()), + monitoredUserTemplates: monitoredUserTemplates, + }; - await this.configRepository.save(options); + await this.configRepository.save(new_options); } } diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts index d9631dcf..64a4f627 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts @@ -3,6 +3,7 @@ import { User, UserTemplateDiff } from "domain/entities/user-monitoring/user-tem export const user1: User = { lastUpdated: "2024-06-10T10:25:27.228", id: "cNtWc18LXBS", + code: "User_Template", created: "2018-06-09T01:05:48.008", twoFA: false, invitation: false, @@ -119,6 +120,7 @@ export const user1: User = { export const user1Updated: User = { lastUpdated: "2024-06-11T10:25:27.228", id: "cNtWc18LXBS", + code: "Updated_User_Template", created: "2018-06-09T01:05:48.008", twoFA: true, invitation: true, @@ -256,6 +258,7 @@ export const expectedDiff: UserTemplateDiff = { selfRegistered: false, firstName: "User Template", name: "User Template", + code: "User_Template", favorite: false, displayName: "User Template", externalAuth: false, @@ -336,6 +339,7 @@ export const expectedDiff: UserTemplateDiff = { selfRegistered: true, firstName: "Updated User Template", name: "Updated User Template", + code: "Updated_User_Template", favorite: true, displayName: "Updated User Template", externalAuth: true, diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts index 00196f9c..09058024 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts @@ -2,13 +2,13 @@ import { describe, it, expect, beforeEach } from "vitest"; import { user1, user1Updated, noChangesDiff, expectedDiff } from "./CompareUserTemplatesUseCase.data"; -import { CompareUserTemplatesUseCase } from "../CompareUserTemplatesUseCase"; +import { CompareUserTemplates } from "../CompareUserTemplates"; describe("CompareUserTemplatesUseCase", () => { - let useCase: CompareUserTemplatesUseCase; + let useCase: CompareUserTemplates; beforeEach(() => { - useCase = new CompareUserTemplatesUseCase(); + useCase = new CompareUserTemplates(); }); it("should not fild differences between the same user templates", () => { From 11f770c362f036e51da084cc780e3ef184ca84ef Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:23:54 +0200 Subject: [PATCH 19/20] fix: no changes check was failing --- .../user-groups-monitoring/MonitorUserGroupsUseCase.ts | 3 ++- .../user-templates-monitoring/MonitorUserTemplatesUseCase.ts | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts index 6d8158a5..78fe48ef 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts @@ -92,7 +92,8 @@ export class MonitorUserGroupsUseCase { _.isEmpty(changes.changedPropsAdded) && _.isEmpty(changes.changedPropsLost) && _.isEmpty(changes.newProps) && - _.isEmpty(changes.usersChanges) + _.isEmpty(changes.usersChanges.usersAdded) && + _.isEmpty(changes.usersChanges.usersLost) ) { return []; } diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts index 0613efb7..4e12002b 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts @@ -117,7 +117,10 @@ export class MonitorUserTemplatesUseCase { _.isEmpty(changes.changedPropsAdded) && _.isEmpty(changes.changedPropsLost) && _.isEmpty(changes.newProps) && - _.isEmpty(changes.membershipChanges) + _.isEmpty(changes.membershipChanges.userGroupsAdded) && + _.isEmpty(changes.membershipChanges.userGroupsLost) && + _.isEmpty(changes.membershipChanges.userRolesAdded) && + _.isEmpty(changes.membershipChanges.userRolesLost) ) { return []; } From 3d1e21610166b54966eb4d7d9e7a74632511ef25 Mon Sep 17 00:00:00 2001 From: nshandra <34254522+nshandra@users.noreply.github.com> Date: Tue, 24 Sep 2024 21:30:05 +0200 Subject: [PATCH 20/20] fix: address PR#52 comments round 4 Simplify getLogFormatDate, naming and casing. Fix userRoles repeating in userCredentials. --- .../common/MessageMSTeamsRepository.ts | 6 ++--- .../entities/MSTeamsWebhookOptions.ts | 4 ++-- .../UserD2Repository.ts | 22 ++++++++++------- .../user-monitoring/GetLogFormatDate.ts | 19 +++++++-------- ...se.ts => CheckUserByAuthoritiesChanges.ts} | 2 +- .../MonitorUsersByAuthorityUseCase.ts | 6 ++--- .../SaveAuthoritiesMonitoringConfigUseCase.ts | 8 +++---- ...=> CheckUserByAuthoritiesChanges.specs.ts} | 24 +++++++++---------- .../MonitorUserGroupsUseCase.ts | 4 ++-- .../SaveUserGroupsMonitoringConfigUseCase.ts | 8 +++---- ...Case.data.ts => CompareUserGroups.data.ts} | 0 ...se.specs.ts => CompareUserGroups.specs.ts} | 14 +++++------ .../MonitorUserTemplatesUseCase.ts | 6 ++--- ...aveUserTemplatesMonitoringConfigUseCase.ts | 8 +++---- ...e.data.ts => CompareUserTemplates.data.ts} | 0 ...specs.ts => CompareUserTemplates.specs.ts} | 12 +++++----- src/scripts/commands/userMonitoring.ts | 8 +++---- 17 files changed, 77 insertions(+), 74 deletions(-) rename src/domain/usecases/user-monitoring/authorities-monitoring/{CheckUserByAuthoritiesChangesUseCase.ts => CheckUserByAuthoritiesChanges.ts} (97%) rename src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/{CheckUserByAuthoritiesChangesUseCase.specs.ts => CheckUserByAuthoritiesChanges.specs.ts} (57%) rename src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/{CompareUserGroupsUseCase.data.ts => CompareUserGroups.data.ts} (100%) rename src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/{CompareUserGroupsUseCase.specs.ts => CompareUserGroups.specs.ts} (60%) rename src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/{CompareUserTemplatesUseCase.data.ts => CompareUserTemplates.data.ts} (100%) rename src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/{CompareUserTemplatesUseCase.specs.ts => CompareUserTemplates.specs.ts} (60%) diff --git a/src/data/user-monitoring/common/MessageMSTeamsRepository.ts b/src/data/user-monitoring/common/MessageMSTeamsRepository.ts index 15381035..a04ccd57 100644 --- a/src/data/user-monitoring/common/MessageMSTeamsRepository.ts +++ b/src/data/user-monitoring/common/MessageMSTeamsRepository.ts @@ -9,8 +9,8 @@ export class MessageMSTeamsRepository implements MessageRepository { async sendMessage(messageType: string, message: string): Async { const httpProxy = this.webhook.proxy; - const url = this.webhook.ms_url; - const server_name = this.webhook.server_name; + const url = this.webhook.msUrl; + const serverName = this.webhook.serverName; if (!isEmpty(httpProxy)) { process.env["http_proxy"] = httpProxy; @@ -18,7 +18,7 @@ export class MessageMSTeamsRepository implements MessageRepository { } const postData = JSON.stringify({ - text: `[*${messageType}* - ${server_name}] - ${message}`, + text: `[*${messageType}* - ${serverName}] - ${message}`, }); const requestOptions = { diff --git a/src/data/user-monitoring/entities/MSTeamsWebhookOptions.ts b/src/data/user-monitoring/entities/MSTeamsWebhookOptions.ts index 0c1e295e..5a760e16 100644 --- a/src/data/user-monitoring/entities/MSTeamsWebhookOptions.ts +++ b/src/data/user-monitoring/entities/MSTeamsWebhookOptions.ts @@ -1,5 +1,5 @@ export interface MSTeamsWebhookOptions { - ms_url: string; + msUrl: string; proxy: string; - server_name: string; + serverName: string; } diff --git a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts index d0730ccf..836e9b2a 100644 --- a/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts +++ b/src/data/user-monitoring/user-templates-monitoring/UserD2Repository.ts @@ -17,21 +17,25 @@ export class UserD2Repository implements UserRepository { .getData(); return users.objects.map((user): User => { + // used to avoid repeating userRoles in userCredentials + const { userRoles, ...userCredentials } = user.userCredentials; + return { ...user, - username: user.userCredentials.username, - disabled: user.userCredentials.disabled, - twoFA: user.userCredentials.twoFA, - userRoles: user.userCredentials.userRoles, - invitation: user.userCredentials.invitation, - externalAuth: user.userCredentials.externalAuth, - selfRegistered: user.userCredentials.selfRegistered, - catDimensionConstraints: user.userCredentials.catDimensionConstraints, - cogsDimensionConstraints: user.userCredentials.cogsDimensionConstraints, + username: userCredentials.username, + disabled: userCredentials.disabled, + twoFA: userCredentials.twoFA, + userRoles: userRoles, + invitation: userCredentials.invitation, + externalAuth: userCredentials.externalAuth, + selfRegistered: userCredentials.selfRegistered, + catDimensionConstraints: userCredentials.catDimensionConstraints, + cogsDimensionConstraints: userCredentials.cogsDimensionConstraints, attributeValues: user.attributeValues.map(attributeValue => ({ attribute: attributeValue.attribute.name, value: attributeValue.value, })), + userCredentials: userCredentials, }; }); } diff --git a/src/domain/usecases/user-monitoring/GetLogFormatDate.ts b/src/domain/usecases/user-monitoring/GetLogFormatDate.ts index a95b4882..92665d23 100644 --- a/src/domain/usecases/user-monitoring/GetLogFormatDate.ts +++ b/src/domain/usecases/user-monitoring/GetLogFormatDate.ts @@ -1,13 +1,12 @@ -export class GetLogFormatDate { - private logFormatDate(date: Date): string { - const isoString = date.toISOString(); +/** + * Formats a given date into a DHIS2 log timestamp. + * + * @param date - The date to be formatted. + * @returns The timestamp as a string. + */ - return isoString.replace("Z", ""); - } +export function getLogFormatDate(date: Date): string { + const isoString = date.toISOString(); - constructor() {} - - execute(date: Date): string { - return this.logFormatDate(date); - } + return isoString.replace("Z", "").replace(".", ","); } diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/CheckUserByAuthoritiesChangesUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/CheckUserByAuthoritiesChanges.ts similarity index 97% rename from src/domain/usecases/user-monitoring/authorities-monitoring/CheckUserByAuthoritiesChangesUseCase.ts rename to src/domain/usecases/user-monitoring/authorities-monitoring/CheckUserByAuthoritiesChanges.ts index c00684a1..8ab3c038 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/CheckUserByAuthoritiesChangesUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/CheckUserByAuthoritiesChanges.ts @@ -2,7 +2,7 @@ import _ from "lodash"; import { Async } from "../../../entities/Async"; import { UsersByAuthority } from "../../../entities/user-monitoring/authorities-monitoring/AuthoritiesMonitoringOptions"; -export class CheckUserByAuthoritiesChangesUseCase { +export class CheckUserByAuthoritiesChanges { constructor() {} private compareDicts(dict1: UsersByAuthority, dict2: UsersByAuthority) { diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts index 9a7c4ab6..b4e728d2 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/MonitorUsersByAuthorityUseCase.ts @@ -10,7 +10,7 @@ import { User } from "domain/entities/user-monitoring/authorities-monitoring/Use import { AuthoritiesMonitoringOptions } from "domain/entities/user-monitoring/authorities-monitoring/AuthoritiesMonitoringOptions"; import { GetUsersByAuthoritiesUseCase } from "./GetUsersByAuthoritiesUseCase"; -import { CheckUserByAuthoritiesChangesUseCase } from "./CheckUserByAuthoritiesChangesUseCase"; +import { CheckUserByAuthoritiesChanges } from "./CheckUserByAuthoritiesChanges"; import { GetAuthoritiesMonitoringConfigUseCase } from "./GetAuthoritiesMonitoringConfigUseCase"; import { SaveAuthoritiesMonitoringConfigUseCase } from "./SaveAuthoritiesMonitoringConfigUseCase"; @@ -61,8 +61,8 @@ export class MonitorUsersByAuthorityUseCase { this.debugJSON("Users by authority:", usersByAuthority); if (!setDataStore) { - const checkUsersChangesUseCase = new CheckUserByAuthoritiesChangesUseCase(); - const { newUsers, usersLosingAuth } = await checkUsersChangesUseCase.execute( + const checkUsersChanges = new CheckUserByAuthoritiesChanges(); + const { newUsers, usersLosingAuth } = await checkUsersChanges.execute( options.usersByAuthority, usersByAuthority ); diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts index 0cb9a57f..b52c2e91 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/SaveAuthoritiesMonitoringConfigUseCase.ts @@ -6,18 +6,18 @@ import { UsersByAuthority, } from "domain/entities/user-monitoring/authorities-monitoring/AuthoritiesMonitoringOptions"; -import { GetLogFormatDate } from "../GetLogFormatDate"; +import { getLogFormatDate } from "../GetLogFormatDate"; export class SaveAuthoritiesMonitoringConfigUseCase { constructor(private configRepository: AuthoritiesMonitoringConfigRepository) {} async execute(options: AuthoritiesMonitoringOptions, usersByAuthority: UsersByAuthority): Async { - const new_options = { + const newOptions = { ...options, - lastExecution: new GetLogFormatDate().execute(new Date()), + lastExecution: getLogFormatDate(new Date()), usersByAuthority: usersByAuthority, }; - await this.configRepository.save(new_options); + await this.configRepository.save(newOptions); } } diff --git a/src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/CheckUserByAuthoritiesChangesUseCase.specs.ts b/src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/CheckUserByAuthoritiesChanges.specs.ts similarity index 57% rename from src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/CheckUserByAuthoritiesChangesUseCase.specs.ts rename to src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/CheckUserByAuthoritiesChanges.specs.ts index 5b0d87aa..86a29dcb 100644 --- a/src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/CheckUserByAuthoritiesChangesUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/authorities-monitoring/__tests__/CheckUserByAuthoritiesChanges.specs.ts @@ -8,49 +8,49 @@ import { noneUsers, } from "./AuthoritiesMonitoringTests.data"; -import { CheckUserByAuthoritiesChangesUseCase } from "../CheckUserByAuthoritiesChangesUseCase"; +import { CheckUserByAuthoritiesChanges } from "../CheckUserByAuthoritiesChanges"; -describe("CheckUserByAuthoritiesChangesUseCase", () => { +describe("CheckUserByAuthoritiesChanges", () => { it("Should find no changes in the same UsersByAuthority object", async () => { - const useCase = new CheckUserByAuthoritiesChangesUseCase(); + const checkChanges = new CheckUserByAuthoritiesChanges(); - const { newUsers, usersLosingAuth } = await useCase.execute(allAuthUsers, allAuthUsers); + const { newUsers, usersLosingAuth } = await checkChanges.execute(allAuthUsers, allAuthUsers); expect(newUsers).toEqual(noChanges); expect(usersLosingAuth).toEqual(noChanges); }); it("Should find users with new authorities", async () => { - const useCase = new CheckUserByAuthoritiesChangesUseCase(); + const checkChanges = new CheckUserByAuthoritiesChanges(); - const { newUsers, usersLosingAuth } = await useCase.execute(noneUsers, allAuthUsers); + const { newUsers, usersLosingAuth } = await checkChanges.execute(noneUsers, allAuthUsers); expect(newUsers).toEqual(allAuthUsers); expect(usersLosingAuth).toEqual(noChanges); }); it("Should find users losing authorities", async () => { - const useCase = new CheckUserByAuthoritiesChangesUseCase(); + const checkChanges = new CheckUserByAuthoritiesChanges(); - const { newUsers, usersLosingAuth } = await useCase.execute(auth2Users, noneUsers); + const { newUsers, usersLosingAuth } = await checkChanges.execute(auth2Users, noneUsers); expect(newUsers).toEqual(noChanges); expect(usersLosingAuth).toEqual(auth2Users); }); it("Should find new and losing types of changes", async () => { - const useCase = new CheckUserByAuthoritiesChangesUseCase(); + const checkChanges = new CheckUserByAuthoritiesChanges(); - const { newUsers, usersLosingAuth } = await useCase.execute(auth2Users, auth1Users); + const { newUsers, usersLosingAuth } = await checkChanges.execute(auth2Users, auth1Users); expect(newUsers).toEqual(auth1Users); expect(usersLosingAuth).toEqual(auth2Users); }); it("Should find new, no change and losing types of changes", async () => { - const useCase = new CheckUserByAuthoritiesChangesUseCase(); + const checkChanges = new CheckUserByAuthoritiesChanges(); - const { newUsers, usersLosingAuth } = await useCase.execute(twoAuthUsers, auth1and2Users); + const { newUsers, usersLosingAuth } = await checkChanges.execute(twoAuthUsers, auth1and2Users); expect(newUsers).toEqual(auth1Users); expect(usersLosingAuth).toEqual(auth3Users); diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts index 78fe48ef..ddcc674e 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/MonitorUserGroupsUseCase.ts @@ -73,7 +73,7 @@ export class MonitorUserGroupsUseCase { log.info(`Get user groups with ids: ${options.groupsToMonitor.join(", ")}`); const getGroupsUseCase = new GetUserGroupsUseCase(this.userGroupRepository); - const compareUserGroupsUseCase = new CompareUserGroups(); + const compareUserGroups = new CompareUserGroups(); const userGroups: UserGroup[] = await getGroupsUseCase.execute(options.groupsToMonitor); log.info(`Retrieved user groups: ${userGroups.map(g => g.id).join(", ")}`); @@ -86,7 +86,7 @@ export class MonitorUserGroupsUseCase { return []; } - const changes = compareUserGroupsUseCase.execute(orig, group); + const changes = compareUserGroups.execute(orig, group); if ( _.isEmpty(changes.changedPropsAdded) && diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts index 3d869733..4cb720d1 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/SaveUserGroupsMonitoringConfigUseCase.ts @@ -4,18 +4,18 @@ import { Async } from "domain/entities/Async"; import { UserGroupsMonitoringOptions } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroupsMonitoringOptions"; import { UserGroup } from "domain/entities/user-monitoring/user-groups-monitoring/UserGroups"; -import { GetLogFormatDate } from "../GetLogFormatDate"; +import { getLogFormatDate } from "../GetLogFormatDate"; export class SaveUserGroupsMonitoringConfigUseCase { constructor(private configRepository: UserGroupsMonitoringConfigRepository) {} async execute(options: UserGroupsMonitoringOptions, monitoredUserGroups: UserGroup[]): Async { - const new_options = { + const newOptions = { ...options, - lastExecution: new GetLogFormatDate().execute(new Date()), + lastExecution: getLogFormatDate(new Date()), monitoredUserGroups: monitoredUserGroups, }; - await this.configRepository.save(new_options); + await this.configRepository.save(newOptions); } } diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroups.data.ts similarity index 100% rename from src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.data.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroups.data.ts diff --git a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroups.specs.ts similarity index 60% rename from src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts rename to src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroups.specs.ts index 6485c1dc..a6c631b4 100644 --- a/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroupsUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-groups-monitoring/__tests__/CompareUserGroups.specs.ts @@ -8,28 +8,28 @@ import { minimalUserGroup, userGroup1, userGroup1Updated, -} from "./CompareUserGroupsUseCase.data"; +} from "./CompareUserGroups.data"; -describe("CompareUserGroupsUseCase", () => { +describe("CompareUserGroups", () => { it("Should return empty array when comparing the same objects", () => { - const useCase = new CompareUserGroups(); + const compareUserGroups = new CompareUserGroups(); const minUserGroup2 = _.cloneDeep(minimalUserGroup); - const result = useCase.execute(minimalUserGroup, minUserGroup2); + const result = compareUserGroups.execute(minimalUserGroup, minUserGroup2); const userGroup2 = _.cloneDeep(userGroup1); - const result2 = useCase.execute(userGroup1, userGroup2); + const result2 = compareUserGroups.execute(userGroup1, userGroup2); expect(result).toEqual(emptyDiff); expect(result2).toEqual(emptyDiff); }); it("Should return the differences between two user groups", () => { - const useCase = new CompareUserGroups(); + const compareUserGroups = new CompareUserGroups(); - const result = useCase.execute(userGroup1, userGroup1Updated); + const result = compareUserGroups.execute(userGroup1, userGroup1Updated); expect(result).toEqual(userGroup1Diff); }); diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts index 4e12002b..ad70cb03 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/MonitorUserTemplatesUseCase.ts @@ -97,7 +97,7 @@ export class MonitorUserTemplatesUseCase { log.info(`Get user groups with usernames: ${options.templatesToMonitor.join(", ")}`); const getTemplatesUseCase = new GetUserTemplatesUseCase(this.usersRepository); - const compareUserTemplatesUseCase = new CompareUserTemplates(); + const compareUserTemplates = new CompareUserTemplates(); const userTemplates: User[] = await getTemplatesUseCase.execute(options.templatesToMonitor); log.info(`Retrieved user templates: ${userTemplates.map(g => g.username).join(", ")}`); @@ -111,7 +111,7 @@ export class MonitorUserTemplatesUseCase { return []; } - const changes = compareUserTemplatesUseCase.execute(orig, user); + const changes = compareUserTemplates.execute(orig, user); if ( _.isEmpty(changes.changedPropsAdded) && @@ -128,7 +128,7 @@ export class MonitorUserTemplatesUseCase { return changes; }); - log.info(`userGroupsChanges: ${this.stringifyObject(userGroupsChanges)}`); + log.debug(`userGroupsChanges: ${this.stringifyObject(userGroupsChanges)}`); if (_.isEmpty(userGroupsChanges)) { log.info("Report: No changes."); diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts index e9bcfdc2..726b110e 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/SaveUserTemplatesMonitoringConfigUseCase.ts @@ -4,18 +4,18 @@ import { Async } from "domain/entities/Async"; import { UserTemplatesMonitoringOptions } from "domain/entities/user-monitoring/user-templates-monitoring/UserTemplatesMonitoringOptions"; import { User } from "domain/entities/user-monitoring/user-templates-monitoring/Users"; -import { GetLogFormatDate } from "../GetLogFormatDate"; +import { getLogFormatDate } from "../GetLogFormatDate"; export class SaveUserTemplatesMonitoringConfigUseCase { constructor(private configRepository: UserTemplatesMonitoringConfigRepository) {} async execute(options: UserTemplatesMonitoringOptions, monitoredUserTemplates: User[]): Async { - const new_options = { + const newOptions = { ...options, - lastExecution: new GetLogFormatDate().execute(new Date()), + lastExecution: getLogFormatDate(new Date()), monitoredUserTemplates: monitoredUserTemplates, }; - await this.configRepository.save(new_options); + await this.configRepository.save(newOptions); } } diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplates.data.ts similarity index 100% rename from src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.data.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplates.data.ts diff --git a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplates.specs.ts similarity index 60% rename from src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts rename to src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplates.specs.ts index 09058024..3681324a 100644 --- a/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplatesUseCase.specs.ts +++ b/src/domain/usecases/user-monitoring/user-templates-monitoring/__tests__/CompareUserTemplates.specs.ts @@ -1,24 +1,24 @@ import { describe, it, expect, beforeEach } from "vitest"; -import { user1, user1Updated, noChangesDiff, expectedDiff } from "./CompareUserTemplatesUseCase.data"; +import { user1, user1Updated, noChangesDiff, expectedDiff } from "./CompareUserTemplates.data"; import { CompareUserTemplates } from "../CompareUserTemplates"; -describe("CompareUserTemplatesUseCase", () => { - let useCase: CompareUserTemplates; +describe("CompareUserTemplates", () => { + let compareUserTemplates: CompareUserTemplates; beforeEach(() => { - useCase = new CompareUserTemplates(); + compareUserTemplates = new CompareUserTemplates(); }); it("should not fild differences between the same user templates", () => { - const diff = useCase.execute(user1, user1); + const diff = compareUserTemplates.execute(user1, user1); expect(diff).toEqual(noChangesDiff); }); it("should compare user templates and return the differences", () => { - const diff = useCase.execute(user1, user1Updated); + const diff = compareUserTemplates.execute(user1, user1Updated); expect(diff).toEqual(expectedDiff); }); diff --git a/src/scripts/commands/userMonitoring.ts b/src/scripts/commands/userMonitoring.ts index 717a6ffb..d038704d 100644 --- a/src/scripts/commands/userMonitoring.ts +++ b/src/scripts/commands/userMonitoring.ts @@ -232,14 +232,14 @@ function getAuthFromFile(configFile: string): UserMonitoringAuth { function getWebhookConfFromFile(configFile: string): MSTeamsWebhookOptions { const fs = require("fs"); const configJSON = JSON.parse(fs.readFileSync("./" + configFile, "utf8")); - const ms_url = configJSON["WEBHOOK"]["ms_url"]; + const msUrl = configJSON["WEBHOOK"]["ms_url"]; const proxy = configJSON["WEBHOOK"]["proxy"]; - const server_name = configJSON["WEBHOOK"]["server_name"]; + const serverName = configJSON["WEBHOOK"]["server_name"]; return { - ms_url: ms_url, + msUrl: msUrl, proxy: proxy, - server_name: server_name, + serverName: serverName, }; }