Skip to content

Commit

Permalink
Add alt event type matching in Relations model (#3018)
Browse files Browse the repository at this point in the history
* allow alt event types in relations model

* remove unneccesary checks on remove relation

* comment

* assert on event emitted
  • Loading branch information
Kerry authored Jan 5, 2023
1 parent d02559c commit bb23df9
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 16 deletions.
96 changes: 95 additions & 1 deletion spec/unit/relations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { M_POLL_START } from "matrix-events-sdk";

import { EventTimelineSet } from "../../src/models/event-timeline-set";
import { MatrixEvent, MatrixEventEvent } from "../../src/models/event";
import { Room } from "../../src/models/room";
import { Relations } from "../../src/models/relations";
import { Relations, RelationsEvent } from "../../src/models/relations";
import { TestClient } from "../TestClient";
import { RelationType } from "../../src";
import { logger } from "../../src/logger";

describe("Relations", function () {
afterEach(() => {
jest.spyOn(logger, "error").mockRestore();
});

it("should deduplicate annotations", function () {
const room = new Room("room123", null!, null!);
const relations = new Relations("m.annotation", "m.reaction", room);
Expand Down Expand Up @@ -75,6 +83,92 @@ describe("Relations", function () {
}
});

describe("addEvent()", () => {
const relationType = RelationType.Reference;
const eventType = M_POLL_START.stable!;
const altEventTypes = [M_POLL_START.unstable!];
const room = new Room("room123", null!, null!);

it("should not add events without a relation", async () => {
// dont pollute console
const logSpy = jest.spyOn(logger, "error").mockImplementation(() => {});
const relations = new Relations(relationType, eventType, room);
const emitSpy = jest.spyOn(relations, "emit");
const event = new MatrixEvent({ type: eventType });

await relations.addEvent(event);
expect(logSpy).toHaveBeenCalledWith("Event must have relation info");
// event not added
expect(relations.getRelations().length).toBe(0);
expect(emitSpy).not.toHaveBeenCalled();
});

it("should not add events of incorrect event type", async () => {
// dont pollute console
const logSpy = jest.spyOn(logger, "error").mockImplementation(() => {});
const relations = new Relations(relationType, eventType, room);
const emitSpy = jest.spyOn(relations, "emit");
const event = new MatrixEvent({
type: "different-event-type",
content: {
"m.relates_to": {
event_id: "$2s4yYpEkVQrPglSCSqB_m6E8vDhWsg0yFNyOJdVIb_o",
rel_type: relationType,
},
},
});

await relations.addEvent(event);

expect(logSpy).toHaveBeenCalledWith(`Event relation info doesn't match this container`);
// event not added
expect(relations.getRelations().length).toBe(0);
expect(emitSpy).not.toHaveBeenCalled();
});

it("adds events that match alt event types", async () => {
const relations = new Relations(relationType, eventType, room, altEventTypes);
const emitSpy = jest.spyOn(relations, "emit");
const event = new MatrixEvent({
type: M_POLL_START.unstable!,
content: {
"m.relates_to": {
event_id: "$2s4yYpEkVQrPglSCSqB_m6E8vDhWsg0yFNyOJdVIb_o",
rel_type: relationType,
},
},
});

await relations.addEvent(event);

// event added
expect(relations.getRelations()).toEqual([event]);
expect(emitSpy).toHaveBeenCalledWith(RelationsEvent.Add, event);
});

it("should not add events of incorrect relation type", async () => {
const logSpy = jest.spyOn(logger, "error").mockImplementation(() => {});
const relations = new Relations(relationType, eventType, room);
const event = new MatrixEvent({
type: eventType,
content: {
"m.relates_to": {
event_id: "$2s4yYpEkVQrPglSCSqB_m6E8vDhWsg0yFNyOJdVIb_o",
rel_type: "m.annotation",
},
},
});

await relations.addEvent(event);
const emitSpy = jest.spyOn(relations, "emit");

expect(logSpy).toHaveBeenCalledWith(`Event relation info doesn't match this container`);
// event not added
expect(relations.getRelations().length).toBe(0);
expect(emitSpy).not.toHaveBeenCalled();
});
});

it("should emit created regardless of ordering", async function () {
const targetEvent = new MatrixEvent({
sender: "@bob:example.com",
Expand Down
21 changes: 6 additions & 15 deletions src/models/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export type EventHandlerMap = {
[RelationsEvent.Redaction]: (event: MatrixEvent) => void;
};

const matchesEventType = (eventType: string, targetEventType: string, altTargetEventTypes: string[] = []): boolean =>
[targetEventType, ...altTargetEventTypes].includes(eventType);

/**
* A container for relation events that supports easy access to common ways of
* aggregating such events. Each instance holds events that of a single relation
Expand All @@ -55,11 +58,13 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
* @param relationType - The type of relation involved, such as "m.annotation", "m.reference", "m.replace", etc.
* @param eventType - The relation event's type, such as "m.reaction", etc.
* @param client - The client which created this instance. For backwards compatibility also accepts a Room.
* @param altEventTypes - alt event types for relation events, for example to support unstable prefixed event types
*/
public constructor(
public readonly relationType: RelationType | string,
public readonly eventType: string,
client: MatrixClient | Room,
public readonly altEventTypes?: string[],
) {
super();
this.client = client instanceof Room ? client.client : client;
Expand All @@ -84,7 +89,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
const relationType = relation.rel_type;
const eventType = event.getType();

if (this.relationType !== relationType || this.eventType !== eventType) {
if (this.relationType !== relationType || !matchesEventType(eventType, this.eventType, this.altEventTypes)) {
logger.error("Event relation info doesn't match this container");
return;
}
Expand Down Expand Up @@ -122,20 +127,6 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
return;
}

const relation = event.getRelation();
if (!relation) {
logger.error("Event must have relation info");
return;
}

const relationType = relation.rel_type;
const eventType = event.getType();

if (this.relationType !== relationType || this.eventType !== eventType) {
logger.error("Event relation info doesn't match this container");
return;
}

this.relations.delete(event);

if (this.relationType === RelationType.Annotation) {
Expand Down

0 comments on commit bb23df9

Please sign in to comment.