From 8c0f5b4e31dfe515f29c7e4e9d832f63baf57ffc Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 16:48:57 +0200 Subject: [PATCH 01/18] Update event.ts: Add io.element.functional_members --- src/@types/event.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/@types/event.ts b/src/@types/event.ts index f7b22992eaa..4b1dd18ac0f 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -33,6 +33,7 @@ export enum EventType { RoomGuestAccess = "m.room.guest_access", RoomServerAcl = "m.room.server_acl", RoomTombstone = "m.room.tombstone", + RoomFunctionalMembers = "io.element.functional_members", /** * @deprecated Should not be used. */ From d60affc1b88e5372b4676f9aba8da73144a0873d Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 18:35:34 +0200 Subject: [PATCH 02/18] room.calculateRoomName: Exclude service members --- src/models/room.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/models/room.ts b/src/models/room.ts index 9970ae595ac..d53613759ed 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2039,20 +2039,41 @@ export class Room extends EventEmitter { // -1 because these numbers include the syncing user const inviteJoinCount = joinedMemberCount + invitedMemberCount - 1; + // get service members (e.g. helper bots) for exclusion + let excludedUserIds: string[] = []; + const mFunctionalMembers = this.currentState.getStateEvents(EventType.RoomFunctionalMembers, ""); + if (mFunctionalMembers && mFunctionalMembers.getContent() && Array.isArray(mFunctionalMembers.getContent().service_members)) { + excludedUserIds = mRoomName.getContent().service_members; + } + // get members that are NOT ourselves and are actually in the room. let otherNames = null; if (this.summaryHeroes) { // if we have a summary, the member state events // should be in the room state - otherNames = this.summaryHeroes.map((userId) => { + otherNames = []; + this.summaryHeroes.forEach((userId) => { + // filter service members + if (excludedUserIds.includes(userId)) { + inviteJoinCount--; + return; + } const member = this.getMember(userId); - return member ? member.name : userId; + otherNames.push(member ? member.name : userId); }); } else { let otherMembers = this.currentState.getMembers().filter((m) => { return m.userId !== userId && (m.membership === "invite" || m.membership === "join"); }); + otherMembers = otherMembers.filter((userId) => { + // filter service members + if (excludedUserIds.includes(userId)) { + inviteJoinCount--; + return false; + } + return true; + }); // make sure members have stable order otherMembers.sort((a, b) => a.userId.localeCompare(b.userId)); // only 5 first members, immitate summaryHeroes @@ -2065,7 +2086,7 @@ export class Room extends EventEmitter { } const myMembership = this.getMyMembership(); - // if I have created a room and invited people throuh + // if I have created a room and invited people through // 3rd party invites if (myMembership == 'join') { const thirdPartyInvites = From a248bbc46b941c92d871954de0eda6b1bdd4d1d0 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 18:58:07 +0200 Subject: [PATCH 03/18] Update src/models/room.ts Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> --- src/models/room.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/room.ts b/src/models/room.ts index d53613759ed..6e4e8daaa56 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2042,7 +2042,7 @@ export class Room extends EventEmitter { // get service members (e.g. helper bots) for exclusion let excludedUserIds: string[] = []; const mFunctionalMembers = this.currentState.getStateEvents(EventType.RoomFunctionalMembers, ""); - if (mFunctionalMembers && mFunctionalMembers.getContent() && Array.isArray(mFunctionalMembers.getContent().service_members)) { + if (Array.isArray(mFunctionalMembers?.getContent().service_members)) { excludedUserIds = mRoomName.getContent().service_members; } From 4700dc0375c13bba4559041a12213bc690c10a32 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 18:59:02 +0200 Subject: [PATCH 04/18] Remove trailing spaces --- src/models/room.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/room.ts b/src/models/room.ts index 6e4e8daaa56..189056386b0 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2045,7 +2045,7 @@ export class Room extends EventEmitter { if (Array.isArray(mFunctionalMembers?.getContent().service_members)) { excludedUserIds = mRoomName.getContent().service_members; } - + // get members that are NOT ourselves and are actually in the room. let otherNames = null; if (this.summaryHeroes) { From d219c2f4627f15fb4c623c00a5db2692690f58df Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 19:07:20 +0200 Subject: [PATCH 05/18] Fix mistakes --- src/models/room.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/models/room.ts b/src/models/room.ts index 189056386b0..630ab47f081 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2037,13 +2037,13 @@ export class Room extends EventEmitter { const joinedMemberCount = this.currentState.getJoinedMemberCount(); const invitedMemberCount = this.currentState.getInvitedMemberCount(); // -1 because these numbers include the syncing user - const inviteJoinCount = joinedMemberCount + invitedMemberCount - 1; + let inviteJoinCount = joinedMemberCount + invitedMemberCount - 1; // get service members (e.g. helper bots) for exclusion let excludedUserIds: string[] = []; const mFunctionalMembers = this.currentState.getStateEvents(EventType.RoomFunctionalMembers, ""); if (Array.isArray(mFunctionalMembers?.getContent().service_members)) { - excludedUserIds = mRoomName.getContent().service_members; + excludedUserIds = mFunctionalMembers.getContent().service_members; } // get members that are NOT ourselves and are actually in the room. @@ -2066,7 +2066,7 @@ export class Room extends EventEmitter { return m.userId !== userId && (m.membership === "invite" || m.membership === "join"); }); - otherMembers = otherMembers.filter((userId) => { + otherMembers = otherMembers.filter(({userId}) => { // filter service members if (excludedUserIds.includes(userId)) { inviteJoinCount--; From 0074b71cbf460b265fb2f0c3add058228861ba12 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 19:10:25 +0200 Subject: [PATCH 06/18] Fix object-curly-spacing linting errors --- src/models/room.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/room.ts b/src/models/room.ts index 630ab47f081..8c62ed77d23 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2066,7 +2066,7 @@ export class Room extends EventEmitter { return m.userId !== userId && (m.membership === "invite" || m.membership === "join"); }); - otherMembers = otherMembers.filter(({userId}) => { + otherMembers = otherMembers.filter(({ userId }) => { // filter service members if (excludedUserIds.includes(userId)) { inviteJoinCount--; From c4263692f0095b86f6015fe0880e634d8f001081 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 19:34:44 +0200 Subject: [PATCH 07/18] Update event.ts --- src/@types/event.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/@types/event.ts b/src/@types/event.ts index 4b1dd18ac0f..730cbc5fe75 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -33,7 +33,6 @@ export enum EventType { RoomGuestAccess = "m.room.guest_access", RoomServerAcl = "m.room.server_acl", RoomTombstone = "m.room.tombstone", - RoomFunctionalMembers = "io.element.functional_members", /** * @deprecated Should not be used. */ @@ -145,6 +144,13 @@ export const UNSTABLE_MSC3089_LEAF = new UnstableValue("m.leaf", "org.matrix.msc */ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix.msc3089.branch"); +/** + * Functional members type for declaring a purpose of room members (e.g. helpful bots). + * Note that this reference is UNSTABLE and subject to breaking changes, including its + * eventual removal. + */ +export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = "io.element.functional_members"); + export interface IEncryptedFile { url: string; mimetype?: string; From 96420a75abd7a1f7be9c03551a2c8661ae4c2d85 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 6 Jul 2021 19:35:56 +0200 Subject: [PATCH 08/18] room.ts: Use UNSTABLE_ELEMENT_FUNCTIONAL_USERS --- src/models/room.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/room.ts b/src/models/room.ts index 8c62ed77d23..744169b0118 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -30,7 +30,7 @@ import { RoomMember } from "./room-member"; import { IRoomSummary, RoomSummary } from "./room-summary"; import { logger } from '../logger'; import { ReEmitter } from '../ReEmitter'; -import { EventType, RoomCreateTypeField, RoomType } from "../@types/event"; +import { EventType, RoomCreateTypeField, RoomType, UNSTABLE_ELEMENT_FUNCTIONAL_USERS } from "../@types/event"; import { IRoomVersionsCapability, MatrixClient, RoomVersionStability } from "../client"; import { ResizeMethod } from "../@types/partials"; import { Filter } from "../filter"; @@ -2041,7 +2041,7 @@ export class Room extends EventEmitter { // get service members (e.g. helper bots) for exclusion let excludedUserIds: string[] = []; - const mFunctionalMembers = this.currentState.getStateEvents(EventType.RoomFunctionalMembers, ""); + const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS, ""); if (Array.isArray(mFunctionalMembers?.getContent().service_members)) { excludedUserIds = mFunctionalMembers.getContent().service_members; } From ab679c2216a9da00c5813c1ba17009532fb0b0c5 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Wed, 7 Jul 2021 00:39:26 +0200 Subject: [PATCH 09/18] Update src/@types/event.ts --- src/@types/event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/@types/event.ts b/src/@types/event.ts index 730cbc5fe75..0c8d81da855 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -149,7 +149,7 @@ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix * Note that this reference is UNSTABLE and subject to breaking changes, including its * eventual removal. */ -export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = "io.element.functional_members"); +export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue("io.element.functional_members"); export interface IEncryptedFile { url: string; From 96e6e7b1e82b002d7d70bc0d14780b23550eab44 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Fri, 9 Jul 2021 16:44:39 +0200 Subject: [PATCH 10/18] Update event.ts --- src/@types/event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/@types/event.ts b/src/@types/event.ts index 0c8d81da855..32aa8cf8f01 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -149,7 +149,7 @@ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix * Note that this reference is UNSTABLE and subject to breaking changes, including its * eventual removal. */ -export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue("io.element.functional_members"); +export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue("io.element.functional_members", "io.element.functional_members"); export interface IEncryptedFile { url: string; From 116085e92745a8fb005e30ec64a6aa5a4182016f Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Sat, 10 Jul 2021 03:08:51 +0200 Subject: [PATCH 11/18] Fix linter error --- src/@types/event.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/@types/event.ts b/src/@types/event.ts index 32aa8cf8f01..2c6a47928cb 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -149,7 +149,9 @@ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix * Note that this reference is UNSTABLE and subject to breaking changes, including its * eventual removal. */ -export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue("io.element.functional_members", "io.element.functional_members"); +export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue( + "io.element.functional_members", + "io.element.functional_members"); export interface IEncryptedFile { url: string; From d7e6cee19c6249f38f4a6fe2bd1ac93142d0257b Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Sat, 10 Jul 2021 03:44:03 +0200 Subject: [PATCH 12/18] Update room.ts --- src/models/room.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/room.ts b/src/models/room.ts index 744169b0118..70ce826e2b4 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2041,7 +2041,7 @@ export class Room extends EventEmitter { // get service members (e.g. helper bots) for exclusion let excludedUserIds: string[] = []; - const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS, ""); + const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS.unstable, ""); if (Array.isArray(mFunctionalMembers?.getContent().service_members)) { excludedUserIds = mFunctionalMembers.getContent().service_members; } From 7129c7c7af545c8b73225541b74cc477a7e11049 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Mon, 19 Jul 2021 10:56:15 +0200 Subject: [PATCH 13/18] Update src/models/room.ts Co-authored-by: Travis Ralston --- src/models/room.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/room.ts b/src/models/room.ts index 70ce826e2b4..6e78ee4c9a3 100644 --- a/src/models/room.ts +++ b/src/models/room.ts @@ -2041,7 +2041,7 @@ export class Room extends EventEmitter { // get service members (e.g. helper bots) for exclusion let excludedUserIds: string[] = []; - const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS.unstable, ""); + const mFunctionalMembers = this.currentState.getStateEvents(UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, ""); if (Array.isArray(mFunctionalMembers?.getContent().service_members)) { excludedUserIds = mFunctionalMembers.getContent().service_members; } From 4a1cd159a4e74ddc8a6e6f6458650cd9d83b9b0f Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Mon, 19 Jul 2021 11:53:43 +0200 Subject: [PATCH 14/18] Update event.ts --- src/@types/event.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/@types/event.ts b/src/@types/event.ts index 2c6a47928cb..42c7d0529c7 100644 --- a/src/@types/event.ts +++ b/src/@types/event.ts @@ -148,6 +148,19 @@ export const UNSTABLE_MSC3089_BRANCH = new UnstableValue("m.branch", "org.matrix * Functional members type for declaring a purpose of room members (e.g. helpful bots). * Note that this reference is UNSTABLE and subject to breaking changes, including its * eventual removal. + * + * Schema (TypeScript): + * { + * service_members?: string[] + * } + * + * Example: + * { + * "service_members": [ + * "@helperbot:localhost", + * "@reminderbot:alice.tdl" + * ] + * } */ export const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue( "io.element.functional_members", From 4cf655785e37bb0f65d4fe6df07050643a448426 Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Mon, 19 Jul 2021 17:59:11 +0200 Subject: [PATCH 15/18] Add tests --- spec/unit/room.spec.js | 238 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/spec/unit/room.spec.js b/spec/unit/room.spec.js index 34ec05f2495..20d129aed63 100644 --- a/spec/unit/room.spec.js +++ b/spec/unit/room.spec.js @@ -3,6 +3,7 @@ import { EventStatus, MatrixEvent } from "../../src"; import { EventTimeline } from "../../src/models/event-timeline"; import { RoomState } from "../../src"; import { Room } from "../../src"; +import { UNSTABLE_ELEMENT_FUNCTIONAL_USERS } from "../../src/@types/event"; import { TestClient } from "../TestClient"; describe("Room", function() { @@ -1456,4 +1457,241 @@ describe("Room", function() { expect(room.maySendMessage()).toEqual(true); }); }); + + describe("getDefaultRoomName", function() { + it("should return 'Empty room' if a user is the only member", + function() { + const room = new Room(roomId, null, userA); + expect(room.getDefaultRoomName(userA)).toEqual("Empty room"); + }); + + it("should return a display name if one other member is in the room", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); + + it("should return a display name if one other member is banned", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "ban", + room: roomId, event: true, name: "User B", + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("Empty room (was User B)"); + }); + + it("should return a display name if one other member is invited", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "invite", + room: roomId, event: true, name: "User B", + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); + + it("should return 'Empty room (was User B)' if User B left the room", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "leave", + room: roomId, event: true, name: "User B", + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("Empty room (was User B)"); + }); + + it("should return 'User B and User C' if in a room with two other users", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkMembership({ + user: userC, mship: "join", + room: roomId, event: true, name: "User C", + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B and User C"); + }); + + it("should return 'User B and 2 others' if in a room with three other users", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkMembership({ + user: userC, mship: "join", + room: roomId, event: true, name: "User C", + }), + utils.mkMembership({ + user: userD, mship: "join", + room: roomId, event: true, name: "User D", + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B and 2 others"); + }); + + describe("io.element.functional_users", function() { + it("should return a display name (default behaviour) if no one is marked as a functional member", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, + content: { + service_members: [], + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); + + it("should return a display name (default behaviour) if service members is a number (invalid)", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, + content: { + service_members: 1, + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); + + it("should return a display name (default behaviour) if service members is a string (invalid)", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, + content: { + service_members: userB, + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); + + it("should return 'Empty room' if the only other member is a functional member", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, + content: { + service_members: [userB], + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("Empty room"); + }); + + it("should return 'User B' if User B is the only other member who isn't a functional member", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkMembership({ + user: userC, mship: "join", + room: roomId, event: true, name: "User C", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, user: userA, + content: { + service_members: [userC], + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); + }); + }); }); From b8c2a578290d918da43d669aaa2042d15f32d89b Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Mon, 19 Jul 2021 18:17:39 +0200 Subject: [PATCH 16/18] Add test with multiple service_members --- spec/unit/room.spec.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/spec/unit/room.spec.js b/spec/unit/room.spec.js index ce6806e4bbb..f79bc37d434 100644 --- a/spec/unit/room.spec.js +++ b/spec/unit/room.spec.js @@ -1692,6 +1692,33 @@ describe("Room", function() { ]); expect(room.getDefaultRoomName(userA)).toEqual("User B"); }); + + it("should return 'Empty room' if all other members are functional members", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkMembership({ + user: userC, mship: "join", + room: roomId, event: true, name: "User C", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, user: userA, + content: { + service_members: [userB, userC], + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("Empty room"); + }); }); }); }); From cb2b9619abc4d6be1a47ea21d12815b0f6d1c41a Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Mon, 19 Jul 2021 18:22:29 +0200 Subject: [PATCH 17/18] Replace .indexOf() !== -1 with .includes() for readability --- spec/test-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/test-utils.js b/spec/test-utils.js index 47b2624f61c..1f5db16c7d9 100644 --- a/spec/test-utils.js +++ b/spec/test-utils.js @@ -91,7 +91,7 @@ export function mkEvent(opts) { event.state_key = opts.skey; } else if (["m.room.name", "m.room.topic", "m.room.create", "m.room.join_rules", "m.room.power_levels", "m.room.topic", - "com.example.state"].indexOf(opts.type) !== -1) { + "com.example.state"].includes(opts.type)) { event.state_key = ""; } return opts.event ? new MatrixEvent(event) : event; From afa67688f83c2af66adc0da417e76ccdecb1bc2c Mon Sep 17 00:00:00 2001 From: Christian Paul Date: Tue, 20 Jul 2021 12:51:08 +0200 Subject: [PATCH 18/18] Add test for service member who is not a room member --- spec/unit/room.spec.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/unit/room.spec.js b/spec/unit/room.spec.js index f79bc37d434..be746a2371f 100644 --- a/spec/unit/room.spec.js +++ b/spec/unit/room.spec.js @@ -1719,6 +1719,29 @@ describe("Room", function() { ]); expect(room.getDefaultRoomName(userA)).toEqual("Empty room"); }); + + it("should not break if an unjoined user is marked as a service user", + function() { + const room = new Room(roomId, null, userA); + room.addLiveEvents([ + utils.mkMembership({ + user: userA, mship: "join", + room: roomId, event: true, name: "User A", + }), + utils.mkMembership({ + user: userB, mship: "join", + room: roomId, event: true, name: "User B", + }), + utils.mkEvent({ + type: UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, skey: "", + room: roomId, event: true, user: userA, + content: { + service_members: [userC], + }, + }), + ]); + expect(room.getDefaultRoomName(userA)).toEqual("User B"); + }); }); }); });