diff --git a/src/data/externalConfig/Namespaces.ts b/src/data/externalConfig/Namespaces.ts index aead6f0..f61be24 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 0000000..6a01042 --- /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 0000000..c6e0458 --- /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 31b8143..611f880 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 0000000..5ce0fb6 --- /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 0000000..1ac1ee2 --- /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 0000000..bbad455 --- /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 0000000..797371d --- /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 83c3730..c6dfb1a 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 c9c2dfc..a6269ce 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 0000000..06c25b7 --- /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 0000000..785f93b --- /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 0000000..9c58de2 --- /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 0000000..1497861 --- /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 0000000..bb9fc0c --- /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 5e8127c..f332595 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); }, });