/* Copyright 2024 New Vector Ltd. Copyright 2023 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ import { type MatrixClient, type MatrixEvent, EventType, type RuleId, type IAnnotatedPushRule, type IPushRule, type PushRuleKind, } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { VectorPushRulesDefinitions, type VectorPushRuleDefinition } from "../../notifications"; import { updateExistingPushRulesWithActions } from "./updatePushRuleActions"; const pushRuleAndKindToAnnotated = ( ruleAndKind: { rule: IPushRule; kind: PushRuleKind } | null, ): IAnnotatedPushRule | undefined => ruleAndKind ? { ...ruleAndKind.rule, kind: ruleAndKind.kind, } : undefined; /** * Checks that any synced rules that exist a given rule are in sync * And updates any that are out of sync * Ignores ruleIds that do not exist for the user * @param matrixClient - cli * @param ruleId - primary rule * @param definition - VectorPushRuleDefinition of the primary rule */ const monitorSyncedRule = async ( matrixClient: MatrixClient, ruleId: RuleId | string, definition: VectorPushRuleDefinition, ): Promise => { const primaryRule = pushRuleAndKindToAnnotated(matrixClient.pushProcessor.getPushRuleAndKindById(ruleId)); if (!primaryRule) { return; } const syncedRules: IAnnotatedPushRule[] | undefined = definition.syncedRuleIds ?.map((ruleId) => pushRuleAndKindToAnnotated(matrixClient.pushProcessor.getPushRuleAndKindById(ruleId))) .filter((n?: IAnnotatedPushRule): n is IAnnotatedPushRule => Boolean(n)); // no synced rules to manage if (!syncedRules?.length) { return; } const primaryRuleVectorState = definition.ruleToVectorState(primaryRule); const outOfSyncRules = syncedRules.filter( (syncedRule) => syncedRule.enabled !== primaryRule.enabled || definition.ruleToVectorState(syncedRule) !== primaryRuleVectorState, ); if (outOfSyncRules.length) { await updateExistingPushRulesWithActions( matrixClient, // eslint-disable-next-line camelcase, @typescript-eslint/naming-convention outOfSyncRules.map(({ rule_id }) => rule_id), primaryRule.enabled ? primaryRule.actions : undefined, ); } }; /** * On changes to m.push_rules account data, * check that synced push rules are in sync with their primary rule, * and update any out of sync rules. * synced rules are defined in VectorPushRulesDefinitions * If updating a rule fails for any reason, * the error is caught and handled silently * @param accountDataEvent - MatrixEvent * @param matrixClient - cli * @returns Resolves when updates are complete */ export const monitorSyncedPushRules = async ( accountDataEvent: MatrixEvent | undefined, matrixClient: MatrixClient, ): Promise => { if (accountDataEvent?.getType() !== EventType.PushRules) { return; } Object.entries(VectorPushRulesDefinitions).forEach(async ([ruleId, definition]) => { try { await monitorSyncedRule(matrixClient, ruleId, definition); } catch (error) { logger.error(`Failed to fully synchronise push rules for ${ruleId}`, error); } }); };