Polls: sync push rules on changes to account_data (#10287)
* basic sync setup * formatting * get loudest value for synced rules * more types * test synced rules in notifications settings * type fixes * noimplicitany fixes * remove debug * tidying * extract updatePushRuleActions fn to utils * extract update synced rules * just synchronise in one place? * monitor account data changes AND trigger changes sync in notifications form * lint * setup LoggedInView test with enough mocks * test rule syncing in LoggedInView * strict fixes * more comments * one more comment
This commit is contained in:
parent
4c6f8ad122
commit
cef821c21b
5 changed files with 525 additions and 51 deletions
108
src/utils/pushRules/monitorSyncedPushRules.ts
Normal file
108
src/utils/pushRules/monitorSyncedPushRules.ts
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { PushProcessor } from "matrix-js-sdk/src/pushprocessor";
|
||||
import { RuleId, IAnnotatedPushRule } from "matrix-js-sdk/src/@types/PushRules";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { VectorPushRulesDefinitions, VectorPushRuleDefinition } from "../../notifications";
|
||||
import { updateExistingPushRulesWithActions } from "./updatePushRuleActions";
|
||||
|
||||
const pushRuleAndKindToAnnotated = (
|
||||
ruleAndKind: ReturnType<PushProcessor["getPushRuleAndKindById"]>,
|
||||
): 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 pushProcessor - processor used to retrieve current state of rules
|
||||
* @param ruleId - primary rule
|
||||
* @param definition - VectorPushRuleDefinition of the primary rule
|
||||
*/
|
||||
const monitorSyncedRule = async (
|
||||
matrixClient: MatrixClient,
|
||||
pushProcessor: PushProcessor,
|
||||
ruleId: RuleId | string,
|
||||
definition: VectorPushRuleDefinition,
|
||||
): Promise<void> => {
|
||||
const primaryRule = pushRuleAndKindToAnnotated(pushProcessor.getPushRuleAndKindById(ruleId));
|
||||
|
||||
if (!primaryRule) {
|
||||
return;
|
||||
}
|
||||
const syncedRules: IAnnotatedPushRule[] | undefined = definition.syncedRuleIds
|
||||
?.map((ruleId) => pushRuleAndKindToAnnotated(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) => 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.actions,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<void> => {
|
||||
if (accountDataEvent?.getType() !== EventType.PushRules) {
|
||||
return;
|
||||
}
|
||||
const pushProcessor = new PushProcessor(matrixClient);
|
||||
|
||||
Object.entries(VectorPushRulesDefinitions).forEach(async ([ruleId, definition]) => {
|
||||
try {
|
||||
await monitorSyncedRule(matrixClient, pushProcessor, ruleId, definition);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to fully synchronise push rules for ${ruleId}`, error);
|
||||
}
|
||||
});
|
||||
};
|
75
src/utils/pushRules/updatePushRuleActions.ts
Normal file
75
src/utils/pushRules/updatePushRuleActions.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { IPushRule, PushRuleAction, PushRuleKind } from "matrix-js-sdk/src/matrix";
|
||||
import { PushProcessor } from "matrix-js-sdk/src/pushprocessor";
|
||||
|
||||
/**
|
||||
* Sets the actions for a given push rule id and kind
|
||||
* When actions are falsy, disables the rule
|
||||
* @param matrixClient - cli
|
||||
* @param ruleId - rule id to update
|
||||
* @param kind - PushRuleKind
|
||||
* @param actions - push rule actions to set for rule
|
||||
*/
|
||||
export const updatePushRuleActions = async (
|
||||
matrixClient: MatrixClient,
|
||||
ruleId: IPushRule["rule_id"],
|
||||
kind: PushRuleKind,
|
||||
actions?: PushRuleAction[],
|
||||
): Promise<void> => {
|
||||
if (!actions) {
|
||||
await matrixClient.setPushRuleEnabled("global", kind, ruleId, false);
|
||||
} else {
|
||||
await matrixClient.setPushRuleActions("global", kind, ruleId, actions);
|
||||
await matrixClient.setPushRuleEnabled("global", kind, ruleId, true);
|
||||
}
|
||||
};
|
||||
|
||||
interface PushRuleAndKind {
|
||||
rule: IPushRule;
|
||||
kind: PushRuleKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update push rules with given actions
|
||||
* Where they already exist for current user
|
||||
* Rules are updated sequentially and stop at first error
|
||||
* @param matrixClient - cli
|
||||
* @param ruleIds - RuleIds of push rules to attempt to set actions for
|
||||
* @param actions - push rule actions to set for rule
|
||||
* @returns resolves when all rules have been updated
|
||||
* @returns rejects when a rule update fails
|
||||
*/
|
||||
export const updateExistingPushRulesWithActions = async (
|
||||
matrixClient: MatrixClient,
|
||||
ruleIds?: IPushRule["rule_id"][],
|
||||
actions?: PushRuleAction[],
|
||||
): Promise<void> => {
|
||||
const pushProcessor = new PushProcessor(matrixClient);
|
||||
|
||||
const rules: PushRuleAndKind[] | undefined = ruleIds
|
||||
?.map((ruleId) => pushProcessor.getPushRuleAndKindById(ruleId))
|
||||
.filter((n: PushRuleAndKind | null): n is PushRuleAndKind => Boolean(n));
|
||||
|
||||
if (!rules?.length) {
|
||||
return;
|
||||
}
|
||||
for (const { kind, rule } of rules) {
|
||||
await updatePushRuleActions(matrixClient, rule.rule_id, kind, actions);
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue