Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update call notification push rule to match MSC3914 #2781

Merged
merged 7 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions spec/unit/pushprocessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,22 @@ describe('NotificationService', function() {
"enabled": true,
"rule_id": ".m.rule.room_one_to_one",
},
{
rule_id: ".org.matrix.msc3914.rule.room.call",
default: true,
enabled: true,
conditions: [
{
kind: "event_match",
key: "type",
pattern: "org.matrix.msc3401.call",
},
{
kind: "call_started",
},
],
actions: ["notify", { set_tweak: "sound", value: "default" }],
},
],
"room": [],
"sender": [],
Expand Down Expand Up @@ -337,7 +353,11 @@ describe('NotificationService', function() {
}, testEvent)).toBe(true);
});

describe("performCustomEventHandling()", () => {
describe("group call started push rule", () => {
beforeEach(() => {
matrixClient.pushRules!.global!.underride!.find(r => r.rule_id === ".m.rule.fallback")!.enabled = false;
});

const getActionsForEvent = (prevContent: IContent, content: IContent): IActionsObject => {
testEvent = utils.mkEvent({
type: "org.matrix.msc3401.call",
Expand All @@ -353,15 +373,15 @@ describe('NotificationService', function() {
};

const assertDoesNotify = (actions: IActionsObject): void => {
expect(actions.notify).toBeTruthy();
expect(actions.tweaks.sound).toBeTruthy();
expect(actions.tweaks.highlight).toBeFalsy();
expect(actions?.notify).toBeTruthy();
expect(actions?.tweaks?.sound).toBeTruthy();
expect(actions?.tweaks?.highlight).toBeFalsy();
};

const assertDoesNotNotify = (actions: IActionsObject): void => {
expect(actions.notify).toBeFalsy();
expect(actions.tweaks.sound).toBeFalsy();
expect(actions.tweaks.highlight).toBeFalsy();
expect(actions?.notify).toBeFalsy();
expect(actions?.tweaks?.sound).toBeFalsy();
expect(actions?.tweaks?.highlight).toBeFalsy();
};

it.each(
Expand Down
14 changes: 13 additions & 1 deletion src/@types/PushRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export enum ConditionKind {
ContainsDisplayName = "contains_display_name",
RoomMemberCount = "room_member_count",
SenderNotificationPermission = "sender_notification_permission",
CallStarted = "call_started",
CallStartedPrefix = "org.matrix.msc3914.call_started",
}

export interface IPushRuleCondition<N extends ConditionKind | string> {
Expand All @@ -90,12 +92,22 @@ export interface ISenderNotificationPermissionCondition
key: string;
}

export interface ICallStartedCondition extends IPushRuleCondition<ConditionKind.CallStarted> {
// no additional fields
}

export interface ICallStartedPrefixCondition extends IPushRuleCondition<ConditionKind.CallStartedPrefix> {
// no additional fields
}

// XXX: custom conditions are possible but always fail, and break the typescript discriminated union so ignore them here
// IPushRuleCondition<Exclude<string, ConditionKind>> unfortunately does not resolve this at the time of writing.
export type PushRuleCondition = IEventMatchCondition
| IContainsDisplayNameCondition
| IRoomMemberCountCondition
| ISenderNotificationPermissionCondition;
| ISenderNotificationPermissionCondition
| ICallStartedCondition
| ICallStartedPrefixCondition;

export enum PushRuleKind {
Override = "override",
Expand Down
54 changes: 27 additions & 27 deletions src/pushprocessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { MatrixEvent } from "./models/event";
import {
ConditionKind,
IAnnotatedPushRule,
ICallStartedCondition,
ICallStartedPrefixCondition,
IContainsDisplayNameCondition,
IEventMatchCondition,
IPushRule,
Expand Down Expand Up @@ -92,8 +94,8 @@ const DEFAULT_OVERRIDE_RULES: IPushRule[] = [
actions: [],
},
{
// For homeservers which don't support MSC3401 yet
rule_id: ".org.matrix.msc3401.rule.room.call",
// For homeservers which don't support MSC3914 yet
rule_id: ".org.matrix.msc3914.rule.room.call",
default: true,
enabled: true,
conditions: [
Expand All @@ -102,6 +104,9 @@ const DEFAULT_OVERRIDE_RULES: IPushRule[] = [
key: "type",
pattern: "org.matrix.msc3401.call",
},
{
kind: ConditionKind.CallStarted,
},
],
actions: [PushRuleActionName.Notify, { set_tweak: TweakName.Sound, value: "default" }],
},
Expand Down Expand Up @@ -269,6 +274,9 @@ export class PushProcessor {
return this.eventFulfillsRoomMemberCountCondition(cond, ev);
case ConditionKind.SenderNotificationPermission:
return this.eventFulfillsSenderNotifPermCondition(cond, ev);
case ConditionKind.CallStarted:
case ConditionKind.CallStartedPrefix:
return this.eventFulfillsCallStartedCondition(cond, ev);
}

// unknown conditions: we previously matched all unknown conditions,
Expand Down Expand Up @@ -383,6 +391,22 @@ export class PushProcessor {
return !!val.match(regex);
}

private eventFulfillsCallStartedCondition(
_cond: ICallStartedCondition | ICallStartedPrefixCondition,
ev: MatrixEvent,
): boolean {
// Since servers don't support properly sending push notification
// about MSC3401 call events, we do the handling ourselves
return (
["m.ring", "m.prompt"].includes(ev.getContent()["m.intent"])
&& !("m.terminated" in ev.getContent())
&& (
(ev.getPrevContent()["m.terminated"] !== ev.getContent()["m.terminated"])
|| deepCompare(ev.getPrevContent(), {})
)
);
}

private createCachedRegex(prefix: string, glob: string, suffix: string): RegExp {
if (PushProcessor.cachedGlobToRegex[glob]) {
return PushProcessor.cachedGlobToRegex[glob];
Expand Down Expand Up @@ -438,7 +462,7 @@ export class PushProcessor {
return {} as IActionsObject;
}

let actionObj = PushProcessor.actionListToActionsObject(rule.actions);
const actionObj = PushProcessor.actionListToActionsObject(rule.actions);

// Some actions are implicit in some situations: we add those here
if (actionObj.tweaks.highlight === undefined) {
Expand All @@ -447,30 +471,6 @@ export class PushProcessor {
actionObj.tweaks.highlight = (rule.kind == PushRuleKind.ContentSpecific);
}

actionObj = this.performCustomEventHandling(ev, actionObj);

return actionObj;
}

/**
* Some events require custom event handling e.g. due to missing server support
*/
private performCustomEventHandling(ev: MatrixEvent, actionObj: IActionsObject): IActionsObject {
switch (ev.getType()) {
case "m.call":
case "org.matrix.msc3401.call":
// Since servers don't support properly sending push notification
// about MSC3401 call events, we do the handling ourselves
if (
ev.getContent()["m.intent"] === "m.room"
|| ("m.terminated" in ev.getContent())
|| !("m.terminated" in ev.getPrevContent()) && !deepCompare(ev.getPrevContent(), {})
) {
actionObj.notify = false;
actionObj.tweaks = {};
}
}

return actionObj;
}

Expand Down